claudecode-omc 5.6.6 → 5.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/.local/skills/THIRD_PARTY_LICENSES/AvdLee-SwiftUI-Agent-Skill.LICENSE +21 -0
  2. package/.local/skills/THIRD_PARTY_LICENSES/Dimillian-Skills.LICENSE +21 -0
  3. package/.local/skills/THIRD_PARTY_LICENSES/README.md +36 -0
  4. package/.local/skills/THIRD_PARTY_LICENSES/twostraws-swiftui-agent-skill.LICENSE +21 -0
  5. package/.local/skills/h5-to-swiftui/SKILL.md +201 -0
  6. package/.local/skills/h5-to-swiftui/assets/calibration/README.md +176 -0
  7. package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/index.html +52 -0
  8. package/.local/skills/h5-to-swiftui/assets/calibration/h5-twin/style.css +133 -0
  9. package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Package.swift +26 -0
  10. package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin/Sources/CalibrationScreen/CalibrationScreen.swift +142 -0
  11. package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Package.swift +32 -0
  12. package/.local/skills/h5-to-swiftui/assets/calibration/swiftui-twin-divergent/Sources/CalibrationScreenDivergent/CalibrationScreenDivergent.swift +122 -0
  13. package/.local/skills/h5-to-swiftui/assets/calibration/tokens.json +42 -0
  14. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/index.html +14 -0
  15. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/package.json +20 -0
  16. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/001.json +96 -0
  17. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/public/api/articles/index.json +89 -0
  18. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.jsx +22 -0
  19. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/App.module.css +11 -0
  20. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.jsx +53 -0
  21. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/ArticleCard.module.css +139 -0
  22. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.jsx +37 -0
  23. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/NavBar.module.css +72 -0
  24. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.jsx +30 -0
  25. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TagCloud.module.css +50 -0
  26. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.jsx +159 -0
  27. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/components/TrendChart.module.css +21 -0
  28. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/main.jsx +12 -0
  29. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.jsx +182 -0
  30. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/ArticleScreen.module.css +294 -0
  31. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.jsx +147 -0
  32. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/screens/FeedScreen.module.css +161 -0
  33. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/global.css +50 -0
  34. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/src/styles/tokens.css +103 -0
  35. package/.local/skills/h5-to-swiftui/assets/sample-h5-react/vite.config.js +6 -0
  36. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/data/tasks.js +67 -0
  37. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/index.html +26 -0
  38. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/router.js +73 -0
  39. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/detail.js +164 -0
  40. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/home.js +53 -0
  41. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/screens/list.js +87 -0
  42. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/app.css +342 -0
  43. package/.local/skills/h5-to-swiftui/assets/sample-h5-vanilla/styles/tokens.css +68 -0
  44. package/.local/skills/h5-to-swiftui/references/css-to-swiftui-map.md +205 -0
  45. package/.local/skills/h5-to-swiftui/references/design-token-extraction.md +209 -0
  46. package/.local/skills/h5-to-swiftui/references/high-risk-triage.md +209 -0
  47. package/.local/skills/h5-to-swiftui/references/render-equivalence-calibration.md +193 -0
  48. package/.local/skills/h5-to-swiftui/references/stack-detection.md +160 -0
  49. package/.local/skills/h5-to-swiftui/references/visual-diff-loop-protocol.md +365 -0
  50. package/.local/skills/h5-to-swiftui/scripts/_calib-consts.mjs +150 -0
  51. package/.local/skills/h5-to-swiftui/scripts/_imglib.mjs +547 -0
  52. package/.local/skills/h5-to-swiftui/scripts/_provenance.mjs +123 -0
  53. package/.local/skills/h5-to-swiftui/scripts/calibrate-render.mjs +625 -0
  54. package/.local/skills/h5-to-swiftui/scripts/capture-reference.mjs +386 -0
  55. package/.local/skills/h5-to-swiftui/scripts/detect-stack.mjs +305 -0
  56. package/.local/skills/h5-to-swiftui/scripts/evaluate-convergence.mjs +1093 -0
  57. package/.local/skills/h5-to-swiftui/scripts/extract-tokens.mjs +600 -0
  58. package/.local/skills/h5-to-swiftui/scripts/mark-overlay.mjs +379 -0
  59. package/.local/skills/h5-to-swiftui/scripts/pixel-diff.mjs +530 -0
  60. package/.local/skills/h5-to-swiftui/scripts/sim-screenshot.sh +544 -0
  61. package/.local/skills/ios-debugger-agent/SKILL.md +51 -0
  62. package/.local/skills/ios-debugger-agent/agents/openai.yaml +4 -0
  63. package/.local/skills/swift-concurrency-expert/SKILL.md +105 -0
  64. package/.local/skills/swift-concurrency-expert/agents/openai.yaml +4 -0
  65. package/.local/skills/swift-concurrency-expert/references/approachable-concurrency.md +63 -0
  66. package/.local/skills/swift-concurrency-expert/references/swift-6-2-concurrency.md +272 -0
  67. package/.local/skills/swift-concurrency-expert/references/swiftui-concurrency-tour-wwdc.md +33 -0
  68. package/.local/skills/swiftui-expert-skill/SKILL.md +162 -0
  69. package/.local/skills/swiftui-expert-skill/references/accessibility-patterns.md +215 -0
  70. package/.local/skills/swiftui-expert-skill/references/animation-advanced.md +403 -0
  71. package/.local/skills/swiftui-expert-skill/references/animation-basics.md +284 -0
  72. package/.local/skills/swiftui-expert-skill/references/animation-transitions.md +326 -0
  73. package/.local/skills/swiftui-expert-skill/references/charts-accessibility.md +135 -0
  74. package/.local/skills/swiftui-expert-skill/references/charts.md +602 -0
  75. package/.local/skills/swiftui-expert-skill/references/focus-patterns.md +299 -0
  76. package/.local/skills/swiftui-expert-skill/references/image-optimization.md +203 -0
  77. package/.local/skills/swiftui-expert-skill/references/latest-apis.md +488 -0
  78. package/.local/skills/swiftui-expert-skill/references/layout-best-practices.md +266 -0
  79. package/.local/skills/swiftui-expert-skill/references/liquid-glass.md +423 -0
  80. package/.local/skills/swiftui-expert-skill/references/list-patterns.md +446 -0
  81. package/.local/skills/swiftui-expert-skill/references/macos-scenes.md +318 -0
  82. package/.local/skills/swiftui-expert-skill/references/macos-views.md +357 -0
  83. package/.local/skills/swiftui-expert-skill/references/macos-window-styling.md +303 -0
  84. package/.local/skills/swiftui-expert-skill/references/performance-patterns.md +403 -0
  85. package/.local/skills/swiftui-expert-skill/references/scroll-patterns.md +293 -0
  86. package/.local/skills/swiftui-expert-skill/references/sheet-navigation-patterns.md +363 -0
  87. package/.local/skills/swiftui-expert-skill/references/state-management.md +388 -0
  88. package/.local/skills/swiftui-expert-skill/references/text-patterns.md +32 -0
  89. package/.local/skills/swiftui-expert-skill/references/trace-analysis.md +295 -0
  90. package/.local/skills/swiftui-expert-skill/references/trace-recording.md +134 -0
  91. package/.local/skills/swiftui-expert-skill/references/view-structure.md +780 -0
  92. package/.local/skills/swiftui-expert-skill/scripts/__pycache__/analyze_trace.cpython-313.pyc +0 -0
  93. package/.local/skills/swiftui-expert-skill/scripts/__pycache__/record_trace.cpython-313.pyc +0 -0
  94. package/.local/skills/swiftui-expert-skill/scripts/analyze_trace.py +301 -0
  95. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__init__.py +1 -0
  96. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/__init__.cpython-313.pyc +0 -0
  97. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/causes.cpython-313.pyc +0 -0
  98. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/correlate.cpython-313.pyc +0 -0
  99. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/events.cpython-313.pyc +0 -0
  100. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hangs.cpython-313.pyc +0 -0
  101. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/hitches.cpython-313.pyc +0 -0
  102. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/summary.cpython-313.pyc +0 -0
  103. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/swiftui.cpython-313.pyc +0 -0
  104. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/time_profiler.cpython-313.pyc +0 -0
  105. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xctrace.cpython-313.pyc +0 -0
  106. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/__pycache__/xml_utils.cpython-313.pyc +0 -0
  107. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/causes.py +187 -0
  108. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/correlate.py +179 -0
  109. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/events.py +291 -0
  110. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hangs.py +108 -0
  111. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/hitches.py +145 -0
  112. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/summary.py +243 -0
  113. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/swiftui.py +195 -0
  114. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/time_profiler.py +135 -0
  115. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xctrace.py +117 -0
  116. package/.local/skills/swiftui-expert-skill/scripts/instruments_parser/xml_utils.py +224 -0
  117. package/.local/skills/swiftui-expert-skill/scripts/record_trace.py +252 -0
  118. package/.local/skills/swiftui-liquid-glass/SKILL.md +90 -0
  119. package/.local/skills/swiftui-liquid-glass/agents/openai.yaml +4 -0
  120. package/.local/skills/swiftui-liquid-glass/references/liquid-glass.md +280 -0
  121. package/.local/skills/swiftui-performance-audit/SKILL.md +106 -0
  122. package/.local/skills/swiftui-performance-audit/agents/openai.yaml +4 -0
  123. package/.local/skills/swiftui-performance-audit/references/code-smells.md +150 -0
  124. package/.local/skills/swiftui-performance-audit/references/demystify-swiftui-performance-wwdc23.md +46 -0
  125. package/.local/skills/swiftui-performance-audit/references/optimizing-swiftui-performance-instruments.md +29 -0
  126. package/.local/skills/swiftui-performance-audit/references/profiling-intake.md +44 -0
  127. package/.local/skills/swiftui-performance-audit/references/report-template.md +47 -0
  128. package/.local/skills/swiftui-performance-audit/references/understanding-hangs-in-your-app.md +33 -0
  129. package/.local/skills/swiftui-performance-audit/references/understanding-improving-swiftui-performance.md +52 -0
  130. package/.local/skills/swiftui-pro/SKILL.md +108 -0
  131. package/.local/skills/swiftui-pro/agents/openai.yaml +10 -0
  132. package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.png +0 -0
  133. package/.local/skills/swiftui-pro/assets/swiftui-pro-icon.svg +29 -0
  134. package/.local/skills/swiftui-pro/references/accessibility.md +13 -0
  135. package/.local/skills/swiftui-pro/references/api.md +39 -0
  136. package/.local/skills/swiftui-pro/references/data.md +43 -0
  137. package/.local/skills/swiftui-pro/references/design.md +32 -0
  138. package/.local/skills/swiftui-pro/references/hygiene.md +9 -0
  139. package/.local/skills/swiftui-pro/references/navigation.md +14 -0
  140. package/.local/skills/swiftui-pro/references/performance.md +46 -0
  141. package/.local/skills/swiftui-pro/references/swift.md +56 -0
  142. package/.local/skills/swiftui-pro/references/views.md +36 -0
  143. package/.local/skills/swiftui-ui-patterns/SKILL.md +95 -0
  144. package/.local/skills/swiftui-ui-patterns/agents/openai.yaml +4 -0
  145. package/.local/skills/swiftui-ui-patterns/references/app-wiring.md +201 -0
  146. package/.local/skills/swiftui-ui-patterns/references/async-state.md +96 -0
  147. package/.local/skills/swiftui-ui-patterns/references/components-index.md +50 -0
  148. package/.local/skills/swiftui-ui-patterns/references/controls.md +57 -0
  149. package/.local/skills/swiftui-ui-patterns/references/deeplinks.md +66 -0
  150. package/.local/skills/swiftui-ui-patterns/references/focus.md +90 -0
  151. package/.local/skills/swiftui-ui-patterns/references/form.md +97 -0
  152. package/.local/skills/swiftui-ui-patterns/references/grids.md +71 -0
  153. package/.local/skills/swiftui-ui-patterns/references/haptics.md +71 -0
  154. package/.local/skills/swiftui-ui-patterns/references/input-toolbar.md +51 -0
  155. package/.local/skills/swiftui-ui-patterns/references/lightweight-clients.md +93 -0
  156. package/.local/skills/swiftui-ui-patterns/references/list.md +86 -0
  157. package/.local/skills/swiftui-ui-patterns/references/loading-placeholders.md +38 -0
  158. package/.local/skills/swiftui-ui-patterns/references/macos-settings.md +71 -0
  159. package/.local/skills/swiftui-ui-patterns/references/matched-transitions.md +59 -0
  160. package/.local/skills/swiftui-ui-patterns/references/media.md +73 -0
  161. package/.local/skills/swiftui-ui-patterns/references/menu-bar.md +101 -0
  162. package/.local/skills/swiftui-ui-patterns/references/navigationstack.md +159 -0
  163. package/.local/skills/swiftui-ui-patterns/references/overlay.md +45 -0
  164. package/.local/skills/swiftui-ui-patterns/references/performance.md +62 -0
  165. package/.local/skills/swiftui-ui-patterns/references/previews.md +48 -0
  166. package/.local/skills/swiftui-ui-patterns/references/scroll-reveal.md +133 -0
  167. package/.local/skills/swiftui-ui-patterns/references/scrollview.md +87 -0
  168. package/.local/skills/swiftui-ui-patterns/references/searchable.md +71 -0
  169. package/.local/skills/swiftui-ui-patterns/references/sheets.md +155 -0
  170. package/.local/skills/swiftui-ui-patterns/references/split-views.md +72 -0
  171. package/.local/skills/swiftui-ui-patterns/references/tabview.md +114 -0
  172. package/.local/skills/swiftui-ui-patterns/references/theming.md +71 -0
  173. package/.local/skills/swiftui-ui-patterns/references/title-menus.md +93 -0
  174. package/.local/skills/swiftui-ui-patterns/references/top-bar.md +49 -0
  175. package/.local/skills/swiftui-view-refactor/SKILL.md +202 -0
  176. package/.local/skills/swiftui-view-refactor/agents/openai.yaml +4 -0
  177. package/.local/skills/swiftui-view-refactor/references/mv-patterns.md +161 -0
  178. package/bundled/manifest.json +1 -1
  179. package/package.json +1 -1
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
+ import styles from './ArticleCard.module.css';
4
+
5
+ export default function ArticleCard({ article }) {
6
+ const navigate = useNavigate();
7
+ const { id, title, summary, author, publishedAt, readingTime, tag, imageAlt } = article;
8
+
9
+ const formattedDate = new Date(publishedAt).toLocaleDateString('en-US', {
10
+ month: 'short',
11
+ day: 'numeric',
12
+ year: 'numeric',
13
+ });
14
+
15
+ return (
16
+ <article
17
+ className={styles.card}
18
+ onClick={() => navigate(`/article/${id}`)}
19
+ role="button"
20
+ tabIndex={0}
21
+ onKeyDown={e => e.key === 'Enter' && navigate(`/article/${id}`)}
22
+ >
23
+ <div className={styles.imagePlaceholder} aria-label={imageAlt}>
24
+ <span className={styles.imagePlaceholderText}>{imageAlt}</span>
25
+ </div>
26
+
27
+ <div className={styles.body}>
28
+ <div className={styles.meta}>
29
+ <span className={styles.tag}>{tag}</span>
30
+ <span className={styles.readingTime}>{readingTime} min read</span>
31
+ </div>
32
+
33
+ <h2 className={styles.title}>{title}</h2>
34
+ <p className={styles.summary}>{summary}</p>
35
+
36
+ <div className={styles.footer}>
37
+ <div className={styles.authorArea}>
38
+ <div className={styles.avatar} aria-hidden="true">
39
+ {author.name.slice(0, 1)}
40
+ </div>
41
+ <div className={styles.authorInfo}>
42
+ <span className={styles.authorName}>{author.name}</span>
43
+ <span className={styles.authorRole}>{author.role}</span>
44
+ </div>
45
+ </div>
46
+ <time className={styles.date} dateTime={publishedAt}>
47
+ {formattedDate}
48
+ </time>
49
+ </div>
50
+ </div>
51
+ </article>
52
+ );
53
+ }
@@ -0,0 +1,139 @@
1
+ .card {
2
+ background-color: var(--color-bg-card);
3
+ border-radius: var(--radius-lg);
4
+ box-shadow: var(--shadow-card);
5
+ overflow: hidden;
6
+ cursor: pointer;
7
+ transition: box-shadow var(--duration-normal) var(--easing-default),
8
+ transform var(--duration-normal) var(--easing-default);
9
+ display: flex;
10
+ flex-direction: column;
11
+ }
12
+
13
+ .card:hover {
14
+ box-shadow: var(--shadow-elevated);
15
+ transform: translateY(-2px);
16
+ }
17
+
18
+ .card:focus-visible {
19
+ outline: 2px solid var(--color-accent);
20
+ outline-offset: 2px;
21
+ }
22
+
23
+ .imagePlaceholder {
24
+ width: 100%;
25
+ aspect-ratio: 16 / 9;
26
+ background-color: var(--color-bg-secondary);
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ overflow: hidden;
31
+ border-bottom: 1px solid var(--color-divider);
32
+ }
33
+
34
+ .imagePlaceholderText {
35
+ font-size: var(--font-size-xs);
36
+ color: var(--color-text-caption);
37
+ text-align: center;
38
+ padding: var(--space-2);
39
+ }
40
+
41
+ .body {
42
+ padding: var(--space-5);
43
+ display: flex;
44
+ flex-direction: column;
45
+ gap: var(--space-3);
46
+ flex-grow: 1;
47
+ }
48
+
49
+ .meta {
50
+ display: flex;
51
+ flex-direction: row;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ }
55
+
56
+ .tag {
57
+ font-size: var(--font-size-xs);
58
+ font-weight: var(--font-weight-semibold);
59
+ color: var(--color-text-accent);
60
+ text-transform: uppercase;
61
+ letter-spacing: 0.6px;
62
+ }
63
+
64
+ .readingTime {
65
+ font-size: var(--font-size-xs);
66
+ color: var(--color-text-caption);
67
+ }
68
+
69
+ .title {
70
+ font-family: var(--font-family-display);
71
+ font-size: var(--font-size-subhead);
72
+ font-weight: var(--font-weight-bold);
73
+ color: var(--color-text-primary);
74
+ line-height: var(--line-height-tight);
75
+ letter-spacing: -0.3px;
76
+ }
77
+
78
+ .summary {
79
+ font-size: var(--font-size-body);
80
+ color: var(--color-text-secondary);
81
+ line-height: var(--line-height-normal);
82
+ display: -webkit-box;
83
+ -webkit-line-clamp: 3;
84
+ -webkit-box-orient: vertical;
85
+ overflow: hidden;
86
+ }
87
+
88
+ .footer {
89
+ display: flex;
90
+ flex-direction: row;
91
+ align-items: center;
92
+ justify-content: space-between;
93
+ margin-top: auto;
94
+ padding-top: var(--space-3);
95
+ border-top: 1px solid var(--color-divider);
96
+ }
97
+
98
+ .authorArea {
99
+ display: flex;
100
+ flex-direction: row;
101
+ align-items: center;
102
+ gap: var(--space-2);
103
+ }
104
+
105
+ .avatar {
106
+ width: 32px;
107
+ height: 32px;
108
+ border-radius: var(--radius-full);
109
+ background-color: var(--color-accent);
110
+ color: var(--color-text-on-accent);
111
+ font-size: var(--font-size-sm);
112
+ font-weight: var(--font-weight-bold);
113
+ display: flex;
114
+ align-items: center;
115
+ justify-content: center;
116
+ flex-shrink: 0;
117
+ }
118
+
119
+ .authorInfo {
120
+ display: flex;
121
+ flex-direction: column;
122
+ gap: 1px;
123
+ }
124
+
125
+ .authorName {
126
+ font-size: var(--font-size-sm);
127
+ font-weight: var(--font-weight-semibold);
128
+ color: var(--color-text-primary);
129
+ }
130
+
131
+ .authorRole {
132
+ font-size: var(--font-size-xs);
133
+ color: var(--color-text-caption);
134
+ }
135
+
136
+ .date {
137
+ font-size: var(--font-size-xs);
138
+ color: var(--color-text-caption);
139
+ }
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import { useNavigate, useLocation } from 'react-router-dom';
3
+ import styles from './NavBar.module.css';
4
+
5
+ const TABS = [
6
+ { id: 'feed', label: 'Feed', path: '/' },
7
+ ];
8
+
9
+ export default function NavBar({ activeTab, onTabChange }) {
10
+ const navigate = useNavigate();
11
+ const location = useLocation();
12
+
13
+ function handleTab(tab) {
14
+ onTabChange(tab.id);
15
+ navigate(tab.path);
16
+ }
17
+
18
+ return (
19
+ <header className={styles.navbar}>
20
+ <div className={styles.logoArea}>
21
+ <span className={styles.logoMark}>C</span>
22
+ <span className={styles.logoText}>Chronicle</span>
23
+ </div>
24
+ <nav className={styles.tabs}>
25
+ {TABS.map(tab => (
26
+ <button
27
+ key={tab.id}
28
+ className={`${styles.tab} ${location.pathname === tab.path ? styles.tabActive : ''}`}
29
+ onClick={() => handleTab(tab)}
30
+ >
31
+ {tab.label}
32
+ </button>
33
+ ))}
34
+ </nav>
35
+ </header>
36
+ );
37
+ }
@@ -0,0 +1,72 @@
1
+ .navbar {
2
+ display: flex;
3
+ flex-direction: row;
4
+ align-items: center;
5
+ justify-content: space-between;
6
+ padding: var(--space-3) var(--space-6);
7
+ background-color: var(--color-bg-primary);
8
+ border-bottom: 1px solid var(--color-border);
9
+ position: sticky;
10
+ top: 0;
11
+ z-index: 100;
12
+ }
13
+
14
+ .logoArea {
15
+ display: flex;
16
+ flex-direction: row;
17
+ align-items: center;
18
+ gap: var(--space-2);
19
+ }
20
+
21
+ .logoMark {
22
+ width: 28px;
23
+ height: 28px;
24
+ border-radius: var(--radius-sm);
25
+ background-color: var(--color-accent);
26
+ color: var(--color-text-on-accent);
27
+ font-family: var(--font-family-display);
28
+ font-size: var(--font-size-sm);
29
+ font-weight: var(--font-weight-bold);
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ }
34
+
35
+ .logoText {
36
+ font-family: var(--font-family-display);
37
+ font-size: var(--font-size-headline);
38
+ font-weight: var(--font-weight-semibold);
39
+ color: var(--color-text-primary);
40
+ letter-spacing: -0.5px;
41
+ }
42
+
43
+ .tabs {
44
+ display: flex;
45
+ flex-direction: row;
46
+ gap: var(--space-1);
47
+ }
48
+
49
+ .tab {
50
+ padding: var(--space-2) var(--space-4);
51
+ border-radius: var(--radius-full);
52
+ font-size: var(--font-size-sm);
53
+ font-weight: var(--font-weight-medium);
54
+ color: var(--color-text-secondary);
55
+ transition: background-color var(--duration-fast) var(--easing-default),
56
+ color var(--duration-fast) var(--easing-default);
57
+ }
58
+
59
+ .tab:hover {
60
+ background-color: var(--color-bg-secondary);
61
+ color: var(--color-text-primary);
62
+ }
63
+
64
+ .tabActive {
65
+ background-color: var(--color-accent);
66
+ color: var(--color-text-on-accent);
67
+ }
68
+
69
+ .tabActive:hover {
70
+ background-color: var(--color-accent-hover);
71
+ color: var(--color-text-on-accent);
72
+ }
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import styles from './TagCloud.module.css';
3
+
4
+ /**
5
+ * TagCloud — a flex-wrap tag gallery with non-uniform item widths.
6
+ *
7
+ * CSS uses `flex-wrap: wrap` with variable-length tag labels.
8
+ * This pattern has NO stock SwiftUI equivalent:
9
+ * "flex-wrap: wrap → HStack never wraps; LazyHGrid/LazyVGrid are scroll
10
+ * containers, not inline wrapping layouts" (css-to-swiftui-map.md)
11
+ *
12
+ * CUSTOM-LAYOUT: flex-wrap:wrap — the variable-width tags must reflow onto
13
+ * multiple rows at arbitrary breakpoints determined by available width, which
14
+ * HStack cannot do. SwiftUI port requires the FlowLayout custom Layout protocol.
15
+ */
16
+ export default function TagCloud({ tags, onTagClick, selectedTag }) {
17
+ return (
18
+ <div className={styles.cloud}>
19
+ {tags.map(tag => (
20
+ <button
21
+ key={tag}
22
+ className={`${styles.tag} ${selectedTag === tag ? styles.tagSelected : ''}`}
23
+ onClick={() => onTagClick(tag === selectedTag ? null : tag)}
24
+ >
25
+ {tag}
26
+ </button>
27
+ ))}
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,50 @@
1
+ /* CUSTOM-LAYOUT: flex-wrap:wrap
2
+ *
3
+ * flex-wrap: wrap causes tags with non-uniform widths to reflow onto multiple
4
+ * rows. The break points are data-driven (label length) and width-driven
5
+ * (viewport). HStack in SwiftUI never wraps — this MUST use a custom Layout
6
+ * (FlowLayout) implementing the Layout protocol (iOS 16+).
7
+ *
8
+ * Trigger quote from css-to-swiftui-map.md:
9
+ * "flex-wrap: wrap → Custom Layout protocol (iOS 16+) — FlowLayout
10
+ * No LazyHGrid/LazyVGrid equivalent for true wrapping"
11
+ */
12
+ .cloud {
13
+ display: flex;
14
+ flex-direction: row;
15
+ flex-wrap: wrap; /* CUSTOM-LAYOUT: flex-wrap:wrap */
16
+ gap: var(--space-2) var(--space-2);
17
+ padding: var(--space-4) 0;
18
+ }
19
+
20
+ .tag {
21
+ display: inline-flex;
22
+ align-items: center;
23
+ padding: var(--space-1) var(--space-3);
24
+ border-radius: var(--radius-full);
25
+ background-color: var(--color-bg-tag);
26
+ color: var(--color-text-accent);
27
+ font-size: var(--font-size-sm);
28
+ font-weight: var(--font-weight-medium);
29
+ white-space: nowrap;
30
+ border: 1px solid transparent;
31
+ transition: background-color var(--duration-fast) var(--easing-default),
32
+ border-color var(--duration-fast) var(--easing-default);
33
+ cursor: pointer;
34
+ }
35
+
36
+ .tag:hover {
37
+ background-color: var(--color-bg-secondary);
38
+ border-color: var(--color-border);
39
+ }
40
+
41
+ .tagSelected {
42
+ background-color: var(--color-accent);
43
+ color: var(--color-text-on-accent);
44
+ border-color: var(--color-accent);
45
+ }
46
+
47
+ .tagSelected:hover {
48
+ background-color: var(--color-accent-hover);
49
+ border-color: var(--color-accent-hover);
50
+ }
@@ -0,0 +1,159 @@
1
+ import React, { useRef, useEffect } from 'react';
2
+ import styles from './TrendChart.module.css';
3
+
4
+ /**
5
+ * TrendChart — WebGL sparkline chart rendered on a <canvas> element.
6
+ *
7
+ * {/* TIER3: WebGL canvas — uses WebGLRenderingContext to draw a sparkline.
8
+ * The rendering pipeline is entirely GPU-driven via custom GLSL shaders.
9
+ * There is NO SwiftUI equivalent for arbitrary WebGL content.
10
+ * SwiftUI port options:
11
+ * (a) Replace with a native Swift Charts (iOS 16+) line mark — preferred
12
+ * if data semantics are equivalent.
13
+ * (b) Wrap in WKWebView if exact visual must be preserved (accepts
14
+ * partial fidelity loss: no ProMotion, extra process, no Dynamic Type).
15
+ * Risk triage MUST flag this surface and NOT silently generate wrong code.
16
+ * */
17
+ export default function TrendChart({ data, label, color = '#0071e3' }) {
18
+ const canvasRef = useRef(null);
19
+
20
+ useEffect(() => {
21
+ const canvas = canvasRef.current;
22
+ if (!canvas) return;
23
+
24
+ // Attempt WebGL; fall back to 2D canvas if unavailable (e.g. jsdom in tests)
25
+ const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
26
+
27
+ if (!gl) {
28
+ // Graceful 2D fallback (no WebGL in test env)
29
+ const ctx = canvas.getContext('2d');
30
+ if (!ctx || !data?.length) return;
31
+ drawFallback2D(ctx, canvas, data, color);
32
+ return;
33
+ }
34
+
35
+ // WebGL sparkline — minimal shader pair
36
+ const vsSource = `
37
+ attribute vec2 a_position;
38
+ uniform vec2 u_resolution;
39
+ void main() {
40
+ vec2 clip = (a_position / u_resolution) * 2.0 - 1.0;
41
+ gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);
42
+ }
43
+ `;
44
+
45
+ const fsSource = `
46
+ precision mediump float;
47
+ uniform vec4 u_color;
48
+ void main() {
49
+ gl_FragColor = u_color;
50
+ }
51
+ `;
52
+
53
+ const vs = compileShader(gl, gl.VERTEX_SHADER, vsSource);
54
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, fsSource);
55
+ if (!vs || !fs) return;
56
+
57
+ const program = gl.createProgram();
58
+ gl.attachShader(program, vs);
59
+ gl.attachShader(program, fs);
60
+ gl.linkProgram(program);
61
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) return;
62
+
63
+ gl.useProgram(program);
64
+
65
+ // Map data to canvas coordinates
66
+ const w = canvas.width;
67
+ const h = canvas.height;
68
+ const min = Math.min(...data);
69
+ const max = Math.max(...data);
70
+ const range = max - min || 1;
71
+ const pad = 8;
72
+
73
+ const vertices = new Float32Array(data.length * 2);
74
+ data.forEach((v, i) => {
75
+ vertices[i * 2] = pad + (i / (data.length - 1)) * (w - pad * 2);
76
+ vertices[i * 2 + 1] = h - pad - ((v - min) / range) * (h - pad * 2);
77
+ });
78
+
79
+ const buf = gl.createBuffer();
80
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
81
+ gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
82
+
83
+ const posLoc = gl.getAttribLocation(program, 'a_position');
84
+ gl.enableVertexAttribArray(posLoc);
85
+ gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);
86
+
87
+ const resLoc = gl.getUniformLocation(program, 'u_resolution');
88
+ gl.uniform2f(resLoc, w, h);
89
+
90
+ const colLoc = gl.getUniformLocation(program, 'u_color');
91
+ const [r, g, b] = hexToRgb(color);
92
+ gl.uniform4f(colLoc, r, g, b, 1.0);
93
+
94
+ gl.viewport(0, 0, w, h);
95
+ gl.clearColor(0, 0, 0, 0);
96
+ gl.clear(gl.COLOR_BUFFER_BIT);
97
+ gl.lineWidth(2);
98
+ gl.drawArrays(gl.LINE_STRIP, 0, data.length);
99
+
100
+ return () => {
101
+ gl.deleteProgram(program);
102
+ gl.deleteBuffer(buf);
103
+ };
104
+ }, [data, color]);
105
+
106
+ return (
107
+ <div className={styles.chartWrapper}>
108
+ {label && <span className={styles.chartLabel}>{label}</span>}
109
+ <canvas
110
+ ref={canvasRef}
111
+ width={280}
112
+ height={80}
113
+ className={styles.canvas}
114
+ aria-label={`Trend chart: ${label}`}
115
+ role="img"
116
+ />
117
+ </div>
118
+ );
119
+ }
120
+
121
+ // ── helpers ──────────────────────────────────────────────────────────────────
122
+
123
+ function compileShader(gl, type, source) {
124
+ const shader = gl.createShader(type);
125
+ gl.shaderSource(shader, source);
126
+ gl.compileShader(shader);
127
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
128
+ gl.deleteShader(shader);
129
+ return null;
130
+ }
131
+ return shader;
132
+ }
133
+
134
+ function hexToRgb(hex) {
135
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
136
+ return result
137
+ ? [parseInt(result[1], 16) / 255, parseInt(result[2], 16) / 255, parseInt(result[3], 16) / 255]
138
+ : [0, 0.44, 0.89];
139
+ }
140
+
141
+ function drawFallback2D(ctx, canvas, data, color) {
142
+ const w = canvas.width;
143
+ const h = canvas.height;
144
+ const min = Math.min(...data);
145
+ const max = Math.max(...data);
146
+ const range = max - min || 1;
147
+ const pad = 8;
148
+
149
+ ctx.clearRect(0, 0, w, h);
150
+ ctx.beginPath();
151
+ ctx.strokeStyle = color;
152
+ ctx.lineWidth = 2;
153
+ data.forEach((v, i) => {
154
+ const x = pad + (i / (data.length - 1)) * (w - pad * 2);
155
+ const y = h - pad - ((v - min) / range) * (h - pad * 2);
156
+ i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
157
+ });
158
+ ctx.stroke();
159
+ }
@@ -0,0 +1,21 @@
1
+ .chartWrapper {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--space-2);
5
+ }
6
+
7
+ .chartLabel {
8
+ font-size: var(--font-size-xs);
9
+ font-weight: var(--font-weight-semibold);
10
+ color: var(--color-text-secondary);
11
+ text-transform: uppercase;
12
+ letter-spacing: 0.5px;
13
+ }
14
+
15
+ .canvas {
16
+ display: block;
17
+ border-radius: var(--radius-sm);
18
+ background-color: var(--color-bg-secondary);
19
+ width: 100%;
20
+ height: 80px;
21
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import { BrowserRouter } from 'react-router-dom';
4
+ import App from './App.jsx';
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')).render(
7
+ <React.StrictMode>
8
+ <BrowserRouter>
9
+ <App />
10
+ </BrowserRouter>
11
+ </React.StrictMode>
12
+ );