From 025f273f48074bcc06affba0d91c67f09f1ac5a8 Mon Sep 17 00:00:00 2001 From: yequari Date: Mon, 24 Mar 2025 21:00:19 -0700 Subject: [PATCH] improve UI with classless css library and other various modifications --- cmd/web/handlers_user.go | 3 +- ui/static/css/classless.min.css | 1 + ui/static/css/style.css | 12 +- ui/views/common.templ | 19 +- ui/views/common_templ.go | 28 +- ui/views/common_templ.txt | 8 +- ui/views/guestbooks.templ | 127 +++-- ui/views/guestbooks_templ.go | 804 ++++++++++++++------------------ ui/views/guestbooks_templ.txt | 53 +-- ui/views/websites.templ | 2 +- ui/views/websites_templ.go | 4 +- ui/views/websites_templ.txt | 2 +- 12 files changed, 496 insertions(+), 567 deletions(-) create mode 100644 ui/static/css/classless.min.css diff --git a/cmd/web/handlers_user.go b/cmd/web/handlers_user.go index b2b0163..772c8d4 100644 --- a/cmd/web/handlers_user.go +++ b/cmd/web/handlers_user.go @@ -98,7 +98,8 @@ func (app *application) postUserLogout(w http.ResponseWriter, r *http.Request) { } app.sessionManager.Remove(r.Context(), "authenticatedUserId") app.sessionManager.Put(r.Context(), "flash", "You've been logged out successfully!") - http.Redirect(w, r, "/", http.StatusSeeOther) + w.Header().Add("HX-Redirect", "/") + // http.Redirect(w, r, "/", http.StatusSeeOther) } // func (app *application) getUsersList(w http.ResponseWriter, r *http.Request) { diff --git a/ui/static/css/classless.min.css b/ui/static/css/classless.min.css new file mode 100644 index 0000000..e24e3b5 --- /dev/null +++ b/ui/static/css/classless.min.css @@ -0,0 +1 @@ +:root{--primary: #364153;--primary-contrast: #202732;--primary-invert: #364153;--secondary: #64748b;--secondary-light: #94a3b8;--success: #10b981;--success-light: #34d399;--danger: #ef4444;--danger-light: #f87171;--warning: #f59e0b;--warning-light: #fbbf24;--info: #0ea5e9;--info-light: #38bdf8;--light: #f8fafc;--dark: #1e293b;--body-bg: #ffffff;--body-color: #334155;--heading-color: #1e293b;--link-color: #1d72fc;--link-hover-color: #0b65ff;--border-color: #e2e8f0;--shadow-color: rgba(0,0,0,0.1);--card-bg: #ffffff;--progress-color: #60ed7c;--input-icon-color: #64748b;--gradient-primary: linear-gradient(135deg,var(--primary) 0%,var(--primary-contrast) 100%);--gradient-link: linear-gradient(135deg,var(--link-color) 0%,var(--link-hover-color) 100%);--gradient-secondary: linear-gradient(135deg,var(--secondary) 0%,var(--secondary-light) 100%);--gradient-success: linear-gradient(135deg,var(--success) 0%,var(--success-light) 100%);--gradient-danger: linear-gradient(135deg,var(--danger) 0%,var(--danger-light) 100%);--gradient-warning: linear-gradient(135deg,var(--warning) 0%,var(--warning-light) 100%);--gradient-info: linear-gradient(135deg,var(--info) 0%,var(--info-light) 100%);--shadow-sm: 0 1px 2px 0 rgba(0,0,0,0.1);--shadow: 0 4px 6px -1px rgba(0,0,0,0.1),0 2px 4px -1px rgba(0,0,0,0.06);--shadow-md: 0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05);--shadow-lg: 0 20px 25px -5px rgba(0,0,0,0.1),0 10px 10px -5px rgba(0,0,0,0.04);--font-family-sans: 'Inter',system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;--font-family-mono: ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--font-size-base: 1rem;--line-height-base: 1.6;--font-weight-normal: 400;--font-weight-medium: 500;--font-weight-bold: 700;--spacing-base: 1rem;--spacing-base-half: 0.5rem;--border-radius-sm: 0.25rem;--border-radius: 0.5rem;--border-radius-md: 0.75rem;--border-radius-lg: 1rem;--border-radius-xl: 1.5rem;--border-radius-full: 9999px;--container-max-width: 1200px;--transition-base: all 0.2s ease-in-out;--transition-slow: all 0.3s ease-in-out;color-scheme: light;--color-mode: 'light';}@media (prefers-color-scheme: dark){:root{--color-mode: 'dark';}}:root[color-scheme="dark"]{--primary: #13181f;--primary-contrast: #13181f;--primary-invert: #cbe0ff;--body-bg: #0f172a;--body-color: #e2e8f0;--heading-color: #f8fafc;--border-color: #334155;--shadow-color: rgba(0,0,0,0.3);--card-bg: #1e293b;--link-color: #61aeff;--progress-color: #2f9e45;--input-icon-color: #e2e8f0;--shadow-sm: 0 1px 2px 0 rgba(0,0,0,0.2);--shadow: 0 4px 6px -1px rgba(0,0,0,0.3),0 2px 4px -1px rgba(0,0,0,0.2);--shadow-md: 0 10px 15px -3px rgba(0,0,0,0.3),0 4px 6px -2px rgba(0,0,0,0.2);--shadow-lg: 0 20px 25px -5px rgba(0,0,0,0.3),0 10px 10px -5px rgba(0,0,0,0.2);}*{margin: 0;padding: 0;box-sizing: border-box;}html{font-size: 16px;scroll-behavior: smooth;}body{font-family: var(--font-family-sans);font-size: var(--font-size-base);line-height: var(--line-height-base);color: var(--body-color);background-color: var(--body-bg);padding: var(--spacing-base);max-width: var(--container-max-width);margin: 0 auto;transition: var(--transition-slow);animation: colorSchemeTransition 0.5s ease-out;}h1,h2,h3,h4,h5,h6{color: var(--heading-color);margin-bottom: var(--spacing-base);font-weight: var(--font-weight-bold);line-height: 1.2;letter-spacing: -0.025em;text-wrap: balance;}h1{font-size: 2.75rem;margin-top: 2rem;;}h2{font-size: 2.25rem;margin-top: 1.75rem;position: relative;}h2:after{content: "";position: absolute;bottom: -0.5rem;left: 0;width: 3rem;height: 0.15rem;background: var(--primary-contrast);border-radius: var(--border-radius-full);}h3{font-size: 1.75rem;margin-top: 1.5rem;}h4{font-size: 1.5rem;margin-top: 1.25rem;}h5{font-size: 1.25rem;margin-top: 1rem;}h6{font-size: 1rem;margin-top: 0.75rem;text-transform: uppercase;letter-spacing: 0.05em;}p{margin-top: var(--spacing-base-half);margin-bottom: var(--spacing-base);}a{color: var(--link-color);text-decoration: none;transition: var(--transition-base);position: relative;}a:hover{color: var(--link-hover-color);}a:not(nav a):before{content: '';position: absolute;width: 100%;transform: scaleX(0);height: 2px;bottom: -2px;left: 0;background: var(--gradient-link);transform-origin: bottom right;transition: transform 0.3s ease-out;}a:not(nav a):hover:before{transform: scaleX(1);transform-origin: bottom left;}a[target="_blank"]:after{content: "[+]";display: inline-block;margin-left: 0.25em;font-size: 0.6em;font-weight: bold;text-decoration: none;vertical-align: super;}small{font-size: 0.875rem;opacity: 0.85;}code,pre{font-family: var(--font-family-mono);border-radius: var(--border-radius);}code{padding: 0.2em 0.4em;font-size: 0.875em;background-color: rgba(0,0,0,0.05);}:root[color-scheme="dark"] code{background-color: rgba(255,255,255,0.1);}pre{padding: var(--spacing-base);margin-bottom: var(--spacing-base);overflow-x: auto;background-color: rgba(0,0,0,0.03);border-radius: var(--border-radius-md);box-shadow: var(--shadow-sm);}:root[color-scheme="dark"] pre{background-color: rgba(255,255,255,0.05);}pre code{display: inline-block;background-color: transparent;min-width: 100%;}blockquote{border-left: 4px solid var(--primary);padding: var(--spacing-base);margin-bottom: var(--spacing-base);font-style: italic;background-color: rgba(0,0,0,0.02);border-radius: 0 var(--border-radius) var(--border-radius) 0;box-shadow: var(--shadow-sm);}:root[color-scheme="dark"] blockquote{background-color: rgba(255,255,255,0.03);}hr{border: 0;height: 1px;background: linear-gradient(to right,transparent,var(--border-color),transparent);margin: calc(var(--spacing-base) * 2) 0;}ul,ol{margin-bottom: var(--spacing-base);padding-left: 1.5rem;}li{margin-bottom: calc(var(--spacing-base) * 0.5);}table{width: 100%;border-collapse: separate;border-spacing: 0;margin-bottom: var(--spacing-base);border-radius: var(--border-radius);overflow: hidden;box-shadow: var(--shadow);}th,td{padding: calc(var(--spacing-base) * 0.75);border-bottom: 1px solid var(--border-color);text-align: left;}thead{background: var(--gradient-secondary);}th{font-weight: var(--font-weight-bold);color: white;text-transform: uppercase;font-size: 0.875rem;letter-spacing: 0.05em;}tr:last-child td{border-bottom: none;}tr:hover td{background-color: rgba(0,0,0,0.02);}:root[color-scheme="dark"] tr:hover td{background-color: rgba(255,255,255,0.03);}form{background-color: var(--card-bg);padding: var(--spacing-base);border-radius: var(--border-radius-lg);box-shadow: var(--shadow-md);margin-bottom: var(--spacing-base);border: 1px solid var(--border-color);}form > div{margin-bottom: var(--spacing-base);}input,select,textarea,button{font-family: inherit;font-size: inherit;line-height: inherit;}input[type="text"],input[type="email"],input[type="password"],input[type="number"],input[type="search"],input[type="tel"],input[type="url"],input[type="date"],input[type="datetime-local"],input[type="month"],input[type="week"],input[type="time"],input[type="color"],input[type="file"],input[type="range"],input[type="checkbox"],input[type="radio"],select,textarea{display: block;width: 100%;margin-bottom: var(--spacing-base);padding: calc(var(--spacing-base) * 0.75);border: 1px solid var(--border-color);border-radius: var(--border-radius-md);background-color: var(--body-bg);color: var(--body-color);transition: var(--transition-base);box-shadow: var(--shadow-sm);}input[type="checkbox"],input[type="radio"]{width: auto;margin-bottom: 0;display: inline-block;margin-right: 0.5rem;}input[type="color"]{padding: 0;height: 40px;border-radius: unset;}input[type="range"]{padding: 0;}input[type="url"],input[type="email"],input[type="password"],input[type="tel"],input[type="search"]{padding-left: 2.5rem;background-repeat: no-repeat;background-position: 0.75rem center;background-size: 1rem;position: relative;}input[type="url"]{background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23989fab' viewBox='0 0 16 16'%3E%3Cpath d='M4.715 6.542 3.343 7.914a3 3 0 1 0 4.243 4.243l1.828-1.829A3 3 0 0 0 8.586 5.5L8 6.086a1.002 1.002 0 0 0-.154.199 2 2 0 0 1 .861 3.337L6.88 11.45a2 2 0 1 1-2.83-2.83l.793-.792a4.018 4.018 0 0 1-.128-1.287z'/%3E%3Cpath d='M6.586 4.672A3 3 0 0 0 7.414 9.5l.775-.776a2 2 0 0 1-.896-3.346L9.12 3.55a2 2 0 1 1 2.83 2.83l-.793.792c.112.42.155.855.128 1.287l1.372-1.372a3 3 0 1 0-4.243-4.243L6.586 4.672z'/%3E%3C/svg%3E");}input[type="email"]{background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23989fab' viewBox='0 0 16 16'%3E%3Cpath d='M0 4a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V4Zm2-1a1 1 0 0 0-1 1v.217l7 4.2 7-4.2V4a1 1 0 0 0-1-1H2Zm13 2.383-4.708 2.825L15 11.105V5.383Zm-.034 6.876-5.64-3.471L8 9.583l-1.326-.795-5.64 3.47A1 1 0 0 0 2 13h12a1 1 0 0 0 .966-.741ZM1 11.105l4.708-2.897L1 5.383v5.722Z'/%3E%3C/svg%3E");}input[type="password"]{background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23989fab' viewBox='0 0 16 16'%3E%3Cpath transform='rotate(-45 8 8)' d='M3.5 11.5a3.5 3.5 0 1 1 3.163-5H14L15.5 8 14 9.5l-1-1-1 1-1-1-1 1-1-1-1 1H6.663a3.5 3.5 0 0 1-3.163 2zM2.5 9a1 1 0 1 0 0-2 1 1 0 0 0 0 2z'/%3E%3C/svg%3E");}input[type="tel"]{background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' stroke='%23989fab' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M3 5.5C3 14.06 9.94 21 18.5 21c.386 0 .77-.014 1.148-.042.435-.032.653-.048.851-.162a1.06 1.06 0 0 0 .42-.432c.11-.2.121-.418.145-.853l.17-3.072a1.517 1.517 0 0 0-.828-1.536l-2.546-1.273a1.517 1.517 0 0 0-1.784.307l-.89 1.04c-.34.398-.873.54-1.342.353a10.49 10.49 0 0 1-3.27-2.27 10.49 10.49 0 0 1-2.27-3.27 1.25 1.25 0 0 1 .353-1.342l1.04-.89a1.517 1.517 0 0 0 .307-1.784L8.68 3.67A1.517 1.517 0 0 0 7.144 2.84l-3.072.17c-.435.024-.653.036-.853.145a1.06 1.06 0 0 0-.432.42c-.114.198-.13.416-.162.851C3.014 4.73 3 5.114 3 5.5Z'/%3E%3C/svg%3E");}input[type="search"]{background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='%23989fab' viewBox='0 0 16 16'%3E%3Cpath d='M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z'%3E%3C/path%3E%3C/svg%3E");}input[type="url"],input[type="email"],input[type="password"],input[type="tel"],input[type="search"]{color: var(--body-color);}input[type="url"]::placeholder,input[type="email"]::placeholder,input[type="password"]::placeholder,input[type="tel"]::placeholder,input[type="search"]::placeholder{color: var(--body-color);opacity: 0.7;}input[type="search"]{border-radius: var(--border-radius-full);}select{appearance: none;padding-right: 2.5rem;background-image: url("data:image/svg+xml;utf8,");background-repeat: no-repeat;background-position: right 1rem center;background-size: 2rem;}:root[color-scheme="dark"] select{background-image: url("data:image/svg+xml;utf8,");}input:focus,select:focus,textarea:focus{outline: none;border-color: var(--border-color);box-shadow: 0 0 0px 3px rgba(102,118,201,0.54);}textarea{min-height: 9rem;resize: vertical;}label{display: block;margin-bottom: calc(var(--spacing-base) * 0.5);font-weight: var(--font-weight-medium);}button,input[type="button"],input[type="reset"],input[type="submit"]{vertical-align: middle;min-height: 3.1rem;min-width: 6.5rem;display: inline-block;padding: calc(var(--spacing-base) * 0.75) var(--spacing-base);margin: 0.125rem 0.125rem 0.125rem 0;background: var(--gradient-primary);color: white;border: none;border-radius: var(--border-radius-md);cursor: pointer;font-weight: var(--font-weight-medium);text-align: center;transition: var(--transition-base);position: relative;overflow: hidden;}button:empty::after{content: "";position: absolute;top: calc(50% - 12px);left: calc(50% - 12px);width: 16px;height: 16px;border: 3px solid rgb(255,255,255);border-top: 3px solid transparent;border-bottom: 3px solid transparent;border-radius: 50%;animation: spin 1s linear infinite;}@keyframes spin{0%{transform: rotate(0deg);}100%{transform: rotate(360deg);}}button:after,input[type="button"]:after,input[type="reset"]:after,input[type="submit"]:after{content: '';position: absolute;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(255,255,255,0);transition: var(--transition-base);}button:hover:after,input[type="button"]:hover:after,input[type="reset"]:hover:after,input[type="submit"]:hover:after{background-color: rgba(255,255,255,0.1);}button:hover,input[type="button"]:hover,input[type="reset"]:hover,input[type="submit"]:hover{box-shadow: var(--shadow-md);}button:active,input[type="button"]:active,input[type="reset"]:active,input[type="submit"]:active{transform: translateY(2px);box-shadow: var(--shadow-sm);filter: saturate(0.9) brightness(1.1);}button:disabled,input[type="button"]:disabled,input[type="reset"]:disabled,input[type="submit"]:disabled{background: var(--gradient-secondary);cursor: not-allowed;opacity: 0.7;transform: none;}button.success,input[type="button"].success,input[type="submit"].success{background: var(--gradient-success);}button.danger,input[type="button"].danger,input[type="submit"].danger{background: var(--gradient-danger);}button.warning,input[type="button"].warning,input[type="submit"].warning{background: var(--gradient-warning);}button.info,input[type="button"].info,input[type="submit"].info{background: var(--gradient-info);}button.outline,input[type="button"].outline,input[type="submit"].outline{background: transparent;border: 1px solid var(--primary-invert);color: var(--primary-invert);}button.outline:hover,input[type="button"].outline:hover,input[type="submit"].outline:hover{background-color: var(--primary);color: white;}img{max-width: 100%;height: auto;border-radius: var(--border-radius-md);transition: var(--transition-base);box-shadow: var(--shadow);}img:hover{transform: scale(1.01);box-shadow: var(--shadow-md);}figure{text-align: center;margin-bottom: var(--spacing-base);}figcaption{font-size: 0.875rem;color: var(--secondary);text-align: center;margin-top: calc(var(--spacing-base) * 0.5);font-style: italic;}details summary{cursor: pointer;position: relative;padding-bottom: calc(var(--spacing-base) * 0.5);}details summary:after{content: '';position: absolute;left: 0;bottom: 0;width: 100%;height: 1px;background: linear-gradient(to right,var(--border-color),transparent);}details > *:not(summary){cursor: auto;margin-top: calc(var(--spacing-base) * 0.5);}article,section,aside{margin-bottom: calc(var(--spacing-base) * 2);padding: var(--spacing-base);background-color: var(--card-bg);border-radius: var(--border-radius-lg);box-shadow: var(--shadow);transition: var(--transition-base);border: 1px solid var(--border-color);}:focus-visible{outline: 2px solid var(--primary);outline-offset: 2px;}.glass{background: rgba(255,255,255,0.5);backdrop-filter: blur(10px);border: 1px solid rgba(255,255,255,0.2);color: var(--body-color);box-shadow: 0 4px 6px rgba(0,0,0,0.1);}:root[color-scheme="dark"] .glass{background: rgba(0,0,0,0.3);border: 1px solid rgba(255,255,255,0.1);}:root:not([color-scheme="dark"]) .glass{text-shadow: 0 1px 1px rgba(0,0,0,0.1);}@media (max-width: 768px){html{font-size: 14px;}body{padding: calc(var(--spacing-base) * 0.75);}table{width: 100%;display: block;overflow-x: auto;}h1{font-size: 2.25rem;}h2{font-size: 1.75rem;}}@media print{body{background-color: #fff;color: #000;}a{text-decoration: underline;color: #000;}a[href]:after{content: " (" attr(href) ")";}pre,blockquote{border: 1px solid #999;page-break-inside: avoid;}thead{display: table-header-group;}tr,img{page-break-inside: avoid;}p,h2,h3{orphans: 3;widows: 3;}h2,h3{page-break-after: avoid;}h1,h2:after,button,input[type="button"],input[type="reset"],input[type="submit"]{background: none;text-fill-color: #000;box-shadow: none;}article,section,aside,img,pre,blockquote,table{box-shadow: none;}}body,a,button,input,select,textarea,th,td,code,pre,blockquote,article,section,aside{transition: background-color 0.3s ease,color 0.3s ease,border-color 0.3s ease,box-shadow 0.3s ease;}@keyframes colorSchemeTransition{0%{opacity: 0;}100%{opacity: 1;}}progress{appearance: none;width: 100%;height: 1rem;border: none;border-radius: var(--border-radius-full);background-color: var(--border-color);overflow: hidden;}progress::-webkit-progress-bar{background-color: var(--border-color);}progress::-webkit-progress-value{background-color: var(--progress-color);transition: width 0.3s ease;}progress::-moz-progress-bar{background-color: var(--progress-color);transition: width 0.3s ease;}@keyframes moveStripe{0%{background-position: 200% 0;}100%{background-position: 0 0;}}progress:indeterminate{background-image: linear-gradient( to right,var(--border-color) 0%,var(--border-color) 25%,var(--progress-color) 25%,var(--progress-color) 75%,var(--border-color) 75%,var(--border-color) 100% );background-size: 200% 100%;animation: moveStripe 2s linear infinite;}progress:indeterminate::-moz-progress-bar{background-image: linear-gradient( to right,var(--border-color) 0%,var(--border-color) 25%,var(--progress-color) 25%,var(--progress-color) 75%,var(--border-color) 75%,var(--border-color) 100% );background-size: 200% 100%;animation: moveStripe 2s linear infinite;}progress:indeterminate::-webkit-progress-bar{background-image: linear-gradient( to right,var(--border-color) 0%,var(--border-color) 25%,var(--progress-color) 25%,var(--progress-color) 75%,var(--border-color) 75%,var(--border-color) 100% );background-size: 200% 100%;animation: moveStripe 2s linear infinite;} \ No newline at end of file diff --git a/ui/static/css/style.css b/ui/static/css/style.css index 0beca8e..0b1a576 100644 --- a/ui/static/css/style.css +++ b/ui/static/css/style.css @@ -1,12 +1,12 @@ -html { +/* html { background: lightgray; -} +} */ body { max-width: 1024px; margin: 1rem auto; padding: 1rem; - background: white; + /* background: white; */ font-size: 1.2rem; line-height: 1.5; font-family: Arial, Helvetica, sans-serif; @@ -41,8 +41,8 @@ nav button { background: none; font-family: unset; font-size: unset; - color: blue; - text-decoration: underline; + /* color: blue; */ + /* text-decoration: underline; */ cursor: pointer; } @@ -75,5 +75,5 @@ footer { } a { - color: blue; + /* color: blue; */ } diff --git a/ui/views/common.templ b/ui/views/common.templ index 7d5d911..13b5dd4 100644 --- a/ui/views/common.templ +++ b/ui/views/common.templ @@ -2,6 +2,8 @@ package views import "git.32bit.cafe/32bitcafe/guestbook/internal/models" import "strconv" +import "fmt" +import "strings" type CommonData struct { CurrentYear int @@ -21,6 +23,13 @@ func slugToShortId(slug string) uint64 { return id } +func externalUrl(url string) string { + if !strings.HasPrefix(url, "http") { + return "http://" + url + } + return url +} + templ commonHeader() {

webweav.ing

@@ -28,6 +37,7 @@ templ commonHeader() { } templ topNav(data CommonData) { + {{ hxHeaders := fmt.Sprintf("{\"X-CSRF-Token\": \"%s\"}", data.CSRFToken) }}