Commit Graph
411 Commits
Author SHA1 Message Date
phranck e9cea4b2bf perf: preload stargazer avatars for instant Stargazers panel 2026-02-04 21:57:19 +01:00
phranck c891e6ca6e feat: fall back to cached weeklyActivity from weekly-activity-cache.json when /stats/commit_activity is unavailable 2026-02-04 21:54:39 +01:00
phranck 4f57e49d0b Fix: Marquee hover stops only for visible avatars; prevent heatmap popover flicker 2026-02-04 21:42:22 +01:00
phranck abfc3a05e9 feat(dashboard): add iOS-like swipe/drag with momentum to marquee
- Touch swipe on mobile, mouse drag on desktop
- Momentum scrolling with friction-based deceleration
- Click vs drag detection (5px threshold)
- Cursor grab/grabbing visual feedback
- Popover visibility bounded to 5% edge margin
2026-02-04 21:28:42 +01:00
phranck a6930f17be feat(dashboard): add stargazer avatar marquee with horizontal scroll
- Create generic AvatarMarquee component for horizontal scrolling avatars
- Extract StargazerPopoverContent for social links display
- Refactor StargazersPanel to use AvatarMarquee
- Reorder StatCards: Stars, Contributors, Forks, Releases | Commits, Branches, Open PRs, Merged PRs
- Add fade-in/out masks at edges
- Smooth brake/accelerate on hover
- Popover visibility bounded to visible area
- Add cursor-pointer to Refresh button
- Performance: memoized callbacks, stable props
- Add .env.local to .gitignore
2026-02-04 21:23:15 +01:00
phranck c78d439c4d feat(dashboard): add social account lookup for stargazers
- Add multi-source social search (Keybase, about.me, Linktree, GitHub bio/blog)
- Implement avatar comparison and cross-platform verification
- Create GitHub Action for scheduled cache updates (2h incremental, weekly full)
- Display Mastodon, Bluesky, Twitter links in stargazer popover
- Add smooth hover animations with invisible bridge for better UX
- Add social-overrides.json for manual account mappings
2026-02-04 20:09:55 +01:00
phranck 304860ba37 Add stargazer Mastodon lookup plan, translate dashboard plan to English 2026-02-04 18:38:53 +01:00
phranck 51e02fb306 Add Ko-fi donation link to README 2026-02-04 18:15:37 +01:00
phranck 3cedf75376 Update README, added Copilot instructions file 2026-02-04 17:16:14 +01:00
phranck c6b4b3c77c Chore: Add project docs, plans, and Gource visualization
- .claude/: Agent rules (restructured), session context, permissions
- plans/: State Identity, Render Pipeline, Spinner, Toast, Focus Sections, Palette, Memoization, Dashboard
- papers/: Gource documentation
- Gource: Config, render script, avatar, background audio, history video
- to-dos.md: Task tracker with priorities
- .gitignore: Update exclusions
2026-02-04 16:47:04 +01:00
phranck df564fba42 Perf: Preload hard-drive-boot audio for faster playback 2026-02-04 16:11:12 +01:00
phranck cfc81d6172 Redeploy: Remove exposed token from build 2026-02-04 15:22:25 +01:00
phranck d58796f7ea Trigger redeploy without exposed token 2026-02-04 15:12:06 +01:00
phranck 756f23bc1f Fix: Disable StatePropertyWrapperTests on Linux due to Swift runtime race condition 2026-02-04 14:56:48 +01:00
phranck 3b1f25855e Fix: Only add Authorization header when token is non-empty 2026-02-04 14:49:54 +01:00
phranck 60e241699e update README 2026-02-04 14:37:37 +01:00
phranck 668029077d update README by adding a warning message 2026-02-04 14:35:34 +01:00
phranck a0f31a4e5e Merge pull request #73 from phranck/feat/project-dashboard
Feat: Unified IconBadge component & Dashboard rate limit
2026-02-04 14:32:17 +01:00
phranck f9b106e509 Feat: Unified IconBadge component for SF Symbols
- Add IconBadge component with sm/md/lg variants
- Refactor FeatureCard to use IconBadge
- Update ArchHighlight and RepoInfo for consistency
- Add DASHBOARD_GITHUB_TOKEN to CI for rate limit
2026-02-04 14:18:54 +01:00
phranck 5b3f23b213 Merge pull request #72 from phranck/feat/project-dashboard
add dashboard page
2026-02-04 03:24:24 +01:00
phranck 5855f10154 add dashboard page 2026-02-04 03:20:39 +01:00
Frank Gregor a930f9ffa8 Chore: Update test count badge to 503 tests [skip ci] 2026-02-03 23:43:34 +00:00
phranck f2f88a7a8f Merge pull request #71 from phranck/feat/subtree-memoization
Feat: Subtree memoization via EquatableView (render pipeline phase 5)
2026-02-04 00:28:11 +01:00
phranck 443aad2a90 Fix: Remove global RenderNotifier mutation from EquatableView test to prevent Linux race condition 2026-02-04 00:17:15 +01:00
phranck a705414c82 Feat: Add subtree memoization via EquatableView (render pipeline phase 5)
Equatable views can opt into render caching with .equatable(). On cache hit,
the entire subtree is skipped and the cached FrameBuffer returned directly.
Cache is cleared on every @State change; GC removes stale entries per frame.
2026-02-03 23:08:17 +01:00
phranck 2973d11cb9 Merge pull request #70 from phranck/refactor/palette-consolidation
Refactor: Consolidate 6 palette structs into PalettePreset enum + SystemPalette
2026-02-03 22:33:44 +01:00
phranck cb00b29d56 Refactor: Nest PalettePreset as SystemPalette.Preset 2026-02-03 22:31:33 +01:00
phranck ea44f1fd13 Refactor: Consolidate 6 palette structs into PalettePreset enum + SystemPalette 2026-02-03 22:27:59 +01:00
phranck 3f83562b69 Chore: Update test count badge to 485 tests [skip ci] 2026-02-03 21:16:59 +00:00
phranck 476b23a0f4 Merge pull request #69 from phranck/refactor/extension-separation
Refactor: Extension separation across all source files
2026-02-03 22:14:46 +01:00
phranck 7cfa99f6f6 Fix: SwiftLint empty_count violation — use isEmpty instead of count > 0 2026-02-03 22:07:54 +01:00
phranck df9cb27c88 Refactor: Apply extension separation rule to all 35 Swift source files — move ~135 functions from type bodies into access-level-prefixed extensions (public/internal/private) 2026-02-03 22:05:46 +01:00
phranck df4ee3253b Feat: AppHeader — framework-managed header bar rendered outside the view tree
AppHeader is rendered at the top of the terminal by RenderLoop, similar to
StatusBar at the bottom. Views declare header content via .appHeader { }
ViewBuilder modifier. Supports standard (thin divider) and block (half-block
with appHeaderBackground) appearance. Hidden when no content is set.
Diff cache invalidates on header height changes to prevent ghosting.
2026-02-03 21:21:41 +01:00
phranck f77cd8bdec Chore: Unified file headers across all Swift files
Update IDETemplateMacros.plist and replace headers in 136 Swift files with
new format: 🖥️ TUIKit — Terminal UI Kit for Swift. Remove sdsd.swift template draft.
2026-02-03 20:48:29 +01:00
phranck 55fbfb0f4f Refactor: Dimmed overlay background with palette colors, ANSI-aware compositing, centered overlays
DimmedModifier now strips all ANSI codes and ornament characters, re-renders
with uniform palette.foregroundTertiary on palette.overlayBackground.
FrameBuffer.insertOverlay preserves base ANSI styling via ansiAwarePrefix/Suffix
and leadingANSISequences restoration. Overlays center relative to terminal size
with -2 vertical offset. Alert presets no longer color borders — only titles.
2026-02-03 20:48:14 +01:00
phranck 7be9c05343 Refactor: Single-line bracket buttons, palette-based styles, brighter elevated background 2026-02-03 18:27:04 +01:00
phranck db03e4e41c Refactor: HSL-based color system for all palettes — lighter/darker preserve hue, unified baseHue architecture 2026-02-03 18:11:39 +01:00
phranck dc6e3b6437 Merge pull request #68 from phranck/feat/focus-sections
Feat: Focus Sections with StatusBar Cascading
2026-02-03 17:12:47 +01:00
phranck 55ff393682 Test: Focus sections, Color.lerp, PulseTimer, StatusBar cascading, border indicator
26 new tests across 4 new suites (456 → 482 tests, 80 → 84 suites):
- Focus Section Tests: section registration, Tab/Shift+Tab cycling,
  Up/Down within section, activateSection, beginRenderPass preservation,
  endRenderPass fallback, single-section backward compat
