From 04d3c61ac87d75d89a7432f55fc896236775568a Mon Sep 17 00:00:00 2001 From: bboysoul Date: Mon, 7 Sep 2026 13:59:38 +0800 Subject: [PATCH] fix: simplify add button visuals --- frontend/src/components/FloatingAddButton.vue | 5 ++--- frontend/src/style.css | 4 ++-- frontend/src/style.test.ts | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/FloatingAddButton.vue b/frontend/src/components/FloatingAddButton.vue index a7f04e2..f3ceb71 100644 --- a/frontend/src/components/FloatingAddButton.vue +++ b/frontend/src/components/FloatingAddButton.vue @@ -27,7 +27,7 @@ function moveDrag(event: PointerEvent) { const deltaY = event.clientY - start.startY if (!dragging.value && !isFabDrag(deltaX, deltaY)) return dragging.value = true - position.value = clampFabPosition(start.originX + deltaX, start.originY + deltaY, window.innerWidth, window.innerHeight, 58, 14, 84) + position.value = clampFabPosition(start.originX + deltaX, start.originY + deltaY, window.innerWidth, window.innerHeight, 56, 14, 84) } function finishDrag(event: PointerEvent) { const start = pointer.value @@ -49,7 +49,6 @@ function activate(event: MouseEvent) { diff --git a/frontend/src/style.css b/frontend/src/style.css index d0ff0cd..a42b0f9 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -27,6 +27,6 @@ main{min-width:0;padding:27px 34px 50px;overflow:auto;background:linear-gradient .empty-panel{text-align:center;color:var(--muted)} .settings-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.tool-card{display:flex;flex-direction:column;align-items:flex-start;gap:10px}.tool-card>svg{color:var(--accent);width:25px;height:25px}.tool-card p{margin:0;color:var(--muted);font-size:13px}.tool-card.wide{grid-column:1/-1}.file-button input{display:none}.tool-card pre{width:100%;max-height:180px;overflow:auto;background:#f8f3e8;padding:10px;border-radius:8px;font-size:10px}.session-row,.audit-row{width:100%;display:flex;justify-content:space-between;align-items:center;border-top:1px solid var(--line);padding:9px 0}.session-row span{display:grid}.session-row small,.audit-row small{color:var(--muted);font-size:11px}.inline-error{padding:9px;border-radius:8px;color:var(--danger);background:#fff0ed}.settings.active{background:var(--accent-soft);color:#b7421e;font-weight:700} @media(max-width:800px){.settings-grid{grid-template-columns:1fr}.tool-card.wide{grid-column:auto}.habit-row{padding:5px 4px 5px 8px}.habit-main{padding:10px 2px}.numeric-action input{width:62px}} -.unified-fab{display:grid;place-items:center;position:fixed;z-index:60;right:20px;bottom:22px;width:58px;height:58px;border:0;border-radius:50%;background:radial-gradient(circle at 32% 24%,#fff3df 0 16%,#ff8a55 17% 34%,#f15a29 35% 72%,#c8441d 100%);color:#fff;box-shadow:0 14px 32px rgba(241,90,41,.36),0 0 0 8px rgba(241,90,41,.08),inset 0 2px 4px rgba(255,255,255,.34);transition:transform .18s cubic-bezier(.2,.9,.25,1.25),box-shadow .18s ease,filter .18s ease;touch-action:none;user-select:none;isolation:isolate}.unified-fab:before{content:"";position:absolute;inset:-8px;border-radius:inherit;background:conic-gradient(from 0deg,rgba(255,216,113,.9),rgba(241,90,41,.15),rgba(255,255,255,.65),rgba(255,216,113,.9));filter:blur(10px);opacity:.42;animation:fab-aura 2.8s linear infinite;z-index:-2}.unified-fab-aura{position:absolute;inset:-13px;border-radius:inherit;background:radial-gradient(circle,rgba(241,90,41,.2),transparent 68%);animation:fab-pulse 2.2s ease-in-out infinite;z-index:-1}.unified-fab-core{display:grid;place-items:center;width:42px;height:42px;border-radius:50%;background:rgba(255,255,255,.16);box-shadow:inset 0 1px 0 rgba(255,255,255,.38)}.unified-fab svg{width:27px;height:27px;filter:drop-shadow(0 2px 2px rgba(115,42,12,.25))}.unified-fab:hover{transform:translateY(-2px) scale(1.03);filter:saturate(1.08)}.unified-fab:active{transform:scale(.94)}.unified-fab.dragging{transform:scale(1.11) rotate(8deg);box-shadow:0 18px 44px rgba(241,90,41,.48),0 0 0 12px rgba(241,90,41,.1),inset 0 2px 4px rgba(255,255,255,.42)}@keyframes fab-aura{to{transform:rotate(360deg)}}@keyframes fab-pulse{0%,100%{transform:scale(.92);opacity:.42}50%{transform:scale(1.08);opacity:.82}}.task-compose-mask{position:fixed;z-index:70;inset:0;background:rgba(45,38,31,.34);display:flex;align-items:flex-end;padding:0}.task-compose-sheet{width:100%;max-height:min(88dvh,720px);overflow:auto;background:#fffdf8;border-radius:24px 24px 0 0;padding:18px 18px calc(20px + env(safe-area-inset-bottom));box-shadow:0 -16px 42px rgba(56,40,24,.2);display:grid;gap:14px;transform-origin:var(--fab-origin-x,calc(100% - 44px)) var(--fab-origin-y,100%)}.task-compose-sheet header{display:flex;align-items:center;justify-content:space-between}.task-compose-sheet header small{color:var(--accent);font-size:10px;font-weight:800;letter-spacing:.12em}.task-compose-sheet h2{margin:2px 0 0;font-size:22px}.task-compose-sheet label{display:grid;gap:6px;color:#675f54;font-size:12px;font-weight:650}.task-compose-sheet input,.task-compose-sheet select,.task-compose-sheet textarea{width:100%;border:1px solid var(--line);background:#fff;border-radius:11px;padding:12px;outline:none;resize:vertical}.task-compose-sheet input:focus,.task-compose-sheet select:focus,.task-compose-sheet textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(241,90,41,.1)}.task-compose-row{display:grid;grid-template-columns:minmax(0,1fr) 105px;gap:10px}.task-compose-sheet footer{display:flex;justify-content:flex-end;gap:9px;padding-top:4px}.task-compose-sheet button:disabled{opacity:.45}.task-compose-enter-active,.task-compose-leave-active{transition:background .22s ease}.task-compose-enter-active .task-compose-sheet,.task-compose-leave-active .task-compose-sheet{transition:transform .28s cubic-bezier(.2,.9,.25,1.08),opacity .2s ease}.task-compose-enter-from,.task-compose-leave-to{background:rgba(45,38,31,0)}.task-compose-enter-from .task-compose-sheet,.task-compose-leave-to .task-compose-sheet{transform:translateY(36px) scale(.86);opacity:0} +.unified-fab{display:grid;place-items:center;position:fixed;z-index:60;right:20px;bottom:22px;width:56px;height:56px;border:0;border-radius:50%;background:var(--accent);color:#fff;box-shadow:0 8px 20px rgba(241,90,41,.28);transition:transform .16s ease,box-shadow .16s ease;touch-action:none;user-select:none}.unified-fab svg{width:25px;height:25px}.unified-fab:hover{transform:translateY(-2px);box-shadow:0 10px 24px rgba(241,90,41,.32)}.unified-fab:active{transform:scale(.96)}.unified-fab.dragging{transform:scale(1.06);box-shadow:0 12px 28px rgba(241,90,41,.36)}.task-compose-mask{position:fixed;z-index:70;inset:0;background:rgba(45,38,31,.34);display:flex;align-items:flex-end;padding:0}.task-compose-sheet{width:100%;max-height:min(88dvh,720px);overflow:auto;background:#fffdf8;border-radius:24px 24px 0 0;padding:18px 18px calc(20px + env(safe-area-inset-bottom));box-shadow:0 -16px 42px rgba(56,40,24,.2);display:grid;gap:14px;transform-origin:var(--fab-origin-x,calc(100% - 44px)) var(--fab-origin-y,100%)}.task-compose-sheet header{display:flex;align-items:center;justify-content:space-between}.task-compose-sheet header small{color:var(--accent);font-size:10px;font-weight:800;letter-spacing:.12em}.task-compose-sheet h2{margin:2px 0 0;font-size:22px}.task-compose-sheet label{display:grid;gap:6px;color:#675f54;font-size:12px;font-weight:650}.task-compose-sheet input,.task-compose-sheet select,.task-compose-sheet textarea{width:100%;border:1px solid var(--line);background:#fff;border-radius:11px;padding:12px;outline:none;resize:vertical}.task-compose-sheet input:focus,.task-compose-sheet select:focus,.task-compose-sheet textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px rgba(241,90,41,.1)}.task-compose-row{display:grid;grid-template-columns:minmax(0,1fr) 105px;gap:10px}.task-compose-sheet footer{display:flex;justify-content:flex-end;gap:9px;padding-top:4px}.task-compose-sheet button:disabled{opacity:.45}.task-compose-enter-active,.task-compose-leave-active{transition:background .22s ease}.task-compose-enter-active .task-compose-sheet,.task-compose-leave-active .task-compose-sheet{transition:transform .28s cubic-bezier(.2,.9,.25,1.08),opacity .2s ease}.task-compose-enter-from,.task-compose-leave-to{background:rgba(45,38,31,0)}.task-compose-enter-from .task-compose-sheet,.task-compose-leave-to .task-compose-sheet{transform:translateY(36px) scale(.86);opacity:0} .countdown-compose-enter-active,.countdown-compose-leave-active{transition:background .24s ease}.countdown-compose-enter-active .countdown-modal,.countdown-compose-leave-active .countdown-modal{transition:transform .34s cubic-bezier(.18,.9,.28,1.16),opacity .22s ease,filter .22s ease;transform-origin:var(--fab-origin-x,calc(100% - 43px)) var(--fab-origin-y,calc(100% - 104px))}.countdown-compose-enter-from,.countdown-compose-leave-to{background:rgba(45,38,31,0)}.countdown-compose-enter-from .countdown-modal,.countdown-compose-leave-to .countdown-modal{transform:translate(20px,28px) scale(.18) rotate(8deg);opacity:0;filter:blur(5px)}@media(max-width:930px){.unified-fab{bottom:calc(82px + env(safe-area-inset-bottom))}}@media(prefers-reduced-motion:reduce){*,*:before,*:after{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}} -.pager{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin:0 0 14px}.pager button:disabled{opacity:.4;cursor:not-allowed}.pager span{color:var(--muted);font-size:13px}.section-heading{display:flex;align-items:center;gap:7px;margin:16px 0 10px;font-size:16px;line-height:1.35;color:#514a40}.section-heading svg{width:17px;height:17px;color:var(--accent)}.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.more-settings{border:1px solid var(--line);border-radius:10px;background:#fff}.more-settings summary{cursor:pointer;padding:11px 13px;color:#756d61;font-size:12px;font-weight:700}.more-settings-body{display:grid;gap:12px;padding:0 13px 13px}.more-settings-body>label{display:grid;grid-template-columns:80px 1fr;align-items:center;gap:7px;color:#756d61;font-size:12px;font-weight:650}.modal-mask{position:fixed;inset:0;z-index:80;background:rgba(45,38,31,.4);display:grid;place-items:center;padding:24px}.modal-box{width:min(360px,92vw);background:#fffdf8;border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);padding:22px;display:grid;gap:14px}.modal-box h3{margin:0;font-size:17px}.modal-box label{display:grid;gap:7px;font-size:12px;font-weight:650;color:#756d61}.modal-input{width:100%;border:1px solid var(--line);background:#fff;padding:11px;border-radius:9px;outline:none;font-size:16px}.modal-actions{display:flex;justify-content:flex-end;gap:8px}.countdown-view{display:grid;gap:16px;padding-bottom:36px}.countdown-hero{display:flex;align-items:end;justify-content:space-between;border-bottom:1px dashed var(--line);padding-bottom:12px}.countdown-hero h2{margin:2px 0 0;font-size:22px}.countdown-hero small{color:var(--muted);font-size:12px}.countdown-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}.countdown-card,.countdown-empty{background:#fff;border:1px solid var(--line);border-radius:16px;padding:16px;box-shadow:0 4px 18px rgba(81,61,38,.06)}.countdown-card.pinned{border-color:#f0c9b5;box-shadow:0 8px 22px rgba(241,90,41,.12)}.countdown-card-head{display:flex;align-items:center;gap:8px;color:#8d8276;font-size:12px}.countdown-icon{width:34px;height:34px;border-radius:12px;background:#fff5ef;display:grid;place-items:center;font-size:18px}.countdown-type{padding:4px 8px;border-radius:999px;background:#f6f0e5}.pinned-icon{margin-left:auto;color:var(--accent);width:16px;height:16px}.countdown-card h3{margin:16px 0 10px;font-size:20px}.countdown-number{display:flex;align-items:end;gap:4px;margin-bottom:6px}.countdown-number strong{font-size:38px;line-height:1;font-weight:800;color:#1f1a14}.countdown-number span{font-size:14px;color:#7a7165}.countdown-copy{display:block;font-size:14px;color:var(--accent);margin-bottom:10px}.countdown-card p{margin:0;color:var(--muted);font-size:12px}.countdown-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:15px}.countdown-actions button,.archived-toggle,.archived-countdowns button{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);background:#fff;border-radius:10px;padding:8px 11px;font-size:12px}.countdown-empty{border-style:dashed;color:#766d60;text-align:center;display:grid;gap:8px;justify-items:center}.countdown-empty svg{color:var(--accent)}.archived-toggle{justify-self:start}.archived-countdowns{display:grid;gap:10px}.archived-countdowns article{display:flex;align-items:center;gap:10px;background:#fff;border:1px solid var(--line);border-radius:14px;padding:12px 14px}.archived-countdowns article b{flex:1}.archived-countdowns article small{color:var(--muted)}.countdown-modal-mask{position:fixed;inset:0;z-index:90;background:rgba(45,38,31,.36);display:grid;place-items:center;padding:20px}.countdown-modal{width:min(420px,96vw);background:#fffdf8;border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow);padding:18px;display:grid;gap:12px}.countdown-modal header{display:flex;justify-content:space-between;align-items:start}.countdown-modal header small{color:var(--muted)}.countdown-modal header h3{margin:2px 0 0}.countdown-modal header button{min-width:44px;min-height:44px;border:0;background:var(--accent-soft);color:var(--accent);border-radius:50%;width:38px;height:38px}.countdown-modal label{display:grid;gap:6px;color:#675f54;font-size:12px;font-weight:650}.countdown-modal input,.countdown-modal select{border:1px solid var(--line);background:#fff;border-radius:10px;padding:11px 12px;outline:none}.countdown-title-fields{display:grid;grid-template-columns:72px 1fr;gap:8px}.countdown-modal footer{display:flex;justify-content:flex-end;gap:8px;padding-top:6px}@media(max-width:800px){.countdown-hero{align-items:center}.countdown-hero h2{font-size:19px}.countdown-grid{grid-template-columns:1fr}.countdown-number strong{font-size:34px}.countdown-modal-mask{place-items:end;padding:0}.countdown-modal{width:100%;border-radius:22px 22px 0 0;padding:18px 16px calc(18px + env(safe-area-inset-bottom));max-height:min(88dvh,760px);overflow:auto}.countdown-view{position:relative}} +.pager{display:flex;align-items:center;justify-content:flex-end;gap:10px;margin:0 0 14px}.pager button:disabled{opacity:.4;cursor:not-allowed}.pager span{color:var(--muted);font-size:13px}.section-heading{display:flex;align-items:center;gap:7px;margin:16px 0 10px;font-size:16px;line-height:1.35;color:#514a40}.section-heading svg{width:17px;height:17px;color:var(--accent)}.sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.more-settings{border:1px solid var(--line);border-radius:10px;background:#fff}.more-settings summary{cursor:pointer;padding:11px 13px;color:#756d61;font-size:12px;font-weight:700}.more-settings-body{display:grid;gap:12px;padding:0 13px 13px}.more-settings-body>label{display:grid;grid-template-columns:80px 1fr;align-items:center;gap:7px;color:#756d61;font-size:12px;font-weight:650}.modal-mask{position:fixed;inset:0;z-index:80;background:rgba(45,38,31,.4);display:grid;place-items:center;padding:24px}.modal-box{width:min(360px,92vw);background:#fffdf8;border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow);padding:22px;display:grid;gap:14px}.modal-box h3{margin:0;font-size:17px}.modal-box label{display:grid;gap:7px;font-size:12px;font-weight:650;color:#756d61}.modal-input{width:100%;border:1px solid var(--line);background:#fff;padding:11px;border-radius:9px;outline:none;font-size:16px}.modal-actions{display:flex;justify-content:flex-end;gap:8px}.countdown-view{display:grid;gap:16px;padding-bottom:36px}.countdown-hero{display:flex;align-items:end;justify-content:space-between;border-bottom:1px dashed var(--line);padding-bottom:12px}.countdown-hero h2{margin:2px 0 0;font-size:22px}.countdown-hero small{color:var(--muted);font-size:12px}.countdown-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}.countdown-card,.countdown-empty{background:#fff;border:1px solid var(--line);border-radius:16px;padding:16px;box-shadow:0 4px 18px rgba(81,61,38,.06)}.countdown-card.pinned{border-color:#f0c9b5;box-shadow:0 8px 22px rgba(241,90,41,.12)}.countdown-card-head{display:flex;align-items:center;gap:8px;color:#8d8276;font-size:12px}.countdown-icon{width:34px;height:34px;border-radius:12px;background:#fff5ef;display:grid;place-items:center;font-size:18px}.countdown-type{padding:4px 8px;border-radius:999px;background:#f6f0e5}.pinned-icon{margin-left:auto;color:var(--accent);width:16px;height:16px}.countdown-card h3{margin:16px 0 10px;font-size:20px}.countdown-number{display:flex;align-items:end;gap:4px;margin-bottom:6px}.countdown-number strong{font-size:38px;line-height:1;font-weight:800;color:#1f1a14}.countdown-number span{font-size:14px;color:#7a7165}.countdown-copy{display:block;font-size:14px;color:var(--accent);margin-bottom:10px}.countdown-card p{margin:0;color:var(--muted);font-size:12px}.countdown-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:15px}.countdown-actions button,.archived-toggle,.archived-countdowns button{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line);background:#fff;border-radius:10px;padding:8px 11px;font-size:12px}.countdown-empty{border-style:dashed;color:#766d60;text-align:center;display:grid;gap:8px;justify-items:center}.countdown-empty svg{color:var(--accent)}.archived-toggle{justify-self:start}.archived-countdowns{display:grid;gap:10px}.archived-countdowns article{display:flex;align-items:center;gap:10px;background:#fff;border:1px solid var(--line);border-radius:14px;padding:12px 14px}.archived-countdowns article b{flex:1}.archived-countdowns article small{color:var(--muted)}.countdown-modal-mask{position:fixed;inset:0;z-index:90;background:rgba(45,38,31,.36);display:grid;place-items:center;padding:20px}.countdown-modal{width:min(420px,96vw);background:#fffdf8;border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow);padding:18px;display:grid;gap:12px}.countdown-modal header{display:flex;justify-content:space-between;align-items:start}.countdown-modal header small{color:var(--muted)}.countdown-modal header h3{margin:2px 0 0}.countdown-modal header button{min-width:44px;min-height:44px;border:0;background:transparent;color:#766d60;border-radius:8px;width:44px;height:44px;display:grid;place-items:center}.countdown-modal label{display:grid;gap:6px;color:#675f54;font-size:12px;font-weight:650}.countdown-modal input,.countdown-modal select{border:1px solid var(--line);background:#fff;border-radius:10px;padding:11px 12px;outline:none}.countdown-title-fields{display:grid;grid-template-columns:72px 1fr;gap:8px}.countdown-modal footer{display:flex;justify-content:flex-end;gap:8px;padding-top:6px}@media(max-width:800px){.countdown-hero{align-items:center}.countdown-hero h2{font-size:19px}.countdown-grid{grid-template-columns:1fr}.countdown-number strong{font-size:34px}.countdown-modal-mask{place-items:end;padding:0}.countdown-modal{width:100%;border-radius:22px 22px 0 0;padding:18px 16px calc(18px + env(safe-area-inset-bottom));max-height:min(88dvh,760px);overflow:auto}.countdown-view{position:relative}} diff --git a/frontend/src/style.test.ts b/frontend/src/style.test.ts index 1081ad8..9c0908c 100644 --- a/frontend/src/style.test.ts +++ b/frontend/src/style.test.ts @@ -96,6 +96,21 @@ describe('unified floating add interaction', () => { expect(css).toContain('@media(max-width:930px){.unified-fab{bottom:calc(82px + env(safe-area-inset-bottom))}') }) + it('keeps the shared FAB visually simple', () => { + expect(floatingAdd).not.toContain('unified-fab-aura') + expect(floatingAdd).not.toContain('unified-fab-core') + expect(css).not.toContain('.unified-fab:before') + expect(css).not.toContain('@keyframes fab-aura') + expect(css).not.toContain('@keyframes fab-pulse') + expect(css).toMatch(/\.unified-fab\{[^}]*background:var\(--accent\)/) + }) + + it('keeps the countdown close button but removes its orange circular background', () => { + expect(countdownPanel).toContain('') + expect(css).toMatch(/\.countdown-modal header button\{[^}]*background:transparent/) + expect(css).toMatch(/\.countdown-modal header button\{[^}]*border-radius:8px/) + }) + it('removes inline create forms and opens the correct composer from the FAB', () => { expect(app).not.toContain('class="quick"') expect(mvpPanel).not.toContain('class="habit-create"')