From cb7d17a47eb67f178183dd4c5387f17150995591 Mon Sep 17 00:00:00 2001 From: TropiiDev Date: Mon, 21 Apr 2025 22:38:47 -0400 Subject: [PATCH] Initial Commit v0.0.1 --- assets/css/defaults.css | 139 +++++++++++++++++++++++++++++++++++++ assets/css/main.css | 101 +++++++++++++++++++++++++++ assets/css/register.css | 94 +++++++++++++++++++++++++ assets/css/sign-in.css | 94 +++++++++++++++++++++++++ assets/js/sign-in.js | 113 ++++++++++++++++++++++++++++++ assets/pages/register.html | 42 +++++++++++ assets/pages/sign-in.html | 39 +++++++++++ assets/pages/user.html | 40 +++++++++++ index.html | 41 +++++++++++ 9 files changed, 703 insertions(+) create mode 100644 assets/css/defaults.css create mode 100644 assets/css/main.css create mode 100644 assets/css/register.css create mode 100644 assets/css/sign-in.css create mode 100644 assets/js/sign-in.js create mode 100644 assets/pages/register.html create mode 100644 assets/pages/sign-in.html create mode 100644 assets/pages/user.html create mode 100644 index.html diff --git a/assets/css/defaults.css b/assets/css/defaults.css new file mode 100644 index 0000000..8b1718f --- /dev/null +++ b/assets/css/defaults.css @@ -0,0 +1,139 @@ +/* vars & default settings */ +:root { + --bg-black: #131200; + --white: #E3E4DB; + --silver: #CDCDCD; + --maroon-pink: #7C6C77; + --gray: #646E78; + --font-family: 'Arial', sans-serif; +} + +body { + margin: 0; + padding: 0; + font-family: var(--font-family); + background-color: var(--bg-black); + color: var(--silver); +} + +.signed-in { + display: none; +} + +/* nav */ + +.nav-section { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 2rem; + border-bottom: 2px solid var(--gray); + backdrop-filter: blur(8px); + position: sticky; + top: 0; + z-index: 1000; +} + +.nav { + display: flex; + gap: 2rem; + align-items: center; + width: 100%; +} + +.nav a { + color: var(--white); + text-decoration: none; + font-size: 1rem; + transition: color 0.2s ease-in-out; + position: relative; +} + +.nav a:hover { + color: var(--silver); +} + +.nav a::after { + content: ''; + position: absolute; + width: 0; + height: 2px; + bottom: -4px; + left: 0; + background-color: var(--white); + transition: width 0.2s ease-in-out; +} + +.nav a:hover::after { + width: 100%; +} + +.nav-home { + font-size: 1.25rem !important; + font-weight: 600; + margin-right: auto; +} + +.nav-signin, +.nav-register, +.nav-user { + padding: 0.5rem 1rem; + border-radius: 4px; +} + +.nav-register { + background-color: var(--white); + color: var(--bg-black) !important; +} + +.nav-register:hover { + opacity: 0.9; +} + +/* tooltips */ +.tooltip { + position: relative; + padding: 0.75rem 1rem; + border-radius: 4px; + font-size: 0.9rem; + opacity: 0; + margin-bottom: 1rem; + transform: translateY(-5px); + transition: all 0.3s ease; + backdrop-filter: blur(8px); + text-align: center; + box-sizing: border-box; +} + +.tooltip.visible { + opacity: 1; + transform: translateY(0); + display: block !important; +} + +.tooltip.info { + background-color: rgba(100, 110, 120, 0.2); + border: 1px solid var(--gray); + color: var(--silver); +} + +.tooltip.error { + background-color: rgba(220, 53, 69, 0.2); + border: 1px solid #dc3545; + color: #ff8c94; +} + +.tooltip.success { + background-color: rgba(40, 167, 69, 0.2); + border: 1px solid #28a745; + color: #98fb98; +} + +/* Position variants */ +.tooltip.top { + bottom: calc(100% + 10px); +} + +.tooltip.bottom { + top: calc(100% + 10px); +} \ No newline at end of file diff --git a/assets/css/main.css b/assets/css/main.css new file mode 100644 index 0000000..b623307 --- /dev/null +++ b/assets/css/main.css @@ -0,0 +1,101 @@ +/* hero */ +.hero-section { + min-height: calc(100vh - 74px); /* Subtract navbar height */ + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +.main-screen { + text-align: center; + padding: 2rem; +} + +.center-screen { + margin-bottom: 3rem; +} + +.hero-title { + font-size: 3.5rem; + color: var(--white); + margin-bottom: 1rem; +} + +.hero-subtext { + font-size: 1.2rem; + color: var(--maroon-pink); + font-weight: normal; + margin: 0; +} + +.hero-buttons { + display: flex; + gap: 1rem; + justify-content: center; + margin-top: 2rem; +} + +.hero-buttons a { + padding: 0.75rem 1.5rem; + border-radius: 4px; + text-decoration: none; + transition: all 0.2s ease-in-out; +} + +.hero-register { + background-color: var(--white); + color: var(--bg-black); +} + +.hero-signin, .hero-about { + border: 2px solid var(--white); + color: var(--white); +} + +.hero-buttons a:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +/* Scroll indicator animation */ +.scroll-indicator { + position: absolute; + bottom: 2rem; + left: 50%; + transform: translateX(-50%); + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + opacity: 0.8; + animation: fadeInOut 2s ease-in-out infinite; +} + +.scroll-text { + color: var(--silver); + font-size: 0.9rem; +} + +.scroll-arrow { + width: 20px; + height: 20px; + border: solid var(--silver); + border-width: 0 2px 2px 0; + transform: rotate(45deg); +} + +@keyframes fadeInOut { + 0% { + opacity: 0.3; + transform: translateX(-50%) translateY(-10px); + } + 50% { + opacity: 0.8; + transform: translateX(-50%) translateY(0); + } + 100% { + opacity: 0.3; + transform: translateX(-50%) translateY(-10px); + } +} \ No newline at end of file diff --git a/assets/css/register.css b/assets/css/register.css new file mode 100644 index 0000000..388b35b --- /dev/null +++ b/assets/css/register.css @@ -0,0 +1,94 @@ +/* register */ +.register-section { + min-height: calc(100vh - 74px); + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; +} + +.main-screen { + background-color: rgba(100, 110, 120, 0.1); + backdrop-filter: blur(8px); + border-radius: 12px; + padding: 2.5rem; + width: 100%; + max-width: 460px; +} + +.register-text { + text-align: center; + margin-bottom: 2.5rem; +} + +.register-title { + color: var(--white); + font-size: 2rem; + margin: 0 0 0.5rem 0; +} + +.register-subtext { + color: var(--maroon-pink); + font-weight: normal; + margin: 0; +} + +.register-form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.register-form label { + color: var(--silver); + font-size: 0.9rem; + margin-bottom: -0.5rem; +} + +.register-form input { + background-color: rgba(255, 255, 255, 0.05); + border: 1px solid var(--gray); + border-radius: 4px; + padding: 0.75rem; + color: var(--white); + font-size: 1rem; + transition: border-color 0.2s ease; +} + +.register-form input:focus { + outline: none; + border-color: var(--white); +} + +.register-form input::placeholder { + color: var(--maroon-pink); + opacity: 0.7; +} + +#register-submit-btn { + margin-top: 1rem; + background-color: var(--white); + color: var(--bg-black); + border: none; + border-radius: 4px; + padding: 0.75rem; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; +} + +#register-submit-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +/* Responsive design */ +@media (max-width: 480px) { + .main-screen { + padding: 1.5rem; + } + + .register-title { + font-size: 1.75rem; + } +} \ No newline at end of file diff --git a/assets/css/sign-in.css b/assets/css/sign-in.css new file mode 100644 index 0000000..24aa9d5 --- /dev/null +++ b/assets/css/sign-in.css @@ -0,0 +1,94 @@ +/* sign-in */ +.sign-in-section { + min-height: calc(100vh - 74px); + display: flex; + align-items: center; + justify-content: center; + padding: 2rem; +} + +.main-screen { + background-color: rgba(100, 110, 120, 0.1); + backdrop-filter: blur(8px); + border-radius: 12px; + padding: 2.5rem; + width: 100%; + max-width: 460px; +} + +.sign-in-text { + text-align: center; + margin-bottom: 2.5rem; +} + +.sign-in-title { + color: var(--white); + font-size: 2rem; + margin: 0 0 0.5rem 0; +} + +.sign-in-subtext { + color: var(--maroon-pink); + font-weight: normal; + margin: 0; +} + +.sign-in-form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.sign-in-form label { + color: var(--silver); + font-size: 0.9rem; + margin-bottom: -0.5rem; +} + +.sign-in-form input { + background-color: rgba(255, 255, 255, 0.05); + border: 1px solid var(--gray); + border-radius: 4px; + padding: 0.75rem; + color: var(--white); + font-size: 1rem; + transition: border-color 0.2s ease; +} + +.sign-in-form input:focus { + outline: none; + border-color: var(--white); +} + +.sign-in-form input::placeholder { + color: var(--maroon-pink); + opacity: 0.7; +} + +#sign-in-submit-btn { + margin-top: 1rem; + background-color: var(--white); + color: var(--bg-black); + border: none; + border-radius: 4px; + padding: 0.75rem; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; +} + +#sign-in-submit-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +/* Responsive design */ +@media (max-width: 480px) { + .main-screen { + padding: 1.5rem; + } + + .sign-in-title { + font-size: 1.75rem; + } +} \ No newline at end of file diff --git a/assets/js/sign-in.js b/assets/js/sign-in.js new file mode 100644 index 0000000..3b779ed --- /dev/null +++ b/assets/js/sign-in.js @@ -0,0 +1,113 @@ +const url = "https://task-api.fstropii.com"; +const localhostUrl = "http://localhost:8000"; +const signInBtn = document.getElementById("sign-in-submit-btn"); +const tooltip = document.getElementById('tooltip'); + +signInBtn.addEventListener("click", function(e) { + e.preventDefault(); + const username = document.querySelector('.sign-in-username-input').value; + const password = document.querySelector('.sign-in-password-input').value; + + // validate the username and password. will return a promise + const signedInPromise = signIn(username, password); + signedInPromise.then((res) => res.json()).then((json) => validateUser(json)) +}); + +const setTooltip = (type, message) => { + tooltip.classList.add(type); + tooltip.classList.add('visible'); + tooltip.innerText = message + tooltip.style.display = "block"; +} + +const removeTooltip = () => { + tooltip.classList.remove('visible'); + tooltip.style.display = "none"; +} + +const signIn = async (username, password) => { + const res = fetch(`${url}/user/login`, { + method: "POST", + body: JSON.stringify({ + username: username, + password: password + }), + headers: { + "Content-type": "application/json" + } + }); + + return res; +}; + +const validateUser = async (parsedJson) => { + if (parsedJson.detail == "Login successful") { + setTooltip("success", "Login successful"); + + // get user token. will return a promise + const tokenPromise = getUserToken(); + tokenPromise.then((res) => res.json()).then((json => { + const token = json.access_token; + const type = json.token_type; + const expiresInDays = json.expires_days; + + // save a cookie + const cookieText = `token=${token},type=${type},expires_days=${expiresInDays}`; + setCookie(token, type, expiresInDays); + })); + } else if (parsedJson.detail == "Invalid password") { + setTooltip("error", "Invalid password"); + } else if (parsedJson.detail == "User not found") { + setTooltip("error", "User not found"); + } +} + +const getUserToken = async () => { + const form = document.getElementById("sign-in-form"); + const formData = new FormData(form); + + const res = fetch(`${url}/token`, { + method: "POST", + body: formData, + }); + + return res; +} + +const setCookie = (token, type, expires_days) => { + const d = new Date(); + d.setTime(d.getTime() + (expires_days*24*60*60*1000)) + let expires = `expires=${d.toUTCString()}`; + document.cookie = `token=${token},type=${type},${expires}`; +} + +const getCookie = (returnType) => { + let decodedCookie = decodeURIComponent(document.cookie); + if (decodedCookie == "") { + return; + } + + let ca = decodedCookie.split(','); + + const token = ca[0].split("token=")[1]; + const type = ca[1].split("type=")[1]; + const expiresDay = ca[2].split("expires=")[1]; + const expiresDate = ca[3] + const expires = `${expiresDay}${expiresDate}` + + if (returnType == "token") { + return token; + } else if (returnType == "type") { + return type + } else if (returnType == "expires") { + return expires; + } + + return null; +} + +const token = getCookie("token"); + +if (token != undefined) { + window.location.href = '/'; +} \ No newline at end of file diff --git a/assets/pages/register.html b/assets/pages/register.html new file mode 100644 index 0000000..7eeb6ad --- /dev/null +++ b/assets/pages/register.html @@ -0,0 +1,42 @@ + + + + + + Task Manager + + + + +
+
+
+

Create an account!

+

Staying organzied has never been so easy.

+
+ +
+
+ + + + + + + + + + + + +
+
+
+
+ + \ No newline at end of file diff --git a/assets/pages/sign-in.html b/assets/pages/sign-in.html new file mode 100644 index 0000000..c2f3428 --- /dev/null +++ b/assets/pages/sign-in.html @@ -0,0 +1,39 @@ + + + + + + Task Manager + + + + +
+
+ + + +
+
+ + + + \ No newline at end of file diff --git a/assets/pages/user.html b/assets/pages/user.html new file mode 100644 index 0000000..7bd208f --- /dev/null +++ b/assets/pages/user.html @@ -0,0 +1,40 @@ + + + + + Task Manager + + + + +
+
+
+

Welcome to your task manager!

+

Keep yourself organized and stay productive.

+
+ + + + +
+
+ Scroll to explore +
+
+ +
+ + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..d9c851b --- /dev/null +++ b/index.html @@ -0,0 +1,41 @@ + + + + + + Task Manager + + + + +
+
+
+

Welcome to your task manager!

+

Keep yourself organized and stay productive.

+
+ + + + +
+
+ Scroll to explore +
+
+ +
+ + \ No newline at end of file