- Color lerp Tests: phase boundaries, midpoint interpolation, clamping,
  ANSI-to-RGB conversion
- PulseTimer Tests: initial state, phase range, start/stop balance
- StatusBar Cascading Tests: merge includes global, replace excludes global,
  child wins on conflict, clearSectionItems, fallback without items
- BorderRenderer Focus Indicator Tests: indicator presence, width preservation,
  title + indicator combination
2026-02-03 17:03:59 +01:00
phranck 93958e0308 Feat: Modal/Alert as focus sections — replace focusManager.clear() with section activation
ModalPresentationModifier and AlertPresentationModifier now register
dedicated focus sections (__modal__/__alert__) and activate them instead
of clearing the entire FocusManager. Modal buttons register in the modal
section. When the modal closes, the section is not re-registered and
endRenderPass() falls back to the previous active section automatically.
2026-02-03 16:59:57 +01:00
phranck b078661e7e Feat: StatusBar cascading — .statusBarItems(.merge/.replace) composition API
New declarative StatusBar item composition system:
- StatusBarItemComposition enum (.merge/.replace)
- .statusBarItems(.replace) { } for cascade barriers (modals)
- .statusBarItems { } defaults to .merge (combines with parent items)
- StatusBarState resolves items per active focus section:
  .replace = only section items, .merge = section + global (section wins)
