From 1eb036d196d8d2b1066d3e5c8bd04b282c48dcbc Mon Sep 17 00:00:00 2001 From: 4cuck <40539855+4cuck@users.noreply.github.com> Date: Fri, 17 Apr 2026 10:26:48 -0700 Subject: [PATCH] ui: redesign from scratch --- public/css/general.css | 56 ++- public/css/inputs.css | 539 ++++++++++++++++++++++------- public/css/navbar.css | 84 ++++- public/css/profile/base.css | 171 ++++++--- public/css/profile/card.css | 231 ++++++++----- public/css/profile/photo-rail.css | 229 ++++++++---- public/css/search.css | 286 ++++++++------- public/css/style.css | 514 ++++++++++++++------------- public/css/themes/teapot_light.css | 95 +++++ public/css/timeline.css | 271 ++++++++++----- public/css/tweet/base.css | 15 +- public/css/tweet/quote.css | 2 +- public/css/twemoji.css | 3 - src/api/client.rs | 8 +- src/main.rs | 4 +- src/routes/status.rs | 8 +- src/types/prefs.rs | 2 +- src/types/tweet.rs | 58 ++-- src/views/layout.rs | 22 +- src/views/preferences.rs | 127 ++++--- src/views/profile.rs | 84 +++-- src/views/renderutils.rs | 6 +- 22 files changed, 1879 insertions(+), 936 deletions(-) create mode 100644 public/css/themes/teapot_light.css diff --git a/public/css/general.css b/public/css/general.css index 5000900..b3a5837 100644 --- a/public/css/general.css +++ b/public/css/general.css @@ -16,46 +16,64 @@ } .error-panel { - padding: 12px; - border-radius: 4px; + padding: 16px; + border-radius: var(--shape-lg); display: flex; - background: var(--error_red); - box-shadow: 0 0 15px var(--shadow_dark); + background: var(--tp-error-container); + color: var(--tp-on-error-container); + box-shadow: var(--elevation-1); margin: auto; margin-top: -50px; text-align: center; + font-weight: 500; } .search-bar > form { - padding: 12px; - border-radius: 4px; + padding: 12px 16px; + border-radius: var(--shape-md); display: flex; - background: var(--darkest_grey); - box-shadow: 0 0 15px var(--shadow_dark); + background: var(--tp-surface-container-highest); + border: none; + box-shadow: none; margin: auto; margin-top: -50px; + transition: background 0.15s ease; & button { - background: var(--bg_elements); - color: var(--fg_color); + background: var(--tp-primary); + color: var(--tp-on-primary); border: 0; - border-radius: 3px; + border-radius: var(--shape-md); cursor: pointer; - font-weight: bold; - width: 30px; - height: 30px; - padding: 0px 5px 1px 8px; + font-weight: 500; + width: 36px; + height: 36px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.15s ease; + /*box-shadow: var(--elevation-1);*/ + + &:hover { + background: var(--tp-on-primary-container); + /* box-shadow: var(--elevation-2); */ + } } & input { font-size: 16px; width: 100%; - background: var(--bg_elements); - color: var(--fg_color); + background: var(--tp-surface-container-highest) !important; + color: var(--tp-on-surface); border: 0; - border-radius: 4px; - padding: 4px; + border-radius: 10px; + padding: 4px 12px; margin-right: 8px; height: unset; + box-shadow: none !important; + + &::placeholder { + color: var(--tp-on-surface-variant); + } } } diff --git a/public/css/inputs.css b/public/css/inputs.css index c771f99..49f6a29 100644 --- a/public/css/inputs.css +++ b/public/css/inputs.css @@ -1,64 +1,86 @@ button { - background-color: var(--bg_elements); - color: var(--fg_color); - border: 1px solid var(--accent_border); - padding: 3px 6px; + background-color: var(--tp-primary-container); + color: var(--tp-on-primary-container); + border: 0; + padding: 8px 16px; font-size: 14px; + font-weight: 500; cursor: pointer; - float: right; +/* border-radius: var(--shape-md); */ + transition: background 0.15s ease; +} - &:hover { - border-color: var(--accent); - } +button:hover { + background: var(--tp-primary); + color: var(--tp-on-primary); +} - &:active { - border-color: var(--accent_light); - } +button:active { + opacity: 0.85; +} + +.translate-btn, +.translate-btn:hover, +.translate-btn:active { + background: none; + border: none; + border-radius: 0; + box-shadow: none; + padding: 0; + font-size: 0.78em; + color: var(--fg_faded); + transform: none; + transition: none; } input[type="text"], input[type="date"], input[type="number"], select { - background-color: var(--bg_elements); - padding: 1px 4px; - color: var(--fg_color); - border: 1px solid var(--accent_border); - border-radius: 0; + background-color: var(--tp-surface-container-highest); + padding: 10px 14px; + color: var(--tp-on-surface); + border: 1px solid var(--tp-outline); + border-radius: var(--shape-md); font-size: 14px; + transition: all 0.15s ease; + width: 100%; + box-sizing: border-box; +} - &:hover { - border-color: var(--accent); - } +input[type="text"]:hover, +input[type="date"]:hover, +input[type="number"]:hover, +select:hover { + border-color: var(--tp-on-surface-variant); +} - &:active { - border-color: var(--accent_light); - } +input[type="text"]:focus, +input[type="date"]:focus, +input[type="number"]:focus, +select:focus { + border-color: var(--tp-primary); + background: var(--tp-surface-container-highest); + box-shadow: 0 0 0 3px var(--tp-primary-container); } input[type="number"] { -moz-appearance: textfield; } -input[type="text"], -input[type="number"] { - height: 16px; -} - select { - height: 20px; - padding: 0 2px; - line-height: 1; + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 12px center; + padding-right: 32px; } input[type="date"]::-webkit-inner-spin-button { display: none; } -input[type="number"] { - -moz-appearance: textfield; -} - input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { display: none; @@ -79,139 +101,422 @@ input::-webkit-calendar-picker-indicator { input::-webkit-datetime-edit-day-field:focus, input::-webkit-datetime-edit-month-field:focus, input::-webkit-datetime-edit-year-field:focus { - background-color: var(--accent); - color: var(--fg_color); + background-color: var(--tp-primary); + color: var(--tp-on-primary); outline: none; } -.date-range { - & .date-input { - display: inline-block; - position: relative; - } +.date-range .date-input { + display: inline-block; + position: relative; +} - & .icon-container { - pointer-events: none; - position: absolute; - top: 2px; - right: 5px; - } +.date-range .icon-container { + pointer-events: none; + position: absolute; + top: 2px; + visibility: hidden; + right: 5px; +} - & .search-title { - margin: 0 2px; - } +.date-range .search-title { + margin: 0 2px; } .icon-button button { - color: var(--accent); + color: var(--tp-primary); text-decoration: none; background: none; border: none; float: none; padding: unset; padding-left: 4px; +} - &:hover { - color: var(--accent_light); - } +.icon-button button:hover { + color: var(--tp-on-primary-container); } .checkbox { position: absolute; - top: 1px; + top: 50%; right: 0; - height: 17px; - width: 17px; - background-color: var(--bg_elements); - border: 1px solid var(--accent_border); + transform: translateY(-50%); + height: 20px; + width: 20px; + background-color: var(--tp-surface-container-highest); + border: 2px solid var(--tp-outline); + border-radius: var(--shape-xs); + transition: all 0.15s ease; +} - &:after { - content: ""; - position: absolute; - display: none; - } +.checkbox:after { + content: ""; + position: absolute; + display: none; } .checkbox-container { display: block; position: relative; - margin-bottom: 5px; + margin-bottom: 8px; cursor: pointer; user-select: none; - padding-right: 22px; + /* padding: 12px 40px 12px 0; */ + border-radius: var(--shape-md); +} - & input { - position: absolute; - opacity: 0; - cursor: pointer; - height: 0; - width: 0; - &:checked ~ .checkbox:after { - display: block; - } - } +.checkbox-container input { + position: absolute; + opacity: 0; + cursor: pointer; + height: 0; + width: 0; +} - &:hover input ~ .checkbox { - border-color: var(--accent); - } +.checkbox-container input:checked ~ .checkbox { + background-color: var(--tp-primary); + border-color: var(--tp-primary); +} - &:active input ~ .checkbox { - border-color: var(--accent_light); - } +.checkbox-container input:checked ~ .checkbox:after { + display: block; +} - & .checkbox:after { - left: 2px; - bottom: 0; - font-size: 13px; - font-family: fontello; - content: "\e811"; - } +.checkbox-container input:focus ~ .checkbox { + box-shadow: 0 0 0 3px var(--tp-primary-container); +} + +.checkbox-container:hover input ~ .checkbox { + border-color: var(--tp-on-surface-variant); +} + +.checkbox-container:active input ~ .checkbox { + border-color: var(--tp-primary); +} + +.checkbox-container .checkbox:after { + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + font-size: 12px; + font-family: fontello; + content: "\e811"; + color: var(--tp-on-primary); } .pref-group { display: inline; } -.preferences { - & button { - margin: 6px 0 3px 0; +.preferences-panel { + max-width: 600px; + width: 100%; + margin: 0 auto; + margin-top: 10px; + background-color: var(--tp-surface-container-low); + border-radius: var(--shape-xl); + padding: 0; + overflow: hidden; +} + +.preferences-header { + padding: 24px 24px 16px; + color: var(--tp-on-primary-container); + margin-bottom: 0; +} + +.preferences-header h2 { + font-size: 24px; + font-weight: 600; + margin: 0 0 4px 0; + color: var(--tp-on-primary-container); +} + +.preferences-header p { + margin: 0; + font-size: 14px; + opacity: 0.9; +} + +.preferences-close { + position: absolute; + top: 16px; + right: 16px; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--shape-sm); + color: var(--tp-on-primary-container); + transition: background 0.15s ease; + text-decoration: none; +} + +.preferences-close:hover { + background-color: rgba(0, 0, 0, 0.1); + text-decoration: none; +} + +.preferences-close .icon-close:before { + font-family: fontello; + content: "\e80a"; + font-size: 18px; +} + +.preferences-form { + padding: 16px 24px; +} + +.preferences-form fieldset { + border: 0; + padding: 0; + margin: 0; +} + +.pref-section { + margin-bottom: 24px; +} + +.pref-section legend { + width: 100%; + padding: 0 0 12px 0; + border: 0; + font-size: 14px; + font-weight: 600; + color: var(--tp-primary); + margin-bottom: 12px; + border-bottom: 1px solid var(--tp-outline-variant); +} + +.pref-grid { + display: flex; + flex-direction: column; + gap: 4px; +} + +.pref-grid .pref-group { + /* background: var(--tp-surface-container); */ + border-radius: var(--shape-md); + margin: 0; + transition: background-color 0.15s ease; +} + +.pref-grid .pref-group:hover { + background: var(--tp-surface-container-high); +} + +.pref-input { + display: flex; + flex-direction: column; + gap: 8px; + padding: 12px 0; +} + +.pref-input label { + padding-right: 0; + font-weight: 500; + color: var(--tp-on-surface); +} + +.prefs-code-wrapper { + position: relative; + margin: 12px 0; +} + +.prefs-code-wrapper .prefs-code { + background: var(--tp-surface-container-highest); + border-radius: var(--shape-md); + padding: 16px 48px 16px 16px; + margin: 0; + font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace; + font-size: 13px; + color: var(--tp-on-surface); + word-break: break-all; + overflow-x: auto; +} + +.prefs-code-wrapper .prefs-code code { + font-family: inherit; +} + +.copy-prefs-btn { + position: absolute; + top: 50%; + right: 8px; + transform: translateY(-50%); + width: 36px; + height: 36px; + border-radius: var(--shape-md); + background: var(--tp-surface-container); + border: 0; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.15s ease; + padding: 0; +} + +.copy-prefs-btn:hover { + background: var(--tp-primary-container); +} + +.copy-prefs-btn .icon-copy:before { + font-family: fontello; + content: "\e806"; + color: var(--tp-on-surface-variant); +} + +.preferences-actions { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 16px 24px; + border-top: 1px solid var(--tp-outline-variant); + margin-top: 24px; +} + +.preferences-actions .pref-submit { + background: var(--tp-primary); + color: var(--tp-on-primary); + font-weight: 500; + padding: 12px 24px; + border-radius: var(--shape-md); +} + +.preferences-actions .pref-submit:hover { + background: var(--tp-on-primary-container); +} + +.pref-reset-form { + padding: 0; + margin: 0; +} + +.pref-reset-form button, +.preferences-actions .pref-reset { + background: transparent; + color: var(--tp-error); + border: 1px solid var(--tp-error); + box-shadow: none; +} + +.pref-reset-form button:hover, +.preferences-actions .pref-reset:hover { + background: var(--tp-error-container); + color: var(--tp-on-error-container); +} + +.preferences-footer-note { + margin: 0 24px 24px; + padding: 12px 16px; + background: var(--tp-surface-container-high); + border-radius: var(--shape-md); + font-size: 13px; + color: var(--tp-on-surface-variant); + text-align: center; + border: 0; +} + +.bookmark-note { + font-size: 14px; + color: var(--tp-on-surface-variant); + margin: 8px 0; + line-height: 1.5; +} + +.preferences button { + /* margin: 6px 0 3px 0; */ +} + +.preferences label { + padding-right: 150px; +} + +.preferences select { + position: absolute; + top: 0; + right: 0; + display: block; + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; +} + +.preferences input[type="text"], +.preferences input[type="number"] { + position: absolute; + right: 0; + max-width: 140px; +} + +.preferences .pref-group { + display: block; +} + +.preferences .pref-input { + position: relative; + margin-bottom: 6px; +} + +/* .preferences .pref-reset { */ +/* float: left; */ +/* } */ + +/* Reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + button, + .checkbox, + .checkbox-container, + .preferences-close, + .pref-section, + .copy-prefs-btn, + input[type="text"], + input[type="number"], + select { + transition: none !important; + animation: none !important; } - & label { - padding-right: 150px; - box-sizing: border-box; - max-width: 100%; + .preferences-panel { + animation: none; } +} - & select { - position: absolute; - top: 0; - right: 0; - display: block; - padding: 0 6px; - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; +/* Mobile responsive */ +@media (max-width: 600px) { + .preferences-panel { + max-width: 95vw; + border-radius: var(--shape-lg); + margin-top: 8px; } - & input[type="text"], - & input[type="number"] { - position: absolute; - right: 0; - max-width: 140px; + .preferences-header { + padding: 20px 16px 12px; } - & .pref-group { - display: block; + .preferences-header h2 { + font-size: 20px; } - & .pref-input { - position: relative; - margin-bottom: 6px; + .preferences-form { + padding: 12px 16px; } - & .pref-reset { - float: left; + .pref-reset-form { + padding: 0 16px 16px; + } + + .preferences-footer-note { + margin: 0 16px 16px; + } + + .nav-item, + .nav-item .icon-container { + font-size: 16px; } } diff --git a/public/css/navbar.css b/public/css/navbar.css index c980b27..0b1fc62 100644 --- a/public/css/navbar.css +++ b/public/css/navbar.css @@ -1,14 +1,30 @@ +.material-symbols-outlined { + font-family: 'Material Symbols Outlined'; + font-weight: 300; + font-style: normal; + font-size: 18px !important; + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24; + user-select: none; +} + nav { display: flex; align-items: center; position: fixed; - background-color: var(--bg_overlays); - box-shadow: 0 0 4px var(--shadow); + background-color: var(--bg_color); padding: 0; width: 100%; - height: 50px; + height: 56px; z-index: 1000; font-size: 16px; + border-bottom: 1px solid var(--tp-outline-variant); & a, & .icon-button button { @@ -19,35 +35,37 @@ nav { .inner-nav { margin: auto; box-sizing: border-box; - padding: 0 10px; + padding: 0 16px; display: flex; align-items: center; - flex-basis: 920px; - height: 50px; + flex-basis: 600px; + height: 56px; } .site-name { - font-size: 15px; - font-weight: 600; + font-size: 16px; + font-weight: 500; line-height: 1; + color: var(--tp-primary); &:hover { - color: var(--accent_light); - text-decoration: unset; + color: var(--tp-on-primary-container); + text-decoration: none; } } .site-logo { display: block; - width: 35px; - height: 35px; + width: 32px; + height: 32px; + border-radius: var(--shape-md); } .nav-item { display: flex; flex: 1; - line-height: 50px; - height: 50px; + line-height: 56px; + height: 56px; overflow: hidden; flex-wrap: wrap; align-items: center; @@ -57,9 +75,19 @@ nav { justify-content: flex-end; } - &.right a:hover { - color: var(--accent_light); - text-decoration: unset; + &.right a { + color: var(--tp-on-surface-variant); + font-weight: 500; + padding: 0; + border-radius: var(--shape-sm); + margin: 0; + transition: color 0.15s ease; + + &:hover { + color: var(--tp-primary); + background-color: var(--bg_hover); + text-decoration: none; + } } } @@ -71,7 +99,7 @@ nav { fill: var(--fg_nav); &:hover { - fill: var(--accent_light); + fill: var(--tp-on-primary-container); } } @@ -81,5 +109,23 @@ nav { .icon-cog { font-size: 15px; - padding-left: 0 !important; + /* padding-left: 0 !important; */ +} + +.nav-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: var(--shape-sm); + color: var(--tp-on-surface-variant); + transition: color 0.15s ease; + text-decoration: none; +} + +.nav-icon:hover { + color: var(--tp-primary); + background-color: var(--bg_hover); + text-decoration: none; } diff --git a/public/css/profile/base.css b/public/css/profile/base.css index 0216f8f..83dd11c 100644 --- a/public/css/profile/base.css +++ b/public/css/profile/base.css @@ -2,72 +2,140 @@ @import "photo-rail.css"; .profile-tabs { - max-width: 900px; + max-width: 1200px; margin: 0 auto; - float: none; - border-radius: 0; - position: relative; - width: auto; - - & .timeline-container { - float: right; - width: 68% !important; - max-width: unset; - } + display: flex; + flex-direction: row; + gap: 12px; + padding: 8px; + align-items: flex-start; } +/* Left sidebar containing profile card and photo rail */ +.profile-sidebar { + flex: 0 0 320px; + display: flex; + flex-direction: column; + gap: 16px; +} + + .profile-banner { - margin-bottom: 4px; - background-color: var(--bg_panel); + width: 100%; + background-color: var(--tp-surface-container); + overflow: hidden; +} - & a { - display: block; - position: relative; - padding: 33.34% 0 0 0; - } +.profile-banner a { + display: block; + position: relative; + padding: 33.34% 0 0 0; +} - & img { - max-width: 100%; - position: absolute; - top: 0; - } +.profile-banner img { + max-width: 100%; + position: absolute; + top: 0; +} + +.profile-header { + position: relative; } .profile-tab { - padding: 0 4px 0 0; + flex: 0 0 400px; box-sizing: border-box; - display: inline-block; + padding: 0; font-size: 14px; text-align: left; - vertical-align: top; - max-width: 32%; - top: 50px; +} + +.profile-tab.sticky { + position: sticky; + top: 72px; + max-height: calc(100vh - 88px); + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: var(--tp-outline-variant) transparent; +} + +.profile-tab.sticky::-webkit-scrollbar { + width: 6px; +} + +.profile-tab.sticky::-webkit-scrollbar-track { + background: transparent; +} + +.profile-tab.sticky::-webkit-scrollbar-thumb { + background: var(--tp-outline-variant); + border-radius: 3px; +} + +/* Timeline container - main content area */ +.timeline-container { + flex: 1; + min-width: 0; + max-width: 600px; } .profile-result { min-height: 54px; +} - & .username { - margin: 0 !important; +.profile-result .username { + margin: 0 !important; +} + +.profile-result .tweet-header { + margin-bottom: unset; +} + +/* Responsive layout */ +@media (max-width: 900px) { + .profile-tabs { + flex-direction: column; + padding: 8px; + gap: 16px; } - & .tweet-header { - margin-bottom: unset; + .profile-sidebar, + .profile-tab { + flex: 1; + width: 100%; + max-width: unset; + } + + .profile-tab.sticky { + position: relative; + top: unset; + max-height: unset; + overflow-y: visible; + } + + .timeline-container { + max-width: unset; + width: 100%; + } + + .profile-banner { + margin: 0; } } @media (max-width: 700px) { .profile-tabs { - width: 100vw; + width: 100%; max-width: 600px; + padding: 0 8px; + } - & .timeline-container { - width: 100% !important; + .timeline-container { + width: 100%; + } - & .tab-item wide { - flex-grow: 1.4; - } - } + .timeline-container .tab-item wide { + flex-grow: 1.4; } .profile-tab { @@ -76,10 +144,27 @@ position: initial !important; padding: 0; } -} -@media (min-height: 900px) { - .profile-tab.sticky { - position: sticky; + .profile-banner { + border-radius: 0; + /* margin-left: -8px; */ + /* margin-right: -8px; */ } } + +@media (min-height: 900px) and (min-width: 900px) { + .profile-tab.sticky { + position: sticky; + border-radius: 10px; + } +} + +/* Reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + .profile-tabs, + .profile-sidebar > *, + .timeline-container { + animation: none; + } + +} diff --git a/public/css/profile/card.css b/public/css/profile/card.css index 8aa310e..e0950be 100644 --- a/public/css/profile/card.css +++ b/public/css/profile/card.css @@ -1,134 +1,211 @@ .profile-card { - flex-wrap: wrap; - background: var(--bg_panel); - padding: 12px; + background: var(--tp-surface-container); + padding: 10px; + padding-top: 62px; display: flex; + flex-direction: column; + position: relative; + /* border-radius: var(--shape-lg); */ + /* transition: box-shadow 0.2s ease, transform 0.2s ease; */ } -.profile-card-info { - overflow: hidden; + +/* .profile-card:hover { + box-shadow: var(--elevation-2); +} +*/ + +.profile-card-identity { overflow-wrap: break-word; width: 100%; -} - -.profile-card-tabs-name { - overflow: hidden; - overflow-wrap: break-word; - max-width: 100%; + margin-bottom: 8px; } .profile-card-username { overflow: hidden; overflow-wrap: break-word; - color: var(--fg_color); - font-size: 14px; + color: var(--tp-accent-blue); + font-size: 15px; + /* font-weight: 400; */ display: block; + /* margin-top: 4px; */ + transition: color 0.15s ease; +} + +.profile-card-username:hover { + color: var(--tp-primary); } .profile-card-fullname { overflow: hidden; overflow-wrap: break-word; - color: var(--fg_color); - font-size: 16px; - font-weight: bold; + color: var(--tp-on-surface); + font-size: 20px; + font-weight: 500; + letter-spacing: -0.1px; + font-family: "Readex Pro", sans-serif; text-shadow: none; max-width: 100%; + transition: color 0.15s ease; +} + +.profile-card-fullname:hover { + color: var(--tp-primary); + text-decoration: none; } .profile-card-avatar { - display: inline-block; - position: relative; - width: 100%; - margin-right: 4px; - margin-bottom: 6px; + position: absolute; + top: -50px; + left: 16px; + width: 100px; + height: 100px; + display: block; + z-index: 1; +} - &:after { - content: ''; - display: block; - margin-top: 100%; - } - - & img { - box-sizing: border-box; - position: absolute; - width: 100%; - height: 100%; - border: 4px solid var(--darker_grey); - background: var(--bg_panel); - } +.profile-card-avatar img { + box-sizing: border-box; + position: static; + width: 100px; + height: 100px; + display: block; + background: var(--tp-surface-container); + border-radius: 50%; + border: 4px solid var(--tp-surface-container) } .profile-card-extra { display: contents; flex: 100%; - margin-top: 7px; + margin-top: 12px; +} - & .profile-bio { - overflow: hidden; - overflow-wrap: break-word; - width: 100%; - margin: 4px -6px 6px 0; - white-space: pre-wrap; +.profile-card-extra .profile-bio { + overflow: hidden; + overflow-wrap: break-word; + width: 100%; + margin: 8px 0 12px 0; + white-space: pre-wrap; + font-size: 14px; + line-height: 1.5; + color: var(--tp-on-surface); +} - & p { - margin: 0; - } - } +.profile-card-extra .profile-bio p { + margin: 0; +} - & .profile-joindate, - & .profile-location, - & .profile-website { - color: var(--fg_faded); - margin: 1px 0; - width: 100%; - } +.profile-card-extra .profile-joindate, +.profile-card-extra .profile-location, +.profile-card-extra .profile-website { + color: var(--tp-on-surface-variant); + margin: 2px 0; + width: 100%; + font-size: 14px; + display: flex; + align-items: center; + gap: 6px; +} + +.profile-card-extra .profile-joindate::before, +.profile-card-extra .profile-location::before, +.profile-card-extra .profile-website::before { + font-family: fontello; + opacity: 0.7; +} + +.profile-card-extra .profile-joindate a, +.profile-card-extra .profile-location a, +.profile-card-extra .profile-website a { + color: var(--tp-primary); + transition: color 0.15s ease; +} + +.profile-card-extra .profile-joindate a:hover, +.profile-card-extra .profile-location a:hover, +.profile-card-extra .profile-website a:hover { + color: var(--tp-on-primary-container); } .profile-card-extra-links { - margin-top: 8px; + margin-top: 10px; font-size: 14px; width: 100%; + /* padding-top: 12px; */ } .profile-statlist { display: flex; - flex-wrap: wrap; + flex-wrap: nowrap; padding: 0; width: 100%; justify-content: space-between; - - & li { - display: table-cell; - text-align: center; - } + gap: 2px; + list-style: none; + margin: 0; } +.profile-statlist li { + /* display: flex; + flex-direction: column; + align-items: center; */ + padding: 10px; + border-radius: var(--shape-sm); + transition: background-color 0.15s ease; + flex: 1; + min-width: 60px; + cursor: pointer; +} + +/* .profile-statlist li:hover { + background-color: var(--tp-surface-container-high); +} */ + .profile-stat-header { - font-weight: bold; - color: var(--profile_stat); + font-size: 14px; + color: var(--tp-on-surface-variant); + font-weight: 400; + /* text-transform: uppercase; */ + /* letter-spacing: 0.5px; */ + margin-bottom: 4px; } .profile-stat-num { display: block; - color: var(--profile_stat); + color: var(--tp-on-surface); + font-size: 16px; + font-weight: 600; + transition: color 0.15s ease; +} + +.profile-statlist li:hover .profile-stat-num { + color: var(--tp-primary); +} + +/* Reduced motion */ +@media (prefers-reduced-motion: reduce) { + .profile-card, + .profile-card-avatar img, + .profile-statlist li { + transition: none; + } } @media (max-width: 700px) { - .profile-card-info { - display: flex; - } - - .profile-card-tabs-name { - flex-shrink: 100; - } - .profile-card-avatar { - width: 80px; - height: 80px; + width: 120px; + height: 120px; + top: -60px; + } - & img { - border-width: 2px; - width: unset; - } + .profile-card-avatar img { + width: 120px; + height: 120px; + } + + .profile-card { + padding-top: 70px; + margin: 0; } } diff --git a/public/css/profile/photo-rail.css b/public/css/profile/photo-rail.css index 879518b..3810208 100644 --- a/public/css/profile/photo-rail.css +++ b/public/css/profile/photo-rail.css @@ -1,75 +1,154 @@ -.photo-rail { - &-card { - float: left; - background: var(--bg_panel); - border-radius: 0 0 4px 4px; - width: 100%; - margin: 5px 0; - } - - &-header { - padding: 5px 12px 0; - } - - &-header-mobile { - display: none; - box-sizing: border-box; - padding: 5px 12px 0; - width: 100%; - float: unset; - color: var(--accent); - justify-content: space-between; - } - - &-grid { - display: grid; - grid-template-columns: repeat(4, 1fr); - grid-gap: 3px 3px; - padding: 5px 12px 12px; - - & a { - position: relative; - border-radius: 5px; - background-color: var(--darker_grey); - - &:before { - content: ""; - display: block; - padding-top: 100%; - } - } - - & img { - height: 100%; - width: 100%; - border-radius: 4px; - object-fit: cover; - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - } - } +.photo-rail-card { + background: var(--tp-surface-container); + border-bottom-left-radius: var(--shape-md); + border-bottom-right-radius: var(--shape-md); + width: 100%; +/* box-shadow: var(--elevation-1); */ overflow: hidden; + transition: box-shadow 0.2s ease; } -/* create-toggle(photo-rail-grid, 640px) */ +.photo-rail-card:hover { + /* box-shadow: var(--elevation-2); */ +} + +.photo-rail-header { + padding: 12px 16px; + color: var(--tp-on-surface); + display: flex; + align-items: center; + justify-content: space-between; +} + +.photo-rail-header a { + display: flex; + align-items: center; + gap: 10px; + color: var(--tp-on-surface); + transition: color 0.15s ease; + text-decoration: none; + position: relative; +} + +.photo-rail-header a:hover { + color: var(--tp-primary); + text-decoration: none; +} + +.photo-rail-icon-wrap { + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + /* width: 24px; + height: 24px; */ +} + +.photo-rail-media-badge { + position: absolute; + top: -12px; + right: -10px; + display: inline-flex; + align-items: center; + justify-content: center; + background-color: var(--tp-accent-red); + color: var(--tp-surface); + font-size: 10px; + font-weight: 500; + min-width: 18px; + height: 18px; + border-radius: var(--shape-full); + padding: 0 4px; + line-height: 1; + box-sizing: border-box; + border: 2px solid var(--tp-surface-container); +} + +.photo-rail-media-icon { + color: var(--tp-on-surface-variant); + font-size: 20px !important; + position: relative; +} + +.photo-rail-media-label { + font-size: 14px; + color: var(--tp-on-surface-variant); + font-weight: 400; +} + +.photo-rail-header-mobile-inner { + display: flex; + align-items: center; + gap: 10px; +} + +.photo-rail-header-mobile { + display: none; + box-sizing: border-box; + padding: 16px; + width: 100%; + color: var(--tp-primary); + justify-content: space-between; + align-items: center; + font-weight: 600; + font-size: 16px; + cursor: pointer; + /* border-radius: var(--shape-lg); */ + transition: background-color 0.15s ease; +} + +.photo-rail-header-mobile:hover { + background-color: var(--tp-surface-container-high); +} + +.photo-rail-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 4px; + padding: 4px; + background: var(--tp-surface-container); +} + +.photo-rail-grid a { + position: relative; + display: block; + border-radius: var(--shape-sm); + background-color: var(--tp-surface-container-highest); + overflow: hidden; + aspect-ratio: 1; + min-width: 0; + min-height: 0; +} + +.photo-rail-grid img { + display: block; + height: 100%; + width: 100%; + object-fit: contain; + position: absolute; + top: 0; + left: 0; +} + + +/* Mobile toggle */ #photo-rail-grid-toggle { display: none; - - &:checked ~ .photo-rail-grid { - max-height: 640px; - } - - &:checked ~ label .icon-down:before { - transform: rotate(180deg) translateY(-1px); - } } #photo-rail-grid-toggle:checked ~ .photo-rail-grid { - padding-bottom: 12px; + max-height: 640px; + padding: 8px; } +#photo-rail-grid-toggle:checked ~ label .icon-down:before { + transform: rotate(180deg) translateY(-1px); +} + +#photo-rail-grid-toggle:checked ~ .photo-rail-grid { + padding-bottom: 8px; +} + + @media (max-width: 700px) { .photo-rail-header { display: none; @@ -81,26 +160,32 @@ .photo-rail-grid { max-height: 0; - padding-bottom: 0; overflow: hidden; - transition: max-height 0.4s; - } - - .photo-rail-grid { - grid-template-columns: repeat(6, 1fr); + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1); + grid-template-columns: repeat(5, 1fr); + gap: 4px; + padding: 0; } #photo-rail-grid-toggle:checked ~ .photo-rail-grid { - max-height: 300px; + max-height: 400px; + padding: 8px; + } + + .photo-rail-card { + border-bottom-left-radius: var(--shape-md); + border-bottom-right-radius: var(--shape-md); + margin: 0; } } @media (max-width: 450px) { .photo-rail-grid { - grid-template-columns: repeat(4, 1fr); + grid-template-columns: repeat(5, 1fr); } #photo-rail-grid-toggle:checked ~ .photo-rail-grid { - max-height: 450px; + max-height: 320px; } } + diff --git a/public/css/search.css b/public/css/search.css index 54f0be0..eaf7681 100644 --- a/public/css/search.css +++ b/public/css/search.css @@ -1,117 +1,173 @@ .search-title { - font-weight: bold; + font-weight: 600; display: inline-block; margin-top: 4px; + color: var(--tp-on-surface); } .search-field { display: flex; flex-wrap: wrap; + gap: 8px; + align-items: center; /* add this */ +} - & button { - margin: 0 2px 0 0; - padding: 0px 1px 1px 4px; - height: 23px; - display: flex; - align-items: center; - } +.search-field button { + margin: 0; + padding: 8px 16px; + height: 36px; + /* display: flex; */ + background-color: var(--tp-primary); + color: var(--tp-on-primary); + border: none; + border-radius: var(--shape-md); + font-weight: 500; + cursor: pointer; + /* transition: all 0.15s ease; + box-shadow: var(--elevation-1); */ +} - & .pref-input { - margin: 0 4px 0 0; - flex-grow: 1; - height: 23px; - } +.search-field button:hover { + background-color: var(--tp-on-primary-container); +} - & input[type="text"], - & input[type="number"] { - height: calc(100% - 4px); - width: calc(100% - 8px); - } +.search-field .pref-input { + margin: 0; + flex-grow: 1; + height: auto; +} - & > label { - display: inline; - background-color: var(--bg_elements); - color: var(--fg_color); - border: 1px solid var(--accent_border); - padding: 1px 1px 2px 4px; - font-size: 14px; - cursor: pointer; - margin-bottom: 2px; +.search-field input[type="text"], +.search-field input[type="number"] { + height: 36px; + width: 100%; + background-color: var(--tp-surface-container-highest); + border: 1px solid transparent; + padding: 0 12px; + color: var(--tp-on-surface); + font-size: 14px; +} - &:hover { - border-color: var(--accent); - } +.search-field input[type="text"]:hover, +.search-field input[type="number"]:hover { + background-color: var(--tp-surface-container-high); +} - &:active { - border-color: var(--accent_light); - } - } +.search-field input[type="text"]:focus, +.search-field input[type="number"]:focus { + background-color: var(--tp-surface-container-highest); + border-color: var(--tp-primary); + outline: none; +} - /* create-toggle(search-panel, 380px) */ - & #search-panel-toggle { - display: none; +.search-field > label { + display: inline-flex; + align-items: center; + /* background-color: var(--tp-surface-container); */ + color: var(--tp-on-surface-variant); + border: 1px solid var(--tp-outline-variant); + padding: 4px 4px; + font-size: 14px; + cursor: pointer; + border-radius: var(--shape-md); + font-weight: 500; + transition: all 0.15s ease; +} - &:checked ~ .search-panel { - max-height: 380px; - } +.search-field > label:hover { + border-color: var(--tp-outline); + background-color: var(--tp-surface-container-high); +} - &:checked ~ label .icon-down:before { - transform: rotate(180deg) translateY(-1px); - } - } +.search-field > label:active { + background-color: var(--tp-surface-container-highest); +} + +/* create-toggle(search-panel, 380px) */ +.search-field #search-panel-toggle { + display: none; +} + +.search-field #search-panel-toggle:checked ~ .search-panel { + max-height: 380px; +} + +.search-field #search-panel-toggle:checked ~ label .icon-down:before { + transform: rotate(180deg) translateY(-1px); } .search-panel { width: 100%; max-height: 0; overflow: hidden; - transition: max-height 0.4s; - + transition: max-height 0.4s ease; flex-grow: 1; font-weight: initial; - text-align: left; - - & .checkbox-container { - display: inline; - padding-right: unset; - margin-bottom: 5px; - margin-left: 23px; - } - - & .checkbox { - right: unset; - left: -22px; - line-height: 1.6em; - } - - & .checkbox-container .checkbox:after { - top: -4px; - } + /* text-align: left; */ + background-color: var(--tp-surface-container); + border-radius: var(--shape-lg); + margin-top: 8px; } +.search-panel .checkbox-container { + display: inline; + padding-right: unset; + margin-bottom: 5px; + margin-left: 23px; +} + +.search-panel .checkbox { + right: unset; + left: -22px; + line-height: 1.6em; + background-color: var(--tp-surface-container-highest); + border: 2px solid var(--tp-outline); + border-radius: var(--shape-xs); +} + + .search-row { display: flex; flex-wrap: wrap; line-height: unset; + padding: 16px; + gap: 12px; +} - & > div { - flex-grow: 1; - flex-shrink: 1; - } +.search-row > div { + flex-grow: 1; + flex-shrink: 1; +} - & input { - height: 21px; - } +.search-row input { + height: 36px; + background-color: var(--tp-surface-container-highest); + border: 1px solid transparent; + border-radius: var(--shape-sm); + padding: 0 12px; + color: var(--tp-on-surface); + font-size: 14px; + transition: all 0.15s ease; +} - & .pref-input { - display: block; - padding-bottom: 5px; +.search-row input:hover { + background-color: var(--tp-surface-container-high); +} - & input { - height: 21px; - margin-top: 1px; - } - } +.search-row input:focus { + background-color: var(--tp-surface-container-highest); + border-color: var(--tp-primary); + outline: none; +} + +.search-row .pref-input { + display: block; + padding-bottom: 5px; +} + +.search-row .pref-input input { + height: 36px; + margin-top: 1px; } .search-toggles { @@ -122,55 +178,53 @@ } /* search-resize expansions for .profile-tabs context */ -.profile-tabs { - @media (max-width: 820px) { - & .search-toggles { - grid-template-columns: repeat(5, auto); - } - - & #search-panel-toggle:checked ~ .search-panel { - max-height: 380px !important; - } +@media (max-width: 820px) { + .profile-tabs .search-toggles { + grid-template-columns: repeat(5, auto); } - @media (max-width: 715px) { - & .search-toggles { - grid-template-columns: repeat(4, auto); - } + .profile-tabs #search-panel-toggle:checked ~ .search-panel { + max-height: 380px !important; + } +} - & #search-panel-toggle:checked ~ .search-panel { - max-height: 380px !important; - } +@media (max-width: 715px) { + .profile-tabs .search-toggles { + grid-template-columns: repeat(4, auto); } - @media (max-width: 700px) { - & .search-toggles { - grid-template-columns: repeat(5, auto); - } + .profile-tabs #search-panel-toggle:checked ~ .search-panel { + max-height: 380px !important; + } +} - & #search-panel-toggle:checked ~ .search-panel { - max-height: 380px !important; - } +@media (max-width: 700px) { + .profile-tabs .search-toggles { + grid-template-columns: repeat(5, auto); } - @media (max-width: 485px) { - & .search-toggles { - grid-template-columns: repeat(4, auto); - } + .profile-tabs #search-panel-toggle:checked ~ .search-panel { + max-height: 380px !important; + } +} - & #search-panel-toggle:checked ~ .search-panel { - max-height: 380px !important; - } +@media (max-width: 485px) { + .profile-tabs .search-toggles { + grid-template-columns: repeat(4, auto); } - @media (max-width: 410px) { - & .search-toggles { - grid-template-columns: repeat(3, auto); - } + .profile-tabs #search-panel-toggle:checked ~ .search-panel { + max-height: 380px !important; + } +} - & #search-panel-toggle:checked ~ .search-panel { - max-height: 380px !important; - } +@media (max-width: 410px) { + .profile-tabs .search-toggles { + grid-template-columns: repeat(3, auto); + } + + .profile-tabs #search-panel-toggle:checked ~ .search-panel { + max-height: 380px !important; } } diff --git a/public/css/style.css b/public/css/style.css index 5e84801..c00dbe2 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -5,61 +5,112 @@ @import "inputs.css"; @import "timeline.css"; @import "search.css"; +@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&display=block'); +@import url('https://fonts.googleapis.com/css2?family=Readex+Pro:wght@160..900&display=swap'); body { - --bg_color: #0f0f0f; - --fg_color: #f8f8f2; - --fg_faded: #f8f8f2cf; - --fg_dark: #ff6c60; - --fg_nav: #ff6c60; + --bg_color: #121214; + --fg_color: #A0A0AF; + --fg_faded: #606069; + --fg_dark: #A0A0AF; + --fg_nav: #A0A0AF; - --bg_panel: #161616; - --bg_elements: #121212; - --bg_overlays: #1f1f1f; - --bg_hover: #1a1a1a; + --bg_panel: #171719; + --bg_elements: #1F1F21; + --bg_overlays: #252527; + --bg_hover: #252527; - --grey: #888889; - --dark_grey: #404040; - --darker_grey: #282828; - --darkest_grey: #222222; - --border_grey: #3e3e35; + --grey: #606069; + /* --dark_grey: #2A2A2C; */ + --darker_grey: #2A2A2C; + --darkest_grey:#2A2A2C; + --border_grey: #3A3A3C; - --accent: #ff6c60; - --accent_light: #ffaca0; - --accent_dark: #8a3731; - --accent_border: #ff6c6091; + --accent: #A0A0AF; + --accent_light: #B8B8C7; + --accent_dark: #888899; + --accent_border: #2A2A2C; - --play_button: #d8574d; - --play_button_hover: #ff6c60; + --play_button: #A0A0AF; + --play_button_hover: #B8B8C7; + --more_replies_dots: #A0A0AF; + --error_red: #2A2028; - --more_replies_dots: #ad433b; - --error_red: #420a05; + --verified_blue: #6C81B8; + --verified_business: #A68170; + --verified_government: #8a8a8a; + --icon_text: #171719; - --verified_blue: #1da1f2; - --verified_business: #fac82b; - --verified_government: #c1b6a4; - --icon_text: #f8f8f2; + --tab: #606069; + --tab_selected: #A0A0AF; + --profile_stat: #A0A0AF; - --tab: #f8f8f2; - --tab_selected: #ff6c60; + --shadow: rgba(0, 0, 0, 0.24); + --shadow_dark: rgba(0, 0, 0, 0.36); - --profile_stat: #f8f8f2; + --tp-primary: var(--accent); + --tp-on-primary: var(--icon_text); + --tp-primary-container: var(--accent_border); + --tp-on-primary-container: var(--fg_nav); - --shadow: rgba(0, 0, 0, 0.6); - --shadow_dark: rgba(0, 0, 0, 0.2); + --tp-secondary: var(--accent_dark); + --tp-on-secondary: var(--icon_text); + --tp-secondary-container: var(--dark_grey); + --tp-on-secondary-container: var(--fg_faded); + + --tp-surface: var(--bg_color); + --tp-surface-dim: var(--bg_panel); + --tp-surface-container-lowest: var(--bg_color); + --tp-surface-container-low: var(--bg_panel); + --tp-surface-container: var(--bg_elements); + --tp-surface-container-high: var(--bg_overlays); + --tp-surface-container-highest: var(--darkest_grey); + --tp-on-surface: var(--fg_color); + --tp-on-surface-variant: var(--fg_faded); + + --tp-outline: var(--border_grey); + --tp-outline-variant: var(--dark_grey); + + --tp-error: #A67E97; + --tp-error-container: var(--error_red); + --tp-on-error-container:var(--fg_color); + + --tp-accent-red: #A67E97; + --tp-accent-green: #738980; + --tp-accent-yellow: var(--verified_business); + --tp-accent-blue: var(--verified_blue); + --tp-accent-magenta: #6E6DA7; + --tp-accent-cyan: #55787D; + + --shape-none: 0px; + --shape-xs: 2px; + --shape-sm: 3px; + --shape-md: 4px; + --shape-lg: 6px; + --shape-xl: 8px; + --shape-full: 9999px; + + --elevation-0: none; + --elevation-1: 0 1px 2px rgba(0, 0, 0, 0.24), 0 1px 3px rgba(0, 0, 0, 0.12); + --elevation-2: 0 2px 4px rgba(0, 0, 0, 0.24), 0 2px 6px rgba(0, 0, 0, 0.16); + --elevation-3: 0 4px 8px rgba(0, 0, 0, 0.32), 0 4px 12px rgba(0, 0, 0, 0.20); background-color: var(--bg_color); color: var(--fg_color); - font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, fontello; - font-size: 15px; - line-height: 1.3; + --font-family: 'Readex Pro', sans-serif, Twemoji; + font-family: var(--font-family); + font-size: 14px; + line-height: 1.5; margin: 0; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } * { outline: unset; margin: 0; text-decoration: none; + font-weight: 300; } h1 { @@ -77,10 +128,10 @@ p { a { color: var(--accent); +} - &:hover { - text-decoration: underline; - } +a:hover { + text-decoration: underline; } fieldset { @@ -100,11 +151,6 @@ legend { margin-bottom: 8px; } -.prefs-code { - white-space: pre-wrap; - word-break: break-all; -} - .preferences .note { border-top: 1px solid var(--border_grey); border-bottom: 1px solid var(--border_grey); @@ -117,192 +163,192 @@ legend { max-width: 700px; margin: 0 auto; padding: 20px; +} - & .cover { - width: 100%; - max-height: 400px; - object-fit: cover; - border-radius: 8px; - margin-bottom: 20px; - } +.note .cover { + width: 100%; + max-height: 400px; + object-fit: cover; + border-radius: 8px; + margin-bottom: 20px; +} - & article { - background-color: var(--bg_panel); - padding: 20px; - border-radius: 8px; +.note article { + background-color: var(--bg_panel); + padding: 20px; + border-radius: 8px; +} - & h1 { - display: block; - font-size: 28px; - margin-bottom: 16px; - line-height: 1.3; - } +.note article h1 { + display: block; + font-size: 28px; + margin-bottom: 16px; + line-height: 1.3; +} - & h2 { - font-size: 22px; - font-weight: bold; - margin: 20px 0 10px; - } +.note article h2 { + font-size: 22px; + font-weight: bold; + margin: 20px 0 10px; +} - & h3 { - font-size: 18px; - font-weight: bold; - margin: 16px 0 8px; - } +.note article h3 { + font-size: 18px; + font-weight: bold; + margin: 16px 0 8px; +} - & p { - margin: 12px 0; - line-height: 1.6; - white-space: pre-wrap; - } +.note article p { + margin: 12px 0; + line-height: 1.6; + white-space: pre-wrap; +} - & ul, - & ol { - margin: 12px 0; - padding-left: 2em; - } +.note article ul, +.note article ol { + margin: 12px 0; + padding-left: 2em; +} - & ol { - list-style-type: decimal; - } +.note article ol { + list-style-type: decimal; +} - & li { - margin: 6px 0; - padding-left: 0.3em; - line-height: 1.6; - } +.note article li { + margin: 6px 0; + padding-left: 0.3em; + line-height: 1.6; +} - & .code-block { - position: relative; - margin: 16px 0; - border-radius: 6px; - background-color: var(--bg_color); - overflow: hidden; +.note article .code-block { + position: relative; + margin: 16px 0; + border-radius: 6px; + background-color: var(--bg_color); + overflow: hidden; +} - & .code-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 4px 10px; - background-color: var(--darker_grey); - font-size: 12px; - color: var(--fg_faded); - min-height: 24px; +.note article .code-block .code-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 4px 10px; + background-color: var(--darker_grey); + font-size: 12px; + color: var(--fg_faded); + min-height: 24px; +} - & .code-lang { - font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace; - } +.note article .code-block .code-header .code-lang { + font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace; +} - & .copy-btn { - background: none; - border: none; - color: var(--fg_faded); - cursor: pointer; - padding: 2px; - border-radius: 3px; - display: flex; - align-items: center; +.note article .code-block .code-header .copy-btn { + background: none; + border: none; + color: var(--fg_faded); + cursor: pointer; + padding: 2px; + border-radius: 3px; + display: flex; + align-items: center; +} - &:hover { - color: var(--fg_color); - } - } - } +.note article .code-block .code-header .copy-btn:hover { + color: var(--fg_color); +} - & .copy-toast { - position: absolute; - top: 4px; - right: 36px; - background-color: var(--bg_elements); - color: var(--fg_color); - font-size: 12px; - padding: 4px 8px; - border-radius: 4px; - pointer-events: none; - animation: toast-fade 1.5s ease forwards; - } +.note article .code-block .copy-toast { + position: absolute; + top: 4px; + right: 36px; + background-color: var(--bg_elements); + color: var(--fg_color); + font-size: 12px; + padding: 4px 8px; + border-radius: 4px; + pointer-events: none; + animation: toast-fade 1.5s ease forwards; +} - & pre { - margin: 0; - padding: 16px; - overflow-x: auto; +.note article .code-block pre { + margin: 0; + padding: 16px; + overflow-x: auto; +} - & code { - font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace; - font-size: 14px; - line-height: 1.5; - white-space: pre; - } - } - } +.note article .code-block pre code { + font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace; + font-size: 14px; + line-height: 1.5; + white-space: pre; +} - & pre { - margin: 16px 0; - padding: 16px; - background-color: var(--bg_color); - border-radius: 6px; - overflow-x: auto; +.note article pre { + margin: 16px 0; + padding: 16px; + background-color: var(--bg_color); + border-radius: 6px; + overflow-x: auto; +} - & code { - font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace; - font-size: 14px; - line-height: 1.5; - white-space: pre; - } - } +.note article pre code { + font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace; + font-size: 14px; + line-height: 1.5; + white-space: pre; +} - & blockquote { - margin: 12px 0; - padding: 4px 0 4px 16px; - border-left: 3px solid var(--accent); - color: var(--fg_faded); - line-height: 1.6; - } - } +.note article blockquote { + margin: 12px 0; + padding: 4px 0 4px 16px; + border-left: 3px solid var(--accent); + color: var(--fg_faded); + line-height: 1.6; +} - & .author { - display: flex; - align-items: center; - margin-bottom: 20px; - color: var(--fg_faded); - font-size: 14px; +.note .author { + display: flex; + align-items: center; + margin-bottom: 20px; + color: var(--fg_faded); + font-size: 14px; +} - & .fullname { - font-weight: bold; - color: var(--fg_color); - } +.note .author .fullname { + font-weight: bold; + color: var(--fg_color); +} - & .username { - color: var(--fg_dark); - } - } +.note .author .username { + color: var(--fg_dark); +} - & .image { - display: flex; - justify-content: center; - margin: 16px 0; +.note .image { + display: flex; + justify-content: center; + margin: 16px 0; +} - & img { - max-width: 100%; - border-radius: 6px; - } +.note .image img { + max-width: 100%; + border-radius: 6px; +} - & video { - max-width: 100%; - border-radius: 6px; - } - } +.note .image video { + max-width: 100%; + border-radius: 6px; +} - & .twemoji { - height: 1.2em; - vertical-align: middle; - } +.note .twemoji { + height: 1.2em; + vertical-align: middle; +} - & .timeline-item { - margin: 16px 0; - border-radius: 8px; - overflow: hidden; - } +.note .timeline-item { + margin: 16px 0; + border-radius: 8px; + overflow: hidden; } @keyframes toast-fade { @@ -336,64 +382,36 @@ ul { background-color: var(--bg_overlays); padding: 10px 15px; align-self: start; - box-sizing: border-box; - overflow: hidden; +} - & ul { - margin-bottom: 14px; - } +.overlay-panel ul { + margin-bottom: 14px; +} - & p { - word-break: break-word; - } +.overlay-panel p { + word-break: break-word; } .verified-icon { - display: inline-block; - width: 14px; - height: 14px; + display: inline-flex; + align-items: center; margin-left: 2px; +} - & .verified-icon-circle { - position: absolute; - font-size: 15px; - } +.verified-icon .verified-badge-check { + fill: #ffffff; +} - & .verified-icon-check { - position: absolute; - font-size: 9px; - margin: 5px 3px; - } +.verified-icon.blue .verified-badge-bg { + fill: var(--verified_blue); +} - &.blue { - & .verified-icon-circle { - color: var(--verified_blue); - } +.verified-icon.business .verified-badge-bg { + fill: var(--verified_business); +} - & .verified-icon-check { - color: var(--icon_text); - } - } - - &.business { - & .verified-icon-circle { - color: var(--verified_business); - } - - & .verified-icon-check { - color: var(--bg_panel); - } - } - - &.government { - & .verified-icon-circle { - color: var(--verified_government); - } - - & .verified-icon-check { - color: var(--bg_panel); - } - } +.verified-icon.government .verified-badge-bg { + fill: var(--verified_government); } @media (max-width: 600px) { diff --git a/public/css/themes/teapot_light.css b/public/css/themes/teapot_light.css new file mode 100644 index 0000000..d3eebbc --- /dev/null +++ b/public/css/themes/teapot_light.css @@ -0,0 +1,95 @@ +/* + * Teapot Light - Light Theme for Teapot + * Warm Coral palette + */ + +body { + --tp-primary: #9c4238; + --tp-on-primary: #ffffff; + --tp-primary-container: #ffdad4; + --tp-on-primary-container: #3a0a06; + + --tp-secondary: #4a635e; + --tp-on-secondary: #ffffff; + --tp-secondary-container: #cce8e2; + --tp-on-secondary-container: #051f1b; + + --tp-surface: #fff8f6; + --tp-surface-dim: #ebd5d1; + --tp-surface-container-lowest: #ffffff; + --tp-surface-container-low: #fff0ed; + --tp-surface-container: #ffe9e5; + --tp-surface-container-high: #fce3de; + --tp-surface-container-highest: #f6ddd9; + --tp-on-surface: #231918; + --tp-on-surface-variant: #544340; + + --tp-outline: #897370; + --tp-outline-variant: #dcc6c2; + + --tp-error: #ba1a1a; + --tp-error-container: #ffdad6; + --tp-on-error-container: #410002; + + --tp-accent-red: #ba1a1a; + --tp-accent-green: #4a635e; + --tp-accent-yellow: #e6a23c; + --tp-accent-blue: #4a90d9; + --tp-accent-magenta: #9c4238; + --tp-accent-cyan: #4a635e; + + --elevation-0: none; + --elevation-1: 0 1px 3px rgba(60, 30, 25, 0.12), 0 1px 2px rgba(60, 30, 25, 0.08); + --elevation-2: 0 3px 6px rgba(60, 30, 25, 0.15), 0 2px 4px rgba(60, 30, 25, 0.10); + --elevation-3: 0 6px 12px rgba(60, 30, 25, 0.18), 0 4px 8px rgba(60, 30, 25, 0.12); + + --bg_color: #fff8f6; + --fg_color: #231918; + --fg_faded: #544340; + --fg_dark: #9c4238; + --fg_nav: #9c4238; + + --bg_panel: #fff0ed; + --bg_elements: #ffe9e5; + --bg_overlays: #fce3de; + --bg_hover: #fce3de; + + --grey: #544340; + --dark_grey: #dcc6c2; + --darker_grey: #dcc6c2; + --darkest_grey: #f6ddd9; + --border_grey: #dcc6c2; + + --accent: #9c4238; + --accent_light: #ff8a7a; + --accent_dark: #7a332b; + --accent_border: #ffdad4; + + --play_button: #9c4238; + --play_button_hover: #3a0a06; + --more_replies_dots: #9c4238; + --error_red: #ffdad6; + + --verified_blue: #4a90d9; + --verified_business: #e6a23c; + --verified_government: #8a8a8a; + --icon_text: #ffffff; + + --tab: #544340; + --tab_selected: #9c4238; + --profile_stat: #231918; + + --shadow: rgba(60, 30, 25, 0.12); + --shadow_dark: rgba(60, 30, 25, 0.24); + + background-color: var(--bg_color); + color: var(--fg_color); +} + +nav { + background-color: var(--tp-surface-container-low); +} + +.search-bar > form:focus-within { + background-color: var(--tp-surface-container-lowest); +} diff --git a/public/css/timeline.css b/public/css/timeline.css index eef5d47..c8b27db 100644 --- a/public/css/timeline.css +++ b/public/css/timeline.css @@ -5,37 +5,51 @@ border-radius: 0; position: relative; width: 100%; + padding: 0 8px; } .timeline { - background-color: var(--bg_panel); - - & > div:not(:first-child) { - border-top: 1px solid var(--border_grey); - } + background-color: transparent; } + .timeline-header { width: 100%; - background-color: var(--bg_panel); + /* background-color: var(--tp-surface-container); */ text-align: center; - padding: 8px; + /* padding: 16px; */ display: block; - font-weight: bold; - margin-bottom: 5px; + font-weight: 600; + font-size: 14px; + /* margin-bottom: 8px; */ box-sizing: border-box; + border-radius: var(--shape-lg); + /* box-shadow: var(--elevation-1); */ + color: var(--tp-on-surface); +} - & button { - float: unset; - } +.timeline-header button { + float: unset; + background: var(--tp-primary); + color: var(--tp-on-primary); + border-radius: var(--shape-sm); + padding: 8px 20px; + font-weight: 500; + transition: background 0.15s ease; +} + +.timeline-header button:hover { + background: var(--tp-on-primary-container); } .timeline-banner img { width: 100%; + border-radius: var(--shape-lg); } .timeline-description { font-weight: normal; + color: var(--tp-on-surface-variant); } .tab { @@ -43,115 +57,163 @@ display: flex; flex-wrap: wrap; list-style: none; - margin: 0 0 5px 0; - background-color: var(--bg_panel); + margin: 0 0 16px 0; padding: 0; + border-bottom: 1px solid var(--tp-outline-variant); + position: sticky; + top: 56px; + background-color: var(--bg_color); + z-index: 10; } .tab-item { flex: 1 1 0; text-align: center; margin-top: 0; +} - & a { - border-bottom: 0.1rem solid transparent; - color: var(--tab); - display: block; - padding: 8px 0; - text-decoration: none; - font-weight: bold; +.tab-item a { + color: var(--tp-on-surface-variant); + display: block; + padding: 8px 12px; + text-decoration: none; + font-weight: 500; + font-size: 14px; + border-bottom: 2px solid transparent; + margin-bottom: -1px; + transition: color 0.15s ease; +} - &:hover { - text-decoration: none; - } +.tab-item a:hover { + text-decoration: none; + color: var(--tp-on-surface); +} - &.active { - border-bottom-color: var(--tab_selected); - color: var(--tab_selected); - } - } +.tab-item a.active { + border-bottom-color: var(--tp-primary); + color: var(--tp-on-surface); +} - &.active a { - border-bottom-color: var(--tab_selected); - color: var(--tab_selected); - } +.tab-item.active a { + border-bottom-color: var(--tp-accent-blue); + color: var(--tp-on-surface); +} - &.wide { - flex-grow: 1.2; - flex-basis: 50px; - } +.tab-item.wide { + flex-grow: 1.2; + flex-basis: 50px; } .timeline-footer { - background-color: var(--bg_panel); - padding: 6px 0; + background-color: var(--tp-surface-container-low); + padding: 8px 0; + border-radius: var(--shape-lg); + margin-top: 8px; } .timeline-protected { text-align: center; + background-color: var(--tp-surface-container); + border-radius: var(--shape-lg); + padding: 24px 16px; + box-shadow: var(--elevation-1); +} - & p { - margin: 8px 0; - } +.timeline-protected p { + margin: 8px 0; + color: var(--tp-on-surface-variant); +} - & h2 { - color: var(--accent); - font-size: 20px; - font-weight: 600; - } +.timeline-protected h2 { + color: var(--tp-primary); + font-size: 22px; + font-weight: 600; } .timeline-none { - color: var(--accent); + color: var(--tp-primary); font-size: 20px; font-weight: 600; text-align: center; + padding: 24px 16px; + /* box-shadow: var(--elevation-1); */ } .timeline-end { - background-color: var(--bg_panel); - color: var(--accent); - font-size: 16px; - font-weight: 600; + background-color: var(--tp-surface-container); + color: var(--tp-on-surface-variant); + font-size: 14px; + font-weight: 500; text-align: center; + padding: 12px; + border-radius: var(--shape-lg); + margin-top: 8px; } .show-more { - background-color: var(--bg_panel); + background-color: transparent; text-align: center; - padding: 0.75em 0; + padding: 12px 0; display: block !important; +} - & a { - background-color: var(--darkest_grey); - display: inline-block; - height: 2em; - padding: 0 2em; - line-height: 2em; +.show-more a { + background-color: transparent; + display: inline-block; + height: auto; + padding: 8px 24px; + line-height: 1.5; + color: var(--tp-primary); + font-weight: 500; + border-radius: var(--shape-sm); + transition: color 0.15s ease; +} - &:hover { - background-color: var(--darker_grey); - } - } +.show-more a:hover { + background-color: var(--bg_hover); + text-decoration: none; + border-radius: 30px; } .top-ref { - background-color: var(--bg_color); + background-color: var(--tp-surface); border-top: none !important; +} - & .icon-down { - font-size: 20px; - display: flex; - justify-content: center; - text-decoration: none; +.top-ref .icon-down { + font-size: 20px; + display: flex; + justify-content: center; + text-decoration: none; + color: var(--tp-primary); + padding: 8px; + border-radius: var(--shape-sm); + width: fit-content; + margin: 0 auto; + transition: color 0.15s ease; +} - &:hover { - color: var(--accent_light); - } +.top-ref .icon-down:hover { + color: var(--tp-on-primary-container); + background-color: var(--bg_hover); +} - &::before { - transform: rotate(180deg) translateY(-1px); - } +.top-ref .icon-down::before { + transform: rotate(180deg) translateY(-1px); +} + +.timeline { + animation: timeline-fade-in 0.4s cubic-bezier(0.4, 0, 0.2, 1); +} + +@keyframes timeline-fade-in { + from { + opacity: 0; + transform: translateY(16px); + } + to { + opacity: 1; + transform: translateY(0); } } @@ -159,7 +221,62 @@ overflow-wrap: break-word; border-left-width: 0; min-width: 0; - padding: 0.75em; + padding: 8px; display: flex; position: relative; + transition: background-color 0.15s ease; + animation: item-slide-up 0.5s cubic-bezier(0.4, 0, 0.2, 1) both; +} + + + +.timeline-item:active { + background-color: var(--tp-surface-container-highest); +} + +@keyframes item-slide-up { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + + +@media (max-width: 600px) { + .timeline-container { + padding: 0; + } + + .timeline-item { + padding: 10px; + } + + .timeline-item:hover { + transform: none; + } + + .timeline-header, + .timeline-footer, + .timeline-protected, + .timeline-none, + .timeline-end { + border-radius: 0; + } + + .tab { + margin-left: -8px; + margin-right: -8px; + } +} + +/* Reduced motion preference */ +@media (prefers-reduced-motion: reduce) { + .timeline, + .timeline-item { + animation: none !important; + } } diff --git a/public/css/tweet/base.css b/public/css/tweet/base.css index 24431f7..9d09609 100644 --- a/public/css/tweet/base.css +++ b/public/css/tweet/base.css @@ -56,7 +56,7 @@ flex-shrink: 2; max-width: 80%; font-size: 14px; - font-weight: 700; + font-weight: 500; color: var(--fg_color); } @@ -78,7 +78,7 @@ .tweet-date a, .username, .show-more a { - color: var(--fg_dark); + color: var(--tp-accent-blue); } .tweet-published { @@ -282,16 +282,12 @@ a.tweet-stat { } .translate-btn { - background: none; - border: none; - padding: 0; - font: inherit; - font-size: 0.85em; - color: var(--accent); cursor: pointer; - pointer-events: all !important; + pointer-events: all; margin-top: 4px; display: block; + clear: both; + width: 100%; } .translate-btn.htmx-request { @@ -332,5 +328,6 @@ a.tweet-stat { &:hover { background-color: var(--bg_hover); + border-radius: 10px; } } diff --git a/public/css/tweet/quote.css b/public/css/tweet/quote.css index 471614d..42dd066 100644 --- a/public/css/tweet/quote.css +++ b/public/css/tweet/quote.css @@ -1,6 +1,6 @@ .quote { margin-top: 10px; - border: solid 1px var(--dark_grey); + border: solid 1px var(--bg_panel); border-radius: 10px; background-color: var(--bg_elements); overflow: hidden; diff --git a/public/css/twemoji.css b/public/css/twemoji.css index c5fc74e..50f8c59 100644 --- a/public/css/twemoji.css +++ b/public/css/twemoji.css @@ -3,6 +3,3 @@ src: url('/fonts/Twemoji.woff2') format('woff2'); font-display: swap; } -body { - font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, Twemoji, fontello; -} diff --git a/src/api/client.rs b/src/api/client.rs index 5c93e12..ab8d0fc 100644 --- a/src/api/client.rs +++ b/src/api/client.rs @@ -843,11 +843,7 @@ impl ApiClient { } /// Translate a tweet using Kagi Translate API. - pub async fn kagi_translate( - &self, - tweet_id: &str, - kagi_token: &str, - ) -> Result { + pub async fn kagi_translate(&self, tweet_id: &str, kagi_token: &str) -> Result { use http_body_util::Full; use hyper_rustls::HttpsConnectorBuilder; use hyper_util::{ @@ -995,7 +991,7 @@ impl ApiClient { tweet_id: tweet.id.to_string(), color: String::new(), }); - if photos.len() >= 16 { + if photos.len() >= 10 { return Ok(photos); } } diff --git a/src/main.rs b/src/main.rs index 4d10eec..76e215e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -155,10 +155,10 @@ async fn main() -> eyre::Result<()> { HeaderValue::from_static( "default-src 'none'; \ script-src 'self'; \ - style-src 'self' 'unsafe-inline'; \ + style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \ img-src 'self' data:; \ media-src 'self' blob:; \ - font-src 'self'; \ + font-src 'self' https://fonts.gstatic.com; \ connect-src 'self'; \ form-action 'self'; \ base-uri 'self'; \ diff --git a/src/routes/status.rs b/src/routes/status.rs index 98fa52a..a8dbdb0 100644 --- a/src/routes/status.rs +++ b/src/routes/status.rs @@ -121,7 +121,8 @@ async fn status_media_redirect(Path((username, id)): Path<(String, String)>) -> #[expect( clippy::cognitive_complexity, - reason = "status handler has many conditional branches for caching, scrolling, pagination, and translation" + reason = "status handler has many conditional branches for caching, scrolling, pagination, and \ + translation" )] async fn status( State(state): State, @@ -534,10 +535,7 @@ async fn translate( (!server_token.is_empty()).then(|| server_token.clone()) }); - let result = state - .api - .translate_auto(&id, kagi_token.as_deref()) - .await; + let result = state.api.translate_auto(&id, kagi_token.as_deref()).await; match result { Ok(tl) if !tl.text.is_empty() => { diff --git a/src/types/prefs.rs b/src/types/prefs.rs index ba291b2..3f0787f 100644 --- a/src/types/prefs.rs +++ b/src/types/prefs.rs @@ -52,7 +52,7 @@ impl Prefs { hide_pins: false, hide_replies: false, hide_community_notes: false, - square_avatars: false, + square_avatars: true, use_twemoji: true, sticky_nav: true, proxy_media: true, diff --git a/src/types/tweet.rs b/src/types/tweet.rs index 420a1a9..eedc4fd 100644 --- a/src/types/tweet.rs +++ b/src/types/tweet.rs @@ -266,41 +266,41 @@ pub struct TweetStats { reason = "mirrors Twitter API tweet fields" )] pub struct Tweet { - pub id: i64, - pub thread_id: i64, - pub reply_id: i64, - pub user: User, - pub text: String, + pub id: i64, + pub thread_id: i64, + pub reply_id: i64, + pub user: User, + pub text: String, #[serde(with = "time::serde::timestamp::option")] - pub time: Option, - pub reply: Vec, - pub pinned: bool, - pub has_thread: bool, - pub available: bool, - pub tombstone: String, - pub location: String, - pub source: String, - pub stats: TweetStats, - pub retweet: Option>, - pub attribution: Option, - pub media_tags: Vec, - pub quote: Option>, - pub card: Option, - pub poll: Option, - pub gif: Option, - pub video: Option