From 6a26c5f752b31cdb631a37459effdf377e2cda86 Mon Sep 17 00:00:00 2001 From: AlexsandrSnytkin Date: Fri, 18 Sep 2026 17:52:24 +0700 Subject: [PATCH] feat(ui): polish appearance controls --- ui_server.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/ui_server.py b/ui_server.py index 797f2fd..684ad6a 100644 --- a/ui_server.py +++ b/ui_server.py @@ -1380,7 +1380,7 @@ HTML = """ .appearance-trigger-copy small { min-width: 0; overflow: hidden; color: var(--ui-muted); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; } .appearance-trigger-chevron { margin-left: auto; color: var(--ui-muted); font-size: 17px; line-height: 1; transform: translateY(-1px); transition: transform .2s ease, color .2s ease; } .appearance-trigger[aria-expanded="true"] .appearance-trigger-chevron { color: var(--ui-accent); transform: rotate(180deg) translateY(1px); } - .appearance-panel { position: absolute; top: calc(100% + 9px); right: 0; width: min(370px, calc(100vw - 20px)); max-height: min(78vh, 620px); overflow: auto; padding: 13px; border: 1px solid var(--ui-border); border-radius: 14px; background: color-mix(in srgb, var(--ui-surface) 97%, var(--ui-input)); box-shadow: 0 18px 46px rgba(0, 0, 0, .24); color: var(--ui-text); animation: appearance-in .2s ease both; } + .appearance-panel { position: absolute; top: calc(100% + 9px); right: 0; width: min(390px, calc(100vw - 20px)); max-height: min(78vh, 680px); overflow: auto; padding: 13px; border: 1px solid color-mix(in srgb, var(--ui-accent) 22%, var(--ui-border)); border-radius: 16px; background: color-mix(in srgb, var(--ui-surface) 97%, var(--ui-input)); box-shadow: 0 18px 46px rgba(0, 0, 0, .24), 0 0 0 1px color-mix(in srgb, var(--ui-accent) 7%, transparent); color: var(--ui-text); animation: appearance-in .2s ease both; } .appearance-panel[hidden] { display: none !important; } .appearance-head, .appearance-group-head, .appearance-intensity > span, .appearance-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; } .appearance-head { padding-bottom: 11px; border-bottom: 1px solid var(--ui-border); } @@ -1389,12 +1389,29 @@ HTML = """ .appearance-head small, .appearance-group-head small, .appearance-foot span { color: var(--ui-muted); font-size: 10px; } .appearance-close { width: 26px; height: 26px; border: 1px solid transparent; border-radius: 7px; background: transparent; color: var(--ui-muted); font-size: 19px; line-height: 1; cursor: pointer; } .appearance-close:hover { color: var(--ui-text); border-color: var(--ui-border); background: var(--ui-input); } + .appearance-preview { display: grid; gap: 7px; margin: 11px 0 1px; padding: 9px; border: 1px solid color-mix(in srgb, var(--ui-accent) 30%, var(--ui-border)); border-radius: 11px; background: linear-gradient(135deg, color-mix(in srgb, var(--ui-accent) 10%, var(--ui-panel)), var(--ui-input)); overflow: hidden; } + .appearance-preview-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; color: var(--ui-muted); font-size: 9px; letter-spacing: .1em; text-transform: uppercase; } + .appearance-preview-status { color: var(--ui-accent); font-weight: 800; } + .appearance-preview-card { position: relative; display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 8px; border: 1px solid color-mix(in srgb, var(--ui-accent) 23%, var(--ui-border)); border-radius: 9px; background: color-mix(in srgb, var(--ui-surface) 72%, transparent); overflow: hidden; animation: preview-float 4.5s ease-in-out infinite; } + .appearance-preview-card::after { content: ""; position: absolute; inset: 0 auto 0 -38%; width: 34%; background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--ui-accent) 18%, transparent), transparent); transform: skewX(-18deg); animation: preview-sheen 4.8s ease-in-out infinite; pointer-events: none; } + .appearance-preview-dot { width: 25px; height: 25px; flex: 0 0 auto; border: 4px solid color-mix(in srgb, var(--ui-accent) 20%, transparent); border-radius: 50%; background: var(--ui-accent); box-shadow: 0 0 16px color-mix(in srgb, var(--ui-accent) 35%, transparent); } + .appearance-preview-copy { min-width: 0; display: grid; gap: 2px; } + .appearance-preview-copy strong { overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; } + .appearance-preview-copy small { color: var(--ui-muted); font-size: 10px; } + .appearance-preview-bars { display: flex; align-items: end; gap: 3px; height: 24px; margin-left: auto; padding-right: 2px; } + .appearance-preview-bars i { display: block; width: 4px; border-radius: 4px; background: var(--ui-accent); opacity: .72; animation: preview-bars 1.8s ease-in-out infinite; } + .appearance-preview-bars i:nth-child(1) { height: 9px; animation-delay: -.4s; } + .appearance-preview-bars i:nth-child(2) { height: 17px; animation-delay: -.2s; } + .appearance-preview-bars i:nth-child(3) { height: 12px; animation-delay: -.7s; } + .appearance-preview-bars i:nth-child(4) { height: 21px; animation-delay: -.1s; } + .appearance-preview-bars i:nth-child(5) { height: 14px; animation-delay: -.55s; } .appearance-group { display: grid; gap: 8px; padding: 12px 0; border-bottom: 1px solid var(--ui-border); } .appearance-group-head span { font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; } .appearance-options { display: grid; grid-template-columns: repeat(auto-fit, minmax(105px, 1fr)); gap: 6px; } .appearance-options button { min-width: 0; display: grid; grid-template-columns: 18px minmax(0, 1fr); align-items: center; gap: 6px; height: 34px; padding: 0 7px; border: 1px solid var(--ui-border); border-radius: 8px; background: var(--ui-input); color: var(--ui-muted); font: 10px/1.05 ui-sans-serif, system-ui, sans-serif; text-align: left; cursor: pointer; transition: border-color .18s ease, background .18s ease, color .18s ease, transform .18s ease; } .appearance-options button:hover { color: var(--ui-text); border-color: color-mix(in srgb, var(--ui-accent) 62%, var(--ui-border)); transform: translateY(-1px); } - .appearance-options button.is-active { color: var(--ui-text); border-color: var(--ui-accent); background: color-mix(in srgb, var(--ui-accent) 12%, var(--ui-input)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-accent) 20%, transparent); } + .appearance-options button.is-active { color: var(--ui-text); border-color: var(--ui-accent); background: color-mix(in srgb, var(--ui-accent) 12%, var(--ui-input)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ui-accent) 20%, transparent), 0 4px 12px color-mix(in srgb, var(--ui-accent) 10%, transparent); } + .appearance-options button.is-active .appearance-swatch { box-shadow: 0 0 0 2px var(--ui-accent), inset 0 0 0 4px var(--appearance-swatch-2, transparent); } .appearance-options button > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .appearance-swatch { width: 18px; height: 18px; border: 1px solid color-mix(in srgb, var(--ui-text) 18%, transparent); border-radius: 6px; background: var(--appearance-swatch); box-shadow: inset 0 0 0 4px var(--appearance-swatch-2, transparent); } .accent-options button { grid-template-columns: 14px minmax(0, 1fr); } @@ -1455,11 +1472,14 @@ HTML = """ .config-block.settings-group input:not([type="checkbox"]):not([type="file"]), .config-block.settings-group select, .config-block.settings-group button { min-height: calc(27px * var(--block-scale)); height: calc(27px * var(--block-scale)); padding-left: calc(7px * var(--block-scale)); padding-right: calc(7px * var(--block-scale)); font-size: clamp(8px, calc(12px * var(--block-scale)), 26px); } .config-block.settings-group .control-fields, .config-block.settings-group .advanced-grid, .config-block.settings-group .packet-grid { gap: calc(6px * var(--block-scale)) calc(8px * var(--block-scale)); } @keyframes appearance-in { from { opacity: 0; transform: translateY(-5px) scale(.98); } to { opacity: 1; transform: none; } } + @keyframes preview-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } } + @keyframes preview-sheen { 0%, 55% { transform: translateX(0) skewX(-18deg); opacity: 0; } 70% { opacity: 1; } 100% { transform: translateX(430%) skewX(-18deg); opacity: 0; } } + @keyframes preview-bars { 0%, 100% { transform: scaleY(.72); opacity: .52; } 50% { transform: scaleY(1); opacity: .95; } } @media (max-width: 760px) { .appearance-trigger { min-width: 38px; width: 38px; padding: 0; justify-content: center; } .appearance-trigger-copy { display: none; } .appearance-trigger-chevron { display: none; } - .appearance-panel { position: fixed; top: 56px; right: 8px; width: min(370px, calc(100vw - 16px)); } + .appearance-panel { position: fixed; top: 56px; right: 8px; width: min(390px, calc(100vw - 16px)); } .appearance-options { grid-template-columns: repeat(3, minmax(0, 1fr)); } } @media (max-width: 420px) { .appearance-options { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @@ -1484,6 +1504,10 @@ HTML = """