diff --git a/app/routes/auth.py b/app/routes/auth.py index cc7e266..3bf9144 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -1,6 +1,6 @@ from flask import Blueprint, render_template, redirect, url_for, flash from werkzeug.security import generate_password_hash, check_password_hash -from app.models import db, User +from app.models import db, User, Profile from app.forms import LoginForm, SignupForm from flask_login import login_user, login_required, logout_user @@ -11,7 +11,8 @@ def signup(): form = SignupForm() if form.validate_on_submit(): hashed_password = generate_password_hash(form.password.data) - new_user = User(username=form.username.data, password_hash=hashed_password) + new_profile = Profile() + new_user = User(username=form.username.data, password_hash=hashed_password, profile=new_profile) db.session.add(new_user) db.session.commit() flash("Account created successfully. Please log in.", "success") diff --git a/app/static/css/tailwind.css b/app/static/css/tailwind.css index 05de110..b73833f 100644 --- a/app/static/css/tailwind.css +++ b/app/static/css/tailwind.css @@ -154,7 +154,7 @@ html, -o-tab-size: 4; tab-size: 4; /* 3 */ - font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + font-family: Inter, sans-serif; /* 4 */ font-feature-settings: normal; /* 5 */ @@ -588,6 +588,10 @@ video { } } +.pointer-events-none { + pointer-events: none; +} + .visible { visibility: visible; } @@ -608,6 +612,15 @@ video { position: relative; } +.inset-0 { + inset: 0px; +} + +.inset-y-0 { + top: 0px; + bottom: 0px; +} + .bottom-0 { bottom: 0px; } @@ -644,10 +657,22 @@ video { top: 1.25rem; } +.top-24 { + top: 6rem; +} + +.left-0 { + left: 0px; +} + .z-10 { z-index: 10; } +.z-50 { + z-index: 50; +} + .col-span-full { grid-column: 1 / -1; } @@ -717,6 +742,38 @@ video { margin-top: 1.5rem; } +.ml-4 { + margin-left: 1rem; +} + +.mb-12 { + margin-bottom: 3rem; +} + +.mb-16 { + margin-bottom: 4rem; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.mb-20 { + margin-bottom: 5rem; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.mt-12 { + margin-top: 3rem; +} + +.mt-8 { + margin-top: 2rem; +} + .block { display: block; } @@ -774,6 +831,14 @@ video { height: 2rem; } +.h-20 { + height: 5rem; +} + +.h-2 { + height: 0.5rem; +} + .w-16 { width: 4rem; } @@ -802,6 +867,18 @@ video { width: 100%; } +.w-10 { + width: 2.5rem; +} + +.w-20 { + width: 5rem; +} + +.min-w-\[300px\] { + min-width: 300px; +} + .max-w-4xl { max-width: 56rem; } @@ -818,6 +895,10 @@ video { max-width: 28rem; } +.max-w-2xl { + max-width: 42rem; +} + .flex-1 { flex: 1 1 0%; } @@ -886,6 +967,10 @@ video { gap: 2rem; } +.gap-10 { + gap: 2.5rem; +} + .space-x-2 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.5rem * var(--tw-space-x-reverse)); @@ -936,6 +1021,23 @@ video { border-radius: 0.375rem; } +.rounded-xl { + border-radius: 0.75rem; +} + +.rounded-2xl { + border-radius: 1rem; +} + +.rounded-3xl { + border-radius: 1.5rem; +} + +.rounded-b-3xl { + border-bottom-right-radius: 1.5rem; + border-bottom-left-radius: 1.5rem; +} + .border { border-width: 1px; } @@ -981,6 +1083,21 @@ video { border-color: rgb(255 255 255 / var(--tw-border-opacity, 1)); } +.border-gray-100 { + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity, 1)); +} + +.border-primary-500 { + --tw-border-opacity: 1; + border-color: rgb(20 184 166 / var(--tw-border-opacity, 1)); +} + +.border-primary-600 { + --tw-border-opacity: 1; + border-color: rgb(13 148 136 / var(--tw-border-opacity, 1)); +} + .bg-blue-600 { --tw-bg-opacity: 1; background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1)); @@ -1041,20 +1158,88 @@ video { background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); } +.bg-primary-800 { + --tw-bg-opacity: 1; + background-color: rgb(17 94 89 / var(--tw-bg-opacity, 1)); +} + +.bg-primary-900 { + --tw-bg-opacity: 1; + background-color: rgb(19 78 74 / var(--tw-bg-opacity, 1)); +} + +.bg-primary-50 { + --tw-bg-opacity: 1; + background-color: rgb(240 253 250 / var(--tw-bg-opacity, 1)); +} + +.bg-primary-700 { + --tw-bg-opacity: 1; + background-color: rgb(15 118 110 / var(--tw-bg-opacity, 1)); +} + +.bg-white\/5 { + background-color: rgb(255 255 255 / 0.05); +} + +.bg-primary-600 { + --tw-bg-opacity: 1; + background-color: rgb(13 148 136 / var(--tw-bg-opacity, 1)); +} + +.bg-primary-100 { + --tw-bg-opacity: 1; + background-color: rgb(204 251 241 / var(--tw-bg-opacity, 1)); +} + .bg-gradient-to-r { background-image: linear-gradient(to right, var(--tw-gradient-stops)); } +.bg-gradient-to-br { + background-image: linear-gradient(to bottom right, var(--tw-gradient-stops)); +} + .from-blue-500 { --tw-gradient-from: #3b82f6 var(--tw-gradient-from-position); --tw-gradient-to: rgb(59 130 246 / 0) var(--tw-gradient-to-position); --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); } +.from-primary-600 { + --tw-gradient-from: #0d9488 var(--tw-gradient-from-position); + --tw-gradient-to: rgb(13 148 136 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} + +.from-primary-400 { + --tw-gradient-from: #2dd4bf var(--tw-gradient-from-position); + --tw-gradient-to: rgb(45 212 191 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} + +.from-primary-500 { + --tw-gradient-from: #14b8a6 var(--tw-gradient-from-position); + --tw-gradient-to: rgb(20 184 166 / 0) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); +} + .to-blue-700 { --tw-gradient-to: #1d4ed8 var(--tw-gradient-to-position); } +.to-primary-800 { + --tw-gradient-to: #115e59 var(--tw-gradient-to-position); +} + +.to-primary-600 { + --tw-gradient-to: #0d9488 var(--tw-gradient-to-position); +} + +.to-primary-700 { + --tw-gradient-to: #0f766e var(--tw-gradient-to-position); +} + .fill-current { fill: currentColor; } @@ -1092,6 +1277,10 @@ video { padding: 2rem; } +.p-10 { + padding: 2.5rem; +} + .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -1147,6 +1336,11 @@ video { padding-bottom: 1rem; } +.py-24 { + padding-top: 6rem; + padding-bottom: 6rem; +} + .pl-1 { padding-left: 0.25rem; } @@ -1167,10 +1361,30 @@ video { padding-top: 1.5rem; } +.pb-20 { + padding-bottom: 5rem; +} + +.pt-24 { + padding-top: 6rem; +} + +.pl-11 { + padding-left: 2.75rem; +} + +.pl-4 { + padding-left: 1rem; +} + .text-center { text-align: center; } +.font-sans { + font-family: Inter, sans-serif; +} + .text-2xl { font-size: 1.5rem; line-height: 2rem; @@ -1211,6 +1425,11 @@ video { line-height: 1rem; } +.text-5xl { + font-size: 3rem; + line-height: 1; +} + .font-bold { font-weight: 700; } @@ -1223,6 +1442,26 @@ video { font-weight: 600; } +.font-extrabold { + font-weight: 800; +} + +.uppercase { + text-transform: uppercase; +} + +.leading-relaxed { + line-height: 1.625; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + +.tracking-wider { + letter-spacing: 0.05em; +} + .text-blue-600 { --tw-text-opacity: 1; color: rgb(37 99 235 / var(--tw-text-opacity, 1)); @@ -1278,10 +1517,40 @@ video { color: rgb(255 255 255 / var(--tw-text-opacity, 1)); } +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity, 1)); +} + +.text-primary-50 { + --tw-text-opacity: 1; + color: rgb(240 253 250 / var(--tw-text-opacity, 1)); +} + +.text-primary-600 { + --tw-text-opacity: 1; + color: rgb(13 148 136 / var(--tw-text-opacity, 1)); +} + +.text-primary-700 { + --tw-text-opacity: 1; + color: rgb(15 118 110 / var(--tw-text-opacity, 1)); +} + +.text-primary-200 { + --tw-text-opacity: 1; + color: rgb(153 246 228 / var(--tw-text-opacity, 1)); +} + .no-underline { text-decoration-line: none; } +.antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + .shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); @@ -1306,6 +1575,24 @@ video { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.shadow-xl { + --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-inner { + --tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.shadow-2xl { + --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); + --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; @@ -1320,6 +1607,37 @@ video { transition-duration: 150ms; } +.transition-colors { + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.transition-all { + transition-property: all; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.duration-300 { + transition-duration: 300ms; +} + +.hover\:-translate-y-1:hover { + --tw-translate-y: -0.25rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:-translate-y-2:hover { + --tw-translate-y: -0.5rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:-translate-y-0\.5:hover { + --tw-translate-y: -0.125rem; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + .hover\:bg-blue-700:hover { --tw-bg-opacity: 1; background-color: rgb(29 78 216 / var(--tw-bg-opacity, 1)); @@ -1360,6 +1678,21 @@ video { background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1)); } +.hover\:bg-gray-50:hover { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity, 1)); +} + +.hover\:bg-primary-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(13 148 136 / var(--tw-bg-opacity, 1)); +} + +.hover\:bg-primary-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(15 118 110 / var(--tw-bg-opacity, 1)); +} + .hover\:text-gray-200:hover { --tw-text-opacity: 1; color: rgb(229 231 235 / var(--tw-text-opacity, 1)); @@ -1390,6 +1723,15 @@ video { color: rgb(255 255 255 / var(--tw-text-opacity, 1)); } +.hover\:text-primary-800:hover { + --tw-text-opacity: 1; + color: rgb(17 94 89 / var(--tw-text-opacity, 1)); +} + +.hover\:underline:hover { + text-decoration-line: underline; +} + .hover\:no-underline:hover { text-decoration-line: none; } @@ -1400,11 +1742,33 @@ video { box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } +.hover\:shadow-2xl:hover { + --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); + --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.hover\:shadow-xl:hover { + --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + .focus\:border-blue-500:focus { --tw-border-opacity: 1; border-color: rgb(59 130 246 / var(--tw-border-opacity, 1)); } +.focus\:border-primary-500:focus { + --tw-border-opacity: 1; + border-color: rgb(20 184 166 / var(--tw-border-opacity, 1)); +} + +.focus\:bg-white:focus { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); +} + .focus\:text-white:focus { --tw-text-opacity: 1; color: rgb(255 255 255 / var(--tw-text-opacity, 1)); @@ -1431,6 +1795,11 @@ video { --tw-ring-color: rgb(34 197 94 / var(--tw-ring-opacity, 1)); } +.focus\:ring-primary-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(20 184 166 / var(--tw-ring-opacity, 1)); +} + .group:hover .group-hover\:scale-105 { --tw-scale-x: 1.05; --tw-scale-y: 1.05; @@ -1453,6 +1822,22 @@ video { .sm\:h-40 { height: 10rem; } + + .sm\:flex-row { + flex-direction: row; + } + + .sm\:space-x-6 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1.5rem * var(--tw-space-x-reverse)); + margin-left: calc(1.5rem * calc(1 - var(--tw-space-x-reverse))); + } + + .sm\:space-y-0 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(0px * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(0px * var(--tw-space-y-reverse)); + } } @media (min-width: 768px) { @@ -1483,6 +1868,16 @@ video { .md\:p-4 { padding: 1rem; } + + .md\:text-2xl { + font-size: 1.5rem; + line-height: 2rem; + } + + .md\:text-6xl { + font-size: 3.75rem; + line-height: 1; + } } @media (min-width: 1024px) { diff --git a/app/static/images/favicon.svg b/app/static/images/favicon.svg new file mode 100644 index 0000000..17737af --- /dev/null +++ b/app/static/images/favicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/templates/_layout.html b/app/templates/_layout.html index b055dcd..d6907e7 100644 --- a/app/templates/_layout.html +++ b/app/templates/_layout.html @@ -5,17 +5,17 @@ {% block title %}BP Tracker{% endblock %} - - + + - -