- Section items rebuilt each frame via clearSectionItems()/registerSectionItems()
- Legacy context: push/pop API preserved for backward compatibility
2026-02-03 16:58:33 +01:00
phranck 818fc5d198 Feat: Breathing focus indicator — pulsing ● in active section border
New components:
- PulseTimer: GCD-based timer driving a sine-wave phase (0→1→0, 3s cycle)
- Color.lerp(): RGB linear interpolation between two colors
- BorderRenderer: standardTopBorder accepts focusIndicatorColor for ● rendering

Integration:
- FocusSectionModifier computes interpolated accent color when section is active
- RenderContext carries pulsePhase (from PulseTimer) and focusIndicatorColor
- BorderedView and ContainerView consume the indicator color on first border,
  then nil it out so nested borders don't duplicate the indicator
- AppRunner owns PulseTimer, passes phase to RenderLoop each frame
2026-02-03 16:52:50 +01:00
phranck b7f51e1b85 Fix: Preserve focus state across render passes
RenderLoop called focusManager.clear() every frame, which reset the
active section and focused element. Replaced with beginRenderPass()
(clears sections/focusables for re-registration) and endRenderPass()
(validates preserved activeSectionID/focusedID against re-registered
sections, falls back to first available if removed from tree).
2026-02-03 16:47:20 +01:00
phranck 8ebda6371e Feat: Section-aware navigation — Up/Down cycles within active section
FocusManager.dispatchKeyEvent now intercepts Up/Down arrows to navigate
between focusable elements within the active section. Tab/Shift+Tab
continues to cycle between sections. Views needing custom Up/Down
handling (e.g. Menu) register via KeyEventDispatcher (Layer 2), which
takes priority over the FocusManager (Layer 3).
2026-02-03 16:43:34 +01:00
phranck 2a3c96e782 Feat: Add FocusSection registration — section-aware FocusManager and .focusSection() modifier
FocusManager reorganized from flat focusable list to section-based architecture.
Each section groups its own focusable elements. Tab cycles sections when multiple
exist, falls back to within-section cycling for single section (backward compat).

New types: FocusSection, FocusSectionModifier
New API: .focusSection("id"), register(_:inSection:), activateNextSection()
RenderContext carries activeFocusSectionID for child registration routing.
2026-02-03 16:41:37 +01:00
phranck 384ebeb7f7 Merge pull request #67 from phranck/feat/overlays-demo-redesign
Feat: Redesign OverlaysPage with interactive demo menu
2026-02-03 13:46:57 +01:00
phranck 5975820ed4 Test: Fix flaky state tests by eliminating global RenderNotifier mutation
AppStateTests: Tests AppState as isolated instances without touching
RenderNotifier.current. Removed .serialized (no shared state).

StateStorageIdentityTests: Replaced testEnvironment() with testStorage()
that only creates a StateStorage. No longer sets RenderNotifier.current.
StateBox.didSet harmlessly calls setNeedsRender() on the default global.

StatePropertyTests: The one test that needs RenderNotifier.current
(stateTriggerRender) now swaps it atomically — set, mutate, check,
restore in a single synchronous sequence with no yield points.

Root cause: All three suites ran .serialized internally but parallel
to each other. Since RenderNotifier.current is a process-global static
variable, concurrent writes caused one suite to overwrite another's
AppState, making needsRender checks fail intermittently.
2026-02-03 13:45:08 +01:00
phranck 186e444fcc Fix: ESC closes modal via StatusBar context switching
OverlaysPage now manages its own StatusBar items based on modal state:
- Modal open: ESC → close modal, Enter → dismiss
- Modal closed: ESC → back to menu, arrows → nav, Enter → show

Removes redundant ESC handlers from Modal/AlertPresentationModifier.
The correct approach is context-aware StatusBar items, not multiple
competing ESC handlers.
2026-02-03 12:35:07 +01:00
phranck ca9a0cf49c Fix: Modal focus isolation, ESC dismiss, footer layout, palette colors
- Wire FocusManager.dispatchKeyEvent() into InputHandler as Layer 3
  (Tab/Shift+Tab navigation, Enter/Space button activation)
- Modal/Alert presenters isolate base content from focus/key systems
  using RenderContext.isolatedForBackground() so only modal buttons
  receive focus and key events
- ESC automatically dismisses any modal or alert (framework-level)
- Fix ContainerView footer layout: Spacer() now fills correctly by
  constraining footer context to actual inner width
- Remove body background color from standard style containers
  (only block style uses distinct section backgrounds)
- Replace all hardcoded ANSI colors with palette semantic colors
  (.palette.warning/error/info/success) in Alert presets and example app
2026-02-03 12:28:39 +01:00
phranck 7e69b9e924 Fix: Right-align dismiss buttons in all overlay demo variants
Changed dismissButton to use HStack { Spacer(); Button } pattern for
consistent right-alignment across all alerts, dialogs, and modals.

Also simplified Alert preset usage — replaced explicit Alert<Button>.warning()
with standard Alert() initializer to avoid generic type inference issues.
2026-02-03 02:22:46 +01:00