Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(sheets): sticky +, wheel scroll, scrollbar polish (#355)

scott e34b25ac 8683e9ed

+101 -15
+20
CHANGELOG.md
··· 7 7 8 8 ## [Unreleased] 9 9 10 + ## [0.30.1] — 2026-04-10 11 + 12 + ### Changed 13 + - Sheet tabs: sticky "+" add-sheet button stays visible while tabs scroll horizontally (#601) 14 + - Sheet tabs: horizontal scroll via mouse wheel / trackpad vertical delta (#601) 15 + - Sheet tabs: scrollbar styling now matches the sheet-container for visual consistency, with `scrollbar-gutter: stable` to prevent layout shift (#601) 16 + - Sheet tabs: padding and spacing normalized to design tokens (#601) 17 + 18 + ## [0.30.0] — 2026-04-10 19 + 20 + ### Added 21 + - Calendar event reminders with configurable lead time (minutes/hours/days) and in-page browser notifications (#599) 22 + - Web Push notifications with VAPID key management and server-side reminder scheduler (#599) 23 + - ICS calendar subscription sync via server-side proxy with SSRF protection (#599) 24 + - Service worker push and notificationclick handling for native OS notifications (#599) 25 + - Notification permission banner on first load (#599) 26 + 27 + ### Fixed 28 + - Homepage no longer scrolls horizontally on mobile / PWA (#599) 29 + 10 30 ## [0.29.0] — 2026-04-09 11 31 12 32 ### Added
+1 -1
package.json
··· 1 1 { 2 2 "name": "tools", 3 - "version": "0.30.0", 3 + "version": "0.30.1", 4 4 "private": true, 5 5 "type": "module", 6 6 "main": "electron/main.js",
+65 -14
src/css/app.css
··· 3049 3049 .cell-align-center { justify-content: center; } 3050 3050 .cell-align-right { justify-content: flex-end; } 3051 3051 3052 - /* Sheet tabs */ 3052 + /* Sheet tabs — fixed-height strip with horizontally scrollable tabs 3053 + and a sticky "add sheet" button that stays visible while scrolling. */ 3053 3054 .sheet-tabs { 3054 3055 display: flex; 3055 3056 align-items: center; 3056 3057 flex-wrap: nowrap; 3057 - gap: 1px; 3058 + gap: var(--space-xs); 3058 3059 padding: var(--space-xs) var(--space-sm); 3059 3060 border-top: 1px solid var(--color-border); 3060 3061 background: var(--color-surface); ··· 3062 3063 overflow-x: auto; 3063 3064 overflow-y: hidden; 3064 3065 scrollbar-width: thin; 3065 - scrollbar-color: var(--color-border) transparent; 3066 + scrollbar-color: oklch(0.78 0.01 75) transparent; 3067 + } 3068 + [data-theme="dark"] .sheet-tabs { 3069 + scrollbar-color: oklch(0.35 0.01 75) transparent; 3070 + } 3071 + @media (prefers-color-scheme: dark) { 3072 + :root:not([data-theme="light"]) .sheet-tabs { 3073 + scrollbar-color: oklch(0.35 0.01 75) transparent; 3074 + } 3075 + } 3076 + 3077 + /* Match the sheet-container scrollbar so both strips feel uniform */ 3078 + .sheet-tabs::-webkit-scrollbar { 3079 + height: 8px; 3080 + } 3081 + .sheet-tabs::-webkit-scrollbar-track { 3082 + background: transparent; 3083 + } 3084 + .sheet-tabs::-webkit-scrollbar-thumb { 3085 + background: oklch(0.78 0.01 75); 3086 + border-radius: 4px; 3087 + border: 2px solid transparent; 3088 + background-clip: padding-box; 3089 + } 3090 + .sheet-tabs::-webkit-scrollbar-thumb:hover { 3091 + background: oklch(0.68 0.01 75); 3092 + background-clip: padding-box; 3093 + } 3094 + [data-theme="dark"] .sheet-tabs::-webkit-scrollbar-thumb { 3095 + background: oklch(0.35 0.01 75); 3096 + background-clip: padding-box; 3097 + } 3098 + [data-theme="dark"] .sheet-tabs::-webkit-scrollbar-thumb:hover { 3099 + background: oklch(0.45 0.01 75); 3100 + background-clip: padding-box; 3066 3101 } 3067 - .sheet-tabs::-webkit-scrollbar { height: 4px; } 3068 - .sheet-tabs::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 2px; } 3069 - .sheet-tabs::-webkit-scrollbar-track { background: transparent; } 3102 + .sheet-tabs::-webkit-scrollbar-corner { 3103 + background: transparent; 3104 + } 3070 3105 3071 3106 .sheet-tab { 3072 3107 font-family: var(--font-body); 3073 3108 font-size: 0.75rem; 3074 3109 font-weight: 500; 3075 - padding: 0.3rem 0.8rem; 3110 + padding: var(--space-xs) var(--space-sm); 3076 3111 background: transparent; 3077 3112 border: 1px solid transparent; 3078 3113 border-radius: var(--radius-sm); 3079 3114 color: var(--color-text-muted); 3080 3115 cursor: pointer; 3081 - transition: all var(--transition-fast); 3116 + transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast); 3082 3117 position: relative; 3083 3118 flex-shrink: 0; 3084 3119 white-space: nowrap; 3120 + line-height: 1.4; 3085 3121 } 3086 3122 .sheet-tab:hover { background: var(--color-hover); color: var(--color-text); } 3087 3123 .sheet-tab.active { ··· 3117 3153 border-radius: 1px; 3118 3154 } 3119 3155 3156 + /* Sticky "add sheet" button — stays pinned to the right edge of the 3157 + visible strip even while the tab list is scrolled. A small inset 3158 + shadow on the left visually separates it from tabs scrolling past. */ 3120 3159 .sheet-tab-add { 3121 - font-size: 0.85rem; 3122 - padding: 0.2rem 0.5rem; 3123 - background: transparent; 3124 - border: none; 3125 - color: var(--color-text-faint); 3160 + position: sticky; 3161 + right: 0; 3162 + flex-shrink: 0; 3163 + font-size: 0.9rem; 3164 + line-height: 1; 3165 + padding: var(--space-xs) var(--space-sm); 3166 + margin-left: auto; 3167 + background: var(--color-surface); 3168 + border: 1px solid transparent; 3169 + color: var(--color-text-muted); 3126 3170 cursor: pointer; 3127 3171 border-radius: var(--radius-sm); 3172 + transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast); 3173 + /* Fade tabs out as they scroll under the sticky add button */ 3174 + box-shadow: -12px 0 12px -8px var(--color-surface); 3128 3175 } 3129 - .sheet-tab-add:hover { background: var(--color-hover); color: var(--color-text); } 3176 + .sheet-tab-add:hover { 3177 + background: var(--color-hover); 3178 + color: var(--color-text); 3179 + border-color: var(--color-border); 3180 + } 3130 3181 3131 3182 /* Sheet tab color bar — colored underline indicator */ 3132 3183 .sheet-tab-color-bar {
+15
src/sheets/main.ts
··· 252 252 const sheetContainer = document.getElementById('sheet-container'); 253 253 const sheetTabsContainer = document.getElementById('sheet-tabs'); 254 254 255 + // Translate vertical wheel into horizontal scroll on the sheet-tabs strip, 256 + // so users can flick through tabs with a trackpad or mouse wheel. We only 257 + // hijack the event when the user is scrolling mostly-vertically and the 258 + // strip actually has horizontal overflow to consume. 259 + if (sheetTabsContainer) { 260 + sheetTabsContainer.addEventListener('wheel', (e: WheelEvent) => { 261 + const canScrollX = sheetTabsContainer.scrollWidth > sheetTabsContainer.clientWidth; 262 + if (!canScrollX) return; 263 + if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) { 264 + e.preventDefault(); 265 + sheetTabsContainer.scrollLeft += e.deltaY; 266 + } 267 + }, { passive: false }); 268 + } 269 + 255 270 // --- Grid rendering (extracted to grid-rendering.ts) --- 256 271 function _gridRenderingDeps() { 257 272 return {