diff options
author | Alexis Hovorka <[email protected]> | 2024-02-16 23:48:02 -0700 |
---|---|---|
committer | Alexis Hovorka <[email protected]> | 2024-02-16 23:48:02 -0700 |
commit | c5aa364e0e372d0e29063a27bd17811446db8b6a (patch) | |
tree | 5c5b10471f7356b66b74277071e61e5e0447edc5 | |
parent | 773e7f747fa096031be427b22257137cf894d587 (diff) |
[feat] Flesh out basic UI
-rw-r--r-- | app/public/icons.svg | 1 | ||||
-rw-r--r-- | app/public/index.html | 71 | ||||
-rw-r--r-- | app/public/logo-icon.svg | 96 | ||||
-rw-r--r-- | app/public/main.js | 119 | ||||
-rw-r--r-- | app/public/style.css | 414 | ||||
-rw-r--r-- | design/cards.html | 37 | ||||
-rw-r--r-- | design/icons.svg | 68 | ||||
-rw-r--r-- | design/logo-icon.svg | 96 |
8 files changed, 834 insertions, 68 deletions
diff --git a/app/public/icons.svg b/app/public/icons.svg new file mode 100644 index 0000000..47e13fb --- /dev/null +++ b/app/public/icons.svg @@ -0,0 +1 @@ +<svg width="96" height="72" viewBox="0 0 25.4 19.05" xmlns="http://www.w3.org/2000/svg"><g style="fill:#000;stroke-width:2"><g style="stroke-width:2"><path fill="none" style="stroke-width:4" d="M0 0h24v24H0z" transform="matrix(.26458 0 0 .26458 6.35 0)"/><path style="fill:#1ab21a;fill-opacity:1;stroke-width:2" d="M7.333 6h9.333C17.4 6 18 6.6 18 7.334v9.333C18 17.4 17.4 18 16.666 18H7.333C6.6 18 6 17.4 6 16.666V7.333c0-.733.6-1.332 1.333-1.332zM5 3c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z" transform="matrix(.26458 0 0 .26458 6.35 0)"/></g></g><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:4" transform="matrix(.26458 0 0 .26458 12.7 0)"/><path d="M15.824 13.676 14.71 14l-.28-.27a6.5 6.5 0 0 0 1.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 0 0-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 0 0 5.34-1.48l.27.28-.324 1.114 4.905 4.906c.41.41 1.225.265 1.812-.322s.732-1.402.322-1.812zM9.5 12.989A3.484 3.484 0 0 1 6.011 9.5 3.484 3.484 0 0 1 9.5 6.011 3.484 3.484 0 0 1 12.989 9.5 3.484 3.484 0 0 1 9.5 12.989z" style="fill:#1565c0;fill-opacity:1;stroke-width:2" transform="matrix(.26458 0 0 .26458 12.7 0)"/></g><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:4" transform="matrix(.26458 0 0 .26458 19.05 0)"/><g style="opacity:1"><path style="color:#000;font-style:normal;font-variant:normal;font-weight:400;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000;solid-opacity:1;vector-effect:none;fill:#fcc11c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000;stop-opacity:1" d="M12 3c-1.095 0-2 .905-2 2v5H5c-1.095 0-2 .905-2 2s.905 2 2 2h5v5c0 1.095.905 2 2 2s2-.905 2-2v-5h5c1.095 0 2-.905 2-2s-.905-2-2-2h-5V5c0-1.095-.905-2-2-2Z" transform="matrix(.26458 0 0 .26458 19.05 0)"/></g></g><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:4" transform="matrix(.26458 0 0 .26458 0 6.35)"/><path d="M3 17.46v3.04c0 .28.22.5.5.5h3.04c.13 0 .26-.05.35-.15L17.81 9.94l-3.75-3.75L3.15 17.1c-.1.1-.15.22-.15.36ZM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75z" style="fill:red;stroke-width:2" transform="matrix(.26458 0 0 .26458 0 6.35)"/></g><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:4" transform="matrix(.26458 0 0 .26458 19.05 6.35)"/><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z" style="fill:red;stroke-width:2" transform="matrix(.26458 0 0 .26458 19.05 6.35)"/></g><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:4" transform="matrix(.26458 0 0 .26458 6.35 6.35)"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2Zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" style="fill:red;stroke-width:2" transform="matrix(.26458 0 0 .26458 6.35 6.35)"/></g><g style="fill:#000;stroke-width:2"><g style="stroke-width:2" fill="none"><path style="stroke-width:4" d="M0 0h24v24H0z" transform="matrix(.26458 0 0 .26458 12.7 6.35)"/><path style="stroke-width:4" d="M0 0h24v24H0z" transform="matrix(.26458 0 0 .26458 12.7 6.35)"/></g><g style="stroke-width:2"><path d="M19 12.87c0-.47-.34-.85-.8-.98A2.997 2.997 0 0 1 16 9V4h1c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1h1v5c0 1.38-.93 2.54-2.2 2.89-.46.13-.8.51-.8.98V13c0 .55.45 1 1 1h4.98l.02 7c0 .55.45 1 1 1s1-.45 1-1l-.02-7H18c.55 0 1-.45 1-1z" fill-rule="evenodd" style="fill:red;stroke-width:4" transform="matrix(.26458 0 0 .26458 12.7 6.35)"/></g></g><path style="fill:#fff;fill-opacity:1;stroke:none;stroke-width:.264999;stroke-linecap:round;stroke-linejoin:round" d="M12.196 179.652a.53.53 0 0 0-.517.53.53.53 0 0 0 .53.528h3.704a.53.53 0 0 0 .529-.529.53.53 0 0 0-.53-.529H12.21a.53.53 0 0 0-.013 0zm0 1.852a.53.53 0 0 0-.517.53.53.53 0 0 0 .53.529h3.704a.53.53 0 0 0 .529-.53.53.53 0 0 0-.53-.529H12.21a.53.53 0 0 0-.013 0zm0 1.852a.53.53 0 0 0-.517.53.53.53 0 0 0 .53.529h3.704a.53.53 0 0 0 .529-.53.53.53 0 0 0-.53-.529H12.21a.53.53 0 0 0-.013 0z" transform="translate(-10.886 -178.858)"/><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:2" transform="matrix(.26458 0 0 .26458 0 12.7)"/><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2Zm-8.29 13.29a.996.996 0 0 1-1.41 0L5.71 12.7a.996.996 0 1 1 1.41-1.41L10 14.17l6.88-6.88a.996.996 0 1 1 1.41 1.41z" style="stroke-width:2;fill:#1565c0;fill-opacity:1" transform="matrix(.26458 0 0 .26458 0 12.7)"/></g><g style="fill:#000;stroke-width:2"><path d="M0 0h24v24H0Z" fill="none" style="stroke-width:2" transform="matrix(.26458 0 0 .26458 6.35 12.7)"/><path d="M18 19H6c-.55 0-1-.45-1-1V6c0-.55.45-1 1-1h12c.55 0 1 .45 1 1v12c0 .55-.45 1-1 1zm1-16H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2Z" style="stroke-width:2;fill:red" transform="matrix(.26458 0 0 .26458 6.35 12.7)"/></g></svg>
\ No newline at end of file diff --git a/app/public/index.html b/app/public/index.html index c7b44c7..593e6b3 100644 --- a/app/public/index.html +++ b/app/public/index.html @@ -56,26 +56,59 @@ <link rel="stylesheet" href="style.css"> </head> <body> - <h1>Notes</h1> + <dialog id="sign-in-dialog"> + <form id="sign-in-form" class="card" method="dialog"> + <h1 class="logo"><img src="logo-icon.svg" alt="" class="logo-icon"> Notes</h1> + <p id="sign-in-error" class="error-message"></p> + <div> + <input type="text" id="sign-in-username" name="username" placeholder="Username" autocomplete="username" autocorrect="off" autocapitalize="off" spellcheck="false" required autofocus> + <input type="password" id="sign-in-password" name="password" placeholder="Password" autocomplete="current-password" autocorrect="off" autocapitalize="off" spellcheck="false" required> + <label> + <input type="checkbox" id="sign-in-keep-session" name="keepSession"> + <span class="checkbox-icon"></span> Keep me signed in + </label> + <button id="sign-in-basic-go"><span class="loading-spinner"></span>Sign in</button> + </div> + <!--div> + <input type="text" inputmode="numeric" id="sign-in-otp" name="otp" placeholder="OTP Code" autocomplete="one-time-code" autocorrect="off" autocapitalize="off" spellcheck="false" pattern="\d{6,6}" required> + <button id="sign-in-otp-go">Sign in</button> + </div> + <div> + <input type="password" id="sign-in-new-password" name="newPassword" placeholder="New password" autocomplete="new-password" autocorrect="off" autocapitalize="off" spellcheck="false" minlength=8 maxlength=512 required> + <input type="password" id="sign-in-new-password-confirm" name="newPasswordConfirm" placeholder="Confirm new password" autocomplete="new-password" autocorrect="off" autocapitalize="off" spellcheck="false" minlength=8 maxlength=512 required> + <button id="sign-in-change-password-go">Change password</button> + </div--> + </form> + </dialog> - <form> - <input type="text" id="username" name="username"> - <input type="password" id="password" name="password"> - <input type="checkbox" id="keep-session" name="keepSession"> - <button id="login">Log In</button> - </form> - <br> - <input type="password" id="new-password" name="newPassword"> - <button id="change-password">Change Password</button> - <br> - <input type="text" id="new-username" name="newUsername"> - <button id="change-username">Change Username</button> - <br> - <input type="text" id="uid" name="uid"> - <button id="logout">Log Out</button> - <button id="logout-everywhere">Log Out Everywhere</button> - <div id="notes"></div> - <button id="new-note">New Note</button> + <div id="menu" class="card-shadow"> + <div class="card"> + <input type="password" id="new-password" name="newPassword" placeholder="New password" autocomplete="new-password" autocorrect="off" autocapitalize="off" spellcheck="false"> + <button id="change-password">Change password</button> + <br> + <input type="text" id="new-username" name="newUsername" placeholder="New username" autocomplete="none" autocorrect="off" autocapitalize="off" spellcheck="false"> + <button id="change-username">Change username</button> + <br> + <button id="log-out">Log out</button> + <button id="log-out-everywhere">Log out everywhere</button> + <br> + <!--input type="text" inputmode="search" id="search" name="search" placeholder="Search…" list="search-hints"--> + <input type="search" id="search" name="search" placeholder="Search…" list="search-hints" incremental> + <datalist id="search-hints"> + <option value="#hash"></option> + <option value="#tag"></option> + </datalist> + </div> + </div> + + <div id="notes" class="notes-column"></div> + <div id="toolbar"> + <button class="toolbar-btn" id="menu-btn"></button> + <button class="toolbar-btn" id="window-btn"></button> + <button class="toolbar-btn" id="search-btn"></button> + <button class="toolbar-btn" id="conflict-btn"></button> + <button class="toolbar-fab" id="add-btn"></button> + </div> <!--script src="sock.js"></script--> <script src="main.js"></script> diff --git a/app/public/logo-icon.svg b/app/public/logo-icon.svg new file mode 100644 index 0000000..d66678f --- /dev/null +++ b/app/public/logo-icon.svg @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="96" + height="96" + viewBox="0 0 25.4 25.4" + version="1.1" + id="svg1753" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" + sodipodi:docname="logo-icon.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <defs + id="defs1747" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="6.2441455" + inkscape:cx="123.67585" + inkscape:cy="47.999999" + inkscape:document-units="mm" + inkscape:current-layer="text902" + inkscape:document-rotation="0" + showgrid="false" + units="px" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:window-width="1368" + inkscape:window-height="890" + inkscape:window-x="-6" + inkscape:window-y="-6" + inkscape:window-maximized="1" /> + <metadata + id="metadata1750"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(645.044,-144.5381)"> + <rect + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-linecap:round;stroke-linejoin:round" + id="rect2383" + width="16.933332" + height="16.933332" + x="-640.81067" + y="148.77144" /> + <g + style="fill:#000000;stroke-width:0.5" + id="g898" + transform="matrix(1.0583333,0,0,1.0583333,-645.044,144.5381)"> + <g + id="g896" + style="stroke-width:0.5"> + <rect + fill="none" + height="24" + width="24" + id="rect892" + x="0" + y="0" + style="stroke-width:0.25" /> + <path + d="M 19,3 H 5 C 3.9,3 3,3.9 3,5 v 14 c 0,1.1 0.9,2 2,2 h 14 c 1.1,0 2,-0.9 2,-2 V 5 C 21,3.9 20.1,3 19,3 Z M 13,17 H 8 C 7.45,17 7,16.55 7,16 7,15.45 7.45,15 8,15 h 5 c 0.55,0 1,0.45 1,1 0,0.55 -0.45,1 -1,1 z m 3,-4 H 8 C 7.45,13 7,12.55 7,12 7,11.45 7.45,11 8,11 h 8 c 0.55,0 1,0.45 1,1 0,0.55 -0.45,1 -1,1 z M 16,9 H 8 C 7.45,9 7,8.55 7,8 7,7.45 7.45,7 8,7 h 8 c 0.55,0 1,0.45 1,1 0,0.55 -0.45,1 -1,1 z" + id="path894" + style="fill:#fbbc04;fill-opacity:1;stroke-width:0.5" /> + </g> + </g> + <g + aria-label="Notes" + id="text902" + style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:14.9352px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:0.87;stroke:none;stroke-width:0.264583" + transform="translate(-0.91684937)" /> + </g> +</svg> diff --git a/app/public/main.js b/app/public/main.js index 5dc9531..5746142 100644 --- a/app/public/main.js +++ b/app/public/main.js @@ -28,13 +28,25 @@ function debounce(fn, delay) { //} function drawNote(note) { - const el = m(`<div> - <h3>${note.id}</h3> - <textarea>${note.content}</textarea> - </div>`); + const el = m(`<div class="card-shadow"><div class="card"> + <!--h3>${note.id}</h3--> + <textarea>${note.content.trim()}</textarea> + </div></div>`); - $("textarea", el).addEventListener("input", - debounce(() => { saveNote(note.id, $("textarea", el).value); }, 500)); + const ta = $("textarea", el) + + ta.addEventListener("input", + debounce(() => { saveNote(note.id, ta.value); }, 500)); + + function resizeTextarea() { // TODO simplify + el.style.height = (el.scrollHeight) + "px"; + ta.style.height = ""; ta.style.height = (ta.scrollHeight) + "px"; + el.style.height = ""; + } + ta.addEventListener("input", resizeTextarea); + ta.addEventListener("focus", resizeTextarea); + window.addEventListener("resize", resizeTextarea); + setTimeout(resizeTextarea); $("#notes").appendChild(el); } @@ -51,9 +63,7 @@ async function getList() { const list = await res.json(); console.log(list); - for (let i=0;i<list.length;i++) { - await getNote(list[i]); - } + return Promise.all(list.map(id => getNote(id))); } async function saveNote(id, content) { @@ -77,13 +87,12 @@ async function newNote() { drawNote(note); } -$("#new-note").addEventListener("click", newNote); +$("#add-btn").addEventListener("click", newNote); async function getUserData() { const res = await fetch(`/user`); const user = await res.json(); console.log(user); - if (user.uid) $("#uid").value = user.uid; } async function getUserSessions() { @@ -92,26 +101,75 @@ async function getUserSessions() { console.log(sessions); } -$("#login").addEventListener("click", async () => { +function showSignIn() { + const hash = location.hash.slice(2).replace(/^sign-in(\/to\/)?/,""); + history.replaceState("sign-in","","#/sign-in"+(hash?"/to/"+hash:"")); + $("#sign-in-dialog").showModal(); +} + +$("#sign-in-dialog").addEventListener("cancel", e => e.preventDefault()); +$("#sign-in-username").addEventListener("input", e => e.target.classList.remove("error")); +$("#sign-in-password").addEventListener("input", e => e.target.classList.remove("error")); +$("#sign-in-basic-go").addEventListener("click", async e => { + e.preventDefault(); + $("#sign-in-error").textContent = ""; + + const inputs = [ + $("#sign-in-username"), + $("#sign-in-password"), + $("#sign-in-keep-session"), + $("#sign-in-basic-go"), + ]; + const validatedInputs = inputs.slice(0,2); + + if (validatedInputs.map(e => { + if (!e.checkValidity()) { + e.classList.add("error"); + return true; } + }).reduce((a,e) => a||e, false)) return; + + inputs.forEach(e => e.disabled = true); + $("#sign-in-form").classList.add("loading"); + const res = await fetch("/login", { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({ - username: $("#username").value, - password: $("#password").value, - keepSession: $("#keep-session").checked, + username: $("#sign-in-username").value, + password: $("#sign-in-password").value, + keepSession: $("#sign-in-keep-session").checked, }) }); - // TODO check return code + inputs.forEach(e => e.disabled = false); + $("#sign-in-form").classList.remove("loading"); + if (!res.ok) { + $("#sign-in-error").textContent = res.status+" "+res.statusText; + return; + } const json = await res.json(); console.log(json); - // TODO "Must Change Password" flow + if (!json.success) { + $("#sign-in-error").textContent = json.msg; + return; + } + + if (json.mustChangePassword) { + alert("Must change password (TODO)"); + // TODO + return; + } + + const hash = location.hash.slice(9); + history.replaceState("","","#/"+hash); + // TODO load location getUserData(); getList(); + + $("#sign-in-dialog").close(); }); $("#change-password").addEventListener("click", async () => { @@ -119,8 +177,8 @@ $("#change-password").addEventListener("click", async () => { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify({ - username: $("#username").value, - password: $("#password").value, + username: $("#username").value, // TODO + password: $("#password").value, // TODO newPassword: $("#new-password").value, keepSession: $("#keep-session").checked, }) @@ -138,7 +196,7 @@ $("#change-username").addEventListener("click", async () => { headers: {"Content-Type": "application/json"}, body: JSON.stringify({ newUsername: $("#new-username").value, - password: $("#password").value, + password: $("#password").value, // TODO }) }); @@ -148,7 +206,7 @@ $("#change-username").addEventListener("click", async () => { getUserData(); }); -$("#logout").addEventListener("click", async () => { +$("#log-out").addEventListener("click", async () => { const res = await fetch("/logout", { method: "POST", }); @@ -156,19 +214,28 @@ $("#logout").addEventListener("click", async () => { //const json = await res.json(); //console.log(json); console.log("Logged out"); - $("#uid").value = ""; + $("#sign-in-dialog").showModal(); }); -$("#logout-everywhere").addEventListener("click", async () => { +$("#log-out-everywhere").addEventListener("click", async () => { const res = await fetch("/deauth-all", { method: "POST", }); console.log("Logged out everywhere"); - $("#uid").value = ""; + showSignIn(); }); -try { getUserData(); getList(); getUserSessions(); } catch(e) {} +try { await getUserData(); await getList(); await getUserSessions(); } catch(e) { showSignIn(); } + +(() => { + let prevScroll = 0; + window.addEventListener("scroll", () => { + document.querySelector("#toolbar").classList[ + (window.scrollY && window.scrollY > prevScroll)?"add":"remove"]("hide"); + prevScroll = window.scrollY; + }); +})(); // TODO make sure to save unsynced delta even if token has expired, then sync when logged in // TODO Cookie consent on signup; "only necessary for maintaining user session and cached data" @@ -190,4 +257,6 @@ try { getUserData(); getList(); getUserSessions(); } catch(e) {} // https://github.com/cure53/DOMPurify/blob/main/src/attrs.js // https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html +// TODO note kebab menu could be a <dialog> element? + }); diff --git a/app/public/style.css b/app/public/style.css index 655e181..e7dd049 100644 --- a/app/public/style.css +++ b/app/public/style.css @@ -3,12 +3,418 @@ padding: 0; box-sizing: border-box; font-family: "Roboto", "Noto Sans", sans-serif; - transition-timing-function: ease-in-out; + transition-timing-function: cubic-bezier(.4,0,.2,1); } -body { - user-select: none; - -webkit-user-select: none; +/* TODO + - normalize text size + - put all colors in variables + - checklists using ::marker? + - links + - CSS scroll snap for columns + - https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_scroll_snap + - box-decoration-break: clone; -webkit-box-decoration-break: clone; + - overscroll-behavior: contain; + - user-select: text; +*/ + +:root, ::backdrop { + --bg-color: #FFF; + --page-bg-color: #EEE; + --text-color: rgba(0,0,0,.87); + --error-triple: 176, 0, 32; + --error-color: rgb(var(--error-triple)); + --icon-opacity-active: .87; + --icon-opacity-inactive: .6; + --icon-opacity-disabled: .38; + --icon-inactive-filter: brightness(0); + --icon-checkbox-active-filter: brightness(1); + --icon-add-hover-filter: brightness(1); + --icon-menu-hover-filter: brightness(1); + --icon-search-hover-filter: brightness(1); + --icon-window-hover-filter: brightness(1); + --menu-button-hover-bg-color: #FBBC04; + --button-hover-bg-color: #FFF; + --button-hover-shadow: 0 2px 16px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.2); + --fab-bg: #FFF; + --fab-shadow: 0 2px 12px rgba(0,0,0,.15), 0 2px 6px rgba(0,0,0,.2); + --fab-shadow-hover: 0 4px 16px rgba(0,0,0,.2), 0 3px 6px rgba(0,0,0,.3); + --toolbar-shadow-mobile: 0 8px 8px 8px rgba(0,0,0,.2); + --toolbar-hide-distance-mobile: calc(-56px - 8px); + --toolbar-button-hover-bg-mobile: rgba(0,0,0,.1); +} + +/*@media (prefers-color-scheme: dark) { :root, ::backdrop { + --bg-color: #000; + --page-bg-color: #000; + --text-color: rgba(255,255,255,.87); + --error-triple: 245, 0, 45; + --error-color: rgb(var(--error-triple)); + --icon-opacity-active: .87; + --icon-opacity-inactive: .6; + --icon-opacity-disabled: .38; + --icon-inactive-filter: brightness(0) invert(1) hue-rotate(180deg); + --icon-add-hover-filter: brightness(1.4) invert(.1) hue-rotate(0); + --icon-menu-hover-filter: brightness(1) invert(1) hue-rotate(180deg); + --icon-search-hover-filter: brightness(1) invert(1) hue-rotate(180deg); + --icon-window-hover-filter: brightness(.75) invert(1) hue-rotate(180deg); + --menu-button-hover-bg-color: #FBBC04; + --button-hover-bg-color: #181818; + --button-hover-shadow: 0 0 0 transparent; + --fab-bg: #333; + --fab-shadow: 0 2px 12px rgba(0,0,0,.2), 0 2px 6px rgba(0,0,0,.24); + --fab-shadow-hover: 0 2px 12px rgba(0,0,0,.2), 0 2px 6px rgba(0,0,0,.24); + --toolbar-shadow-mobile: 0 8px 8px 8px #000, 0 56px 56px -56px rgba(255,255,255,.25) inset; + --toolbar-hide-distance-mobile: calc(-56px - 8px); + --toolbar-button-hover-bg-mobile: rgba(255,255,255,.1); +}}*/ + +html { + background: var(--page-bg-color); + color: var(--text-color); + overscroll-behavior: contain; +} + +body, dialog { /* TODO */ + user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; } + +#toolbar { position: fixed; font-size: 0; } +#toolbar > * { font-size: 16px; text-align: center; } +.toolbar-btn { height: 48px; width: 48px; } +.toolbar-btn, .toolbar-fab { + position: relative; + border-radius: 100%; + background: transparent; + border: none; + outline: none; +} + +.toolbar-btn:not(#conflict-btn)::after, .toolbar-fab::after { content: ""; display: block; height: 24px; width: 24px; background-image: url("icons.svg"); filter: var(--icon-inactive-filter); opacity: var(--icon-opacity-active); position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } +#menu-btn::after { background-position: 0 0; } +#window-btn::after { background-position: -24px 0; } +#search-btn::after { background-position: -48px 0; } +#add-btn::after { background-position: -72px 0; } + +#conflict-btn { display: none; vertical-align: bottom; } +#conflict-btn::after { content: ""; position: absolute; top: 50%; left: 50%; display: block; height: 8px; width: 8px; border-radius: 4px; background: rgba(var(--error-triple), .8); transform: translate(-50%,-50%); } + +@media (hover:hover) { + .toolbar-btn, .toolbar-fab { cursor: pointer; transition: background-color .2s, box-shadow .2s; } + .toolbar-btn:not(#conflict-btn)::after, .toolbar-fab::after { transition: opacity .1s, filter .1s; filter: var(--icon-inactive-filter); } + .toolbar-btn:not(#conflict-btn):hover::after, .toolbar-fab:hover::after { opacity: 1; } + + #menu-btn:hover::after { filter: var(--icon-menu-hover-filter); } + #window-btn:hover::after { filter: var(--icon-window-hover-filter); } + #search-btn:hover::after { filter: var(--icon-search-hover-filter); } + #add-btn:hover::after { filter: var(--icon-add-hover-filter); } + + #conflict-btn::after { transition: box-shadow .1s; } + #conflict-btn:hover::after { box-shadow: 0 0 0 4px rgba(var(--error-triple),.25); } +} + +@media (hover:hover) and (min-width:601px) { + .notes-column { padding: 8px 80px 16px; } + #toolbar { top: 16px; left: 50%; transform: translate(-50%,0); width: 100%; max-width: calc(7in + 16px); pointer-events: none; } + #toolbar > * { pointer-events: auto; } + .toolbar-fab { height: 48px; width: 48px; } + .toolbar-btn, .toolbar-fab { display: block; margin: 0 16px; } + .toolbar-btn:not(#conflict-btn):hover, .toolbar-fab:hover { background-color: var(--button-hover-bg-color); box-shadow: var(--button-hover-shadow); } + .toolbar-btn:not(#conflict-btn)::after, .toolbar-fab::after { opacity: var(--icon-opacity-inactive) } + .toolbar-btn:not(#conflict-btn):hover::after, .toolbar-fab:hover::after { opacity: var(--icon-opacity-active) } + + #menu-btn:hover { background-color: var(--menu-button-hover-bg-color) !important; } + #search-btn { position: absolute; top: 0; right: 0; } + #add-btn { position: absolute; top: 48px; right: 0; } + #conflict-btn { height: 42px; } + #conflict-btn.show { display: block; } +} + +@media (hover:none), (max-width:600px) { + .notes-column { padding: 0 16px 16px; } + #toolbar { bottom: 0; left: 0; right: 0; width: 100%; box-shadow: var(--toolbar-shadow-mobile); padding: 0 4px; background: var(--bg-color); transition: bottom .25s; /* reentrance speed */ } + .toolbar-btn { display: inline-block; } + .toolbar-fab { position: absolute; display: block; right: 16px; top: -28px; width: 56px; height: 56px; box-shadow: var(--fab-shadow); background: var(--fab-bg); transition: top .25s; } + #conflict-btn { width: 36px; } + #conflict-btn.show { display: inline-block; } + + #toolbar.hide { bottom: var(--toolbar-hide-distance-mobile); transition: bottom .2s; /* exit speed */ } + #toolbar.hide .toolbar-fab { top: calc(var(--toolbar-hide-distance-mobile) - 16px); transition: top .2s; } + + @media (orientation:portrait) { + .toolbar-btn { margin: 4px 0; } + } + + @media (orientation:landscape) { + .toolbar-btn { margin: 0; } + } +} + +@media (hover:hover) and (max-width:600px) { + .toolbar-btn:not(#conflict-btn)::before { content: ""; display: block; position: absolute; top: 50%; left: 50%; height: 40px; width: 40px; border-radius: 20px; transform: translate(-50%,-50%); transition: background-color .2s; } + .toolbar-btn:not(#conflict-btn):hover::before { background-color: var(--toolbar-button-hover-bg-mobile); } + #menu-btn:hover::before { background-color: var(--menu-button-hover-bg-color) !important; } + .toolbar-fab { transition: top .25s, box-shadow .2s; } + #toolbar.hide .toolbar-fab { transition: top .2s, box-shadow .2s; } + .toolbar-fab:hover { box-shadow: var(--fab-shadow-hover); } + #add-btn::after { transition: opacity .15s, filter .15s, transform .2s; } + #add-btn:hover::after { filter: var(--icon-add-hover-filter); transform: translate(-50%,-50%) scale(1.25); } +} + +.logo { + font-weight: 500; + word-spacing: -.15em; +} +.logo-icon { + vertical-align: -.45em; + height: 1.6em; +} + +#sign-in-dialog { + margin: auto; + width: auto; + max-width: min(5.5in, 100vw - 32px); + outline: none; + border: none; + border-radius: 24px; + box-shadow: 0 2px 16px rgba(0,0,0,.05), 0 2px 4px rgba(0,0,0,.1); + transition: box-shadow .2s; +} +#sign-in-dialog::after { + content: ""; + position: absolute; + inset: 0; + box-shadow: 0 0 0 1px rgba(255,255,255,.2) inset; + border-radius: 24px; + pointer-events: none; + transition: box-shadow .2s; +} +#sign-in-dialog::backdrop { + background: var(--page-bg-color); +} +#sign-in-form { + display: block; + padding: 16px 16px 40px; + + & .logo { + margin: 16px 0; + padding: .1em .3em .1em 0; + font-size: min(48px, 12vw); + text-align: center; + } + + & .error-message { + text-align: center; + color: var(--error-color); + } + + & input[type=text], + & input[type=password], + & label, + & button { + display: block; + width: 100%; + max-width: 3.5in; + margin: 12px auto; + font-size: inherit; + letter-spacing: .3px; + color: var(--text-color); + border-radius: 16px; + } + + & input[type=text], + & input[type=password], + & button { + padding: 12px 18px; + outline: 0; + } + & input[type=text], + & input[type=password] { + position: relative; + background-color: #FFF; + border: 1px solid #FFF; + border-bottom: 1px solid rgba(0,0,0,.15); + box-shadow: 0 2px 1px -1px rgba(0,0,0,.1); + transition: border .2s, box-shadow .2s, opacity .2s; + } + & input[type=text]:hover:not(:disabled), + & input[type=password]:hover:not(:disabled), + & input[type=text]:focus, + & input[type=password]:focus { + border: 1px solid rgba(0,0,0,.07); + border-bottom: 1px solid rgba(0,0,0,.18); + box-shadow: 0 2px 16px rgba(0,0,0,.05), 0 2px 4px rgba(0,0,0,.15); + } + & input[type=text]::placeholder, + & input[type=password]::placeholder { + color: rgba(0,0,0,.6); + } + & input[type=text]:autofill, + & input[type=password]:autofill { + background-color: rgb(232,240,254); + border: 1px solid rgb(179,207,255); + } + & input[type=text].error, + & input[type=password].error { + background-color: rgb(254,232,232); + border: 1px solid rgb(255,191,191); + } + & input[type=text].error:focus, + & input[type=password].error:focus { + box-shadow: 0 2px 16px rgba(0,0,0,.05), 0 2px 4px rgba(0,0,0,.15), 0 0 1px 2px rgb(255,191,191) inset; + } + + & label { + width: fit-content; + padding: 8px 12px 8px 8px; + text-align: center; + cursor: pointer; + transition: background-color .2s, opacity .2s; + } + & label:focus-within:has(:focus-visible) { + background-color: rgb(232,240,254); + text-align: center; + cursor: pointer; + } + & input[type=checkbox] { + display: inline-block; + height: 0; + width: 0; + opacity: 0; + } + .checkbox-icon { + display: inline-block; + height: 24px; + width: 24px; + vertical-align: -.36em; + background-image: url("icons.svg"); + background-position: -24px -48px; + filter: var(--icon-inactive-filter); + opacity: var(--icon-opacity-inactive); + } + input[type=checkbox]:checked + .checkbox-icon { + background-position: 0 -48px; + filter: var(--icon-checkbox-active-filter); + opacity: var(--icon-opacity-active); + } + + & button { + position: relative; + font-weight: 500; + background-color: rgba(0,0,0,.06); + border: none; + cursor: pointer; + transition: background-color .2s, box-shadow .2s; + } + & button:hover, + & button:focus, + &.loading button { + background-color: #FBBC04; + } + & button:focus-visible { + box-shadow: 0 0 0 4px rgba(251,188,4,.4); + } + & input + button { + margin-top: 32px; + } + &.loading button { + color: transparent; + } + + & button .loading-spinner { + inset: 50%; + transform: translate(-50%,calc(-50% - 1em)); + display: none; + } + &.loading button .loading-spinner { + display: inline-block; + } + & .loading-spinner, + & .loading-spinner::before, + & .loading-spinner::after { + position: absolute; + border-radius: 50%; + width: .7em; + height: .7em; + animation-fill-mode: both; + animation: loading-spinner 1.8s infinite ease-in-out; + } + & .loading-spinner { + animation-delay: -0.16s; + } + & .loading-spinner::before, + & .loading-spinner::after { + content: ''; + top: 0; + } + & .loading-spinner::before { + left: -1.3em; + animation-delay: -0.32s; + } + & .loading-spinner::after { + left: 1.3em; + } + + &.loading input, + &.loading label { + opacity: .5; + } +} +@keyframes loading-spinner { + 0%, 80%, 100% { box-shadow: 0 1em 0 -1.3em #fff; } + 40% { box-shadow: 0 1em 0 0 #fff; } +} + +.notes-column { + overflow-y: auto; +} + +/* TODO :target? */ +.card-shadow { + position: relative; + margin: 16px auto; + max-width: 5.5in; + border-radius: 24px; + box-shadow: 0 2px 16px rgba(0,0,0,.05), 0 2px 4px rgba(0,0,0,.1); + transition: box-shadow .2s; +} +.card-shadow:hover, +.card-shadow:focus-within { + box-shadow: 0 2px 16px rgba(0,0,0,.15), 0 2px 4px rgba(0,0,0,.15); +} +.card-shadow::after { + content: ""; + position: absolute; + inset: 0; + box-shadow: 0 0 0 1px rgba(255,255,255,.2) inset; + border-radius: 24px; + pointer-events: none; + transition: box-shadow .2s; +} +.card-shadow:hover::after, +.card-shadow:focus-within::after { + box-shadow: 0 0 0 2px rgba(255,255,255,.25) inset; +} +.card { + /*padding-bottom: 16px;*/ + border-radius: 24px; + background-color: var(--bg-color); + color: var(--text-color); + overflow: hidden; +} + +.card > textarea { /* TODO */ + display: block; + width: 100%; + padding: 16px 24px; + border: none; + resize: none; + outline: none; + font-size: 16px; + line-height: 24px; + letter-spacing: .3px; + background: transparent; + color: inherit; +} diff --git a/design/cards.html b/design/cards.html index d6d2a7c..d2f3ad4 100644 --- a/design/cards.html +++ b/design/cards.html @@ -111,6 +111,37 @@ .card:has(img:last-child) { padding-bottom: 0; } + + code { + margin: 0 -2px; + padding: 2px 4px; + font: 14px/1.3em "Hack", monospace; + white-space: nowrap; + background: rgba(0,0,0,.05); + border-radius: 4px; + letter-spacing: 0; + } + .gfm-color_chip { + display: inline-block; + line-height: 1; + margin: 0 0 2px 4px; + vertical-align: middle; + border-radius: 3px; + width: 0.9em; + height: 0.9em; + background: #fff; + background-image: linear-gradient(135deg, #ded6ee 25%, transparent 0%, transparent 75%, #ded6ee 0%),linear-gradient(135deg, #ded6ee 25%, transparent 0%, transparent 75%, #ded6ee 0%); + background-size: 1em 1em; + background-position: 0 0, 0.5em 0.5em; + } + .gfm-color_chip>span { + display: inline-block; + width: 100%; + height: 100%; + margin-bottom: 2px; + border-radius: 3px; + border: 1px solid rgba(31,30,36,0.24); + } </style> </head> <body> @@ -122,12 +153,12 @@ </h3> <h2>Example Note</h2> <p>Meh <strong>bold</strong> <em>italic</em> meh whatever <del>lorem</del> ipsum dolor sit amet adispicing elit</p> - <p><span style="color:#1565C0">Foobar</span> <span style="color:#b00020">lipsum</span> <span style="background:#feefc3">yeet</span></p> - <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p> + <p><span style="color:#1565C0">Foobar</span> <span style="color:#b00020">lipsum</span> <span style="background:#feefc3">yeet</span> <code>uwu</code></p> + <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Call the <code>load()</code> function. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p> <pre>function test() { return 42; }</pre> - <p>It has <em>survived</em> not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p> + <p>It has <em>survived</em> not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. <code>RGBA(0,255,0,0.3)<span class="gfm-color_chip"><span style="background-color: RGBA(0,255,0,0.3);"></span></span></code></p> <div class="tags"><span class="tag">#hash</span> <span class="tag">#tag</span> <i class="material-icons-round">more_vert</i> </div> diff --git a/design/icons.svg b/design/icons.svg index 563df7f..1526d57 100644 --- a/design/icons.svg +++ b/design/icons.svg @@ -1,19 +1,19 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="96" - height="48" - viewBox="0 0 25.399999 12.7" + height="72" + viewBox="0 0 25.399999 19.05" version="1.1" id="svg1041" sodipodi:docname="icons.svg" - inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07, custom)"> + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> <defs id="defs1035" /> <sodipodi:namedview @@ -27,7 +27,7 @@ inkscape:cx="48" inkscape:cy="24" inkscape:document-units="mm" - inkscape:current-layer="g3200" + inkscape:current-layer="g1110" inkscape:document-rotation="0" showgrid="false" fit-margin-top="0" @@ -37,7 +37,14 @@ units="px" showguides="true" inkscape:guide-bbox="true" - inkscape:pagecheckerboard="true" /> + inkscape:pagecheckerboard="true" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" + inkscape:window-width="1368" + inkscape:window-height="890" + inkscape:window-x="-6" + inkscape:window-y="-6" + inkscape:window-maximized="1" /> <metadata id="metadata1038"> <rdf:RDF> @@ -46,7 +53,6 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title /> </cc:Work> </rdf:RDF> </metadata> @@ -72,7 +78,7 @@ style="stroke-width:4" /> <path id="path946" - style="fill:#1ab21a;stroke-width:2;fill-opacity:1" + style="fill:#1ab21a;fill-opacity:1;stroke-width:2" d="m 7.3331298,6.0005772 h 9.3331632 c 0.733313,0 1.333419,0.5993013 1.333419,1.3326144 v 9.3331524 c 0,0.733319 -0.600106,1.333424 -1.333419,1.333424 H 7.3331298 c -0.7333131,0 -1.3334182,-0.600105 -1.3334182,-1.333424 V 7.3331916 c 0,-0.7333131 0.6001051,-1.3326144 1.3334182,-1.3326144 z M 5.0002,3.000172 c -1.1,0 -2,0.9 -2,2 v 14 c 0,1.1 0.9,2 2,2 h 14 c 1.1,0 2,-0.9 2,-2 v -14 c 0,-1.1 -0.9,-2 -2,-2 z" /> </g> </g> @@ -89,7 +95,7 @@ d="M 15.824121,13.675879 14.71,14 14.43,13.73 c 1.2,-1.4 1.82,-3.31 1.48,-5.34 -0.47,-2.78 -2.79,-5 -5.59,-5.34 -4.23,-0.52 -7.79,3.04 -7.27,7.27 0.34,2.8 2.56,5.12 5.34,5.59 2.03,0.34 3.94,-0.28 5.34,-1.48 l 0.27,0.28 -0.324121,1.114121 4.905161,4.905839 c 0.410071,0.410128 1.224774,0.265226 1.81196,-0.32196 0.587186,-0.587186 0.73196,-1.40196 0.32196,-1.81196 z M 9.5,12.989033 c -1.9305983,0 -3.489033,-1.558435 -3.489033,-3.489033 0,-1.9305983 1.5584347,-3.489033 3.489033,-3.489033 1.930598,0 3.489033,1.5584347 3.489033,3.489033 0,1.930598 -1.558435,3.489033 -3.489033,3.489033 z" id="path971" sodipodi:nodetypes="ccccccccccssccsssss" - style="fill:#1565c0;stroke-width:2;fill-opacity:1" /> + style="fill:#1565c0;fill-opacity:1;stroke-width:2" /> </g> <g style="fill:#000000;stroke-width:2" @@ -105,7 +111,7 @@ style="opacity:1"> <path style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#fcc11c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1" - d="M 12 3 C 10.904545 3 10 3.9045455 10 5 L 10 10 L 5 10 C 3.9045455 10 3 10.904545 3 12 C 3 13.095455 3.9045455 14 5 14 L 10 14 L 10 19 C 10 20.095455 10.904545 21 12 21 C 13.095455 21 14 20.095455 14 19 L 14 14 L 19 14 C 20.095455 14 21 13.095455 21 12 C 21 10.904545 20.095455 10 19 10 L 14 10 L 14 5 C 14 3.9045455 13.095455 3 12 3 z " + d="m 12,3 c -1.095455,0 -2,0.9045455 -2,2 v 5 H 5 c -1.0954545,0 -2,0.904545 -2,2 0,1.095455 0.9045455,2 2,2 h 5 v 5 c 0,1.095455 0.904545,2 2,2 1.095455,0 2,-0.904545 2,-2 v -5 h 5 c 1.095455,0 2,-0.904545 2,-2 0,-1.095455 -0.904545,-2 -2,-2 H 14 V 5 C 14,3.9045455 13.095455,3 12,3 Z" id="path3204" /> </g> </g> @@ -187,7 +193,35 @@ </g> <path id="rect2982-1" - style="fill:#ffffff;stroke:none;stroke-width:0.264999;stroke-linecap:round;stroke-linejoin:round;fill-opacity:1" + style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-linecap:round;stroke-linejoin:round" d="m 12.19571,179.65208 a 0.52916669,0.52916716 0 0 0 -0.516248,0.52917 0.52916669,0.52916716 0 0 0 0.529167,0.52916 h 3.704166 a 0.52916621,0.52916716 0 0 0 0.529167,-0.52916 0.52916621,0.52916716 0 0 0 -0.529167,-0.52917 h -0.01292 -3.691247 a 0.52916669,0.52916716 0 0 0 -0.01292,0 z m 0,1.85208 a 0.52916669,0.52916716 0 0 0 -0.516248,0.52917 0.52916669,0.52916716 0 0 0 0.529167,0.52917 h 3.704166 a 0.52916621,0.52916716 0 0 0 0.529167,-0.52917 0.52916621,0.52916716 0 0 0 -0.529167,-0.52917 h -3.704166 a 0.52916669,0.52916716 0 0 0 -0.01292,0 z m 0,1.85209 a 0.52916669,0.52916716 0 0 0 -0.516248,0.52916 0.52916669,0.52916716 0 0 0 0.529167,0.52917 h 3.704166 a 0.52916621,0.52916716 0 0 0 0.529167,-0.52917 0.52916621,0.52916716 0 0 0 -0.529167,-0.52916 h -3.704166 a 0.52916669,0.52916716 0 0 0 -0.01292,0 z" /> + <g + style="fill:#000000;stroke-width:2" + id="g1110" + transform="matrix(0.26458333,0,0,0.26458333,10.885714,191.55833)"> + <path + d="M 0,0 H 24 V 24 H 0 Z" + fill="none" + id="path1096" + style="stroke-width:2" /> + <path + d="M 19,3 H 5 C 3.9,3 3,3.9 3,5 v 14 c 0,1.1 0.9,2 2,2 h 14 c 1.1,0 2,-0.9 2,-2 V 5 C 21,3.9 20.1,3 19,3 Z m -8.29,13.29 c -0.39,0.39 -1.02,0.39 -1.41,0 L 5.71,12.7 c -0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0 L 10,14.17 16.88,7.29 c 0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41 z" + id="path1098" + style="stroke-width:2;fill:#1565c0;fill-opacity:1" /> + </g> + <g + style="fill:#000000;stroke-width:2" + id="g1126" + transform="matrix(0.26458333,0,0,0.26458333,17.235714,191.55833)"> + <path + d="M 0,0 H 24 V 24 H 0 Z" + fill="none" + id="path1112" + style="stroke-width:2" /> + <path + d="M 18,19 H 6 C 5.45,19 5,18.55 5,18 V 6 C 5,5.45 5.45,5 6,5 h 12 c 0.55,0 1,0.45 1,1 v 12 c 0,0.55 -0.45,1 -1,1 z M 19,3 H 5 C 3.9,3 3,3.9 3,5 v 14 c 0,1.1 0.9,2 2,2 h 14 c 1.1,0 2,-0.9 2,-2 V 5 C 21,3.9 20.1,3 19,3 Z" + id="path1114" + style="stroke-width:2;fill:#ff0000" /> + </g> </g> </svg> diff --git a/design/logo-icon.svg b/design/logo-icon.svg new file mode 100644 index 0000000..d66678f --- /dev/null +++ b/design/logo-icon.svg @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="96" + height="96" + viewBox="0 0 25.4 25.4" + version="1.1" + id="svg1753" + inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)" + sodipodi:docname="logo-icon.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <defs + id="defs1747" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="6.2441455" + inkscape:cx="123.67585" + inkscape:cy="47.999999" + inkscape:document-units="mm" + inkscape:current-layer="text902" + inkscape:document-rotation="0" + showgrid="false" + units="px" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:window-width="1368" + inkscape:window-height="890" + inkscape:window-x="-6" + inkscape:window-y="-6" + inkscape:window-maximized="1" /> + <metadata + id="metadata1750"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(645.044,-144.5381)"> + <rect + style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.264999;stroke-linecap:round;stroke-linejoin:round" + id="rect2383" + width="16.933332" + height="16.933332" + x="-640.81067" + y="148.77144" /> + <g + style="fill:#000000;stroke-width:0.5" + id="g898" + transform="matrix(1.0583333,0,0,1.0583333,-645.044,144.5381)"> + <g + id="g896" + style="stroke-width:0.5"> + <rect + fill="none" + height="24" + width="24" + id="rect892" + x="0" + y="0" + style="stroke-width:0.25" /> + <path + d="M 19,3 H 5 C 3.9,3 3,3.9 3,5 v 14 c 0,1.1 0.9,2 2,2 h 14 c 1.1,0 2,-0.9 2,-2 V 5 C 21,3.9 20.1,3 19,3 Z M 13,17 H 8 C 7.45,17 7,16.55 7,16 7,15.45 7.45,15 8,15 h 5 c 0.55,0 1,0.45 1,1 0,0.55 -0.45,1 -1,1 z m 3,-4 H 8 C 7.45,13 7,12.55 7,12 7,11.45 7.45,11 8,11 h 8 c 0.55,0 1,0.45 1,1 0,0.55 -0.45,1 -1,1 z M 16,9 H 8 C 7.45,9 7,8.55 7,8 7,7.45 7.45,7 8,7 h 8 c 0.55,0 1,0.45 1,1 0,0.55 -0.45,1 -1,1 z" + id="path894" + style="fill:#fbbc04;fill-opacity:1;stroke-width:0.5" /> + </g> + </g> + <g + aria-label="Notes" + id="text902" + style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:14.9352px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto, Medium';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:0.87;stroke:none;stroke-width:0.264583" + transform="translate(-0.91684937)" /> + </g> +</svg> |