@usequark/quark-create-app 1.23.11

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 (237) hide show
  1. package/README.md +210 -0
  2. package/package.json +56 -0
  3. package/src/dependabot-config.test.js +128 -0
  4. package/src/deploy/adapters/iac.js +203 -0
  5. package/src/deploy/adapters/index.js +27 -0
  6. package/src/deploy/adapters/railway.js +508 -0
  7. package/src/deploy/adapters/railway.test.js +318 -0
  8. package/src/deploy/contract.js +59 -0
  9. package/src/deploy/deploy.integration.test.js +183 -0
  10. package/src/deploy/deploy.js +430 -0
  11. package/src/deploy/deploy.test.js +105 -0
  12. package/src/deploy/discovery.js +115 -0
  13. package/src/deploy/discovery.test.js +141 -0
  14. package/src/deploy/index.js +38 -0
  15. package/src/deploy/inspect.js +130 -0
  16. package/src/index.js +2920 -0
  17. package/src/mobile-template.test.js +232 -0
  18. package/src/prepare-hooks.test.js +535 -0
  19. package/src/scaffold-guards.test.js +140 -0
  20. package/src/scaffold-output.test.js +228 -0
  21. package/src/template-scripts.test.js +160 -0
  22. package/src/utils.js +77 -0
  23. package/src/utils.test.js +95 -0
  24. package/src/worker-dockerfile.test.js +85 -0
  25. package/templates/base-project/.cursor/rules/quark.mdc +172 -0
  26. package/templates/base-project/.dockerignore +14 -0
  27. package/templates/base-project/.env.railway.example +87 -0
  28. package/templates/base-project/.github/copilot-instructions.md +65 -0
  29. package/templates/base-project/.github/dependabot.yml +31 -0
  30. package/templates/base-project/.github/skills/project-context/SKILL.md +109 -0
  31. package/templates/base-project/.github/workflows/ci.yml +116 -0
  32. package/templates/base-project/.github/workflows/dependabot-auto-merge.yml +22 -0
  33. package/templates/base-project/.github/workflows/install-windows.yml +27 -0
  34. package/templates/base-project/.github/workflows/release.yml +67 -0
  35. package/templates/base-project/.railway/railway.ts +40 -0
  36. package/templates/base-project/CLAUDE.md +163 -0
  37. package/templates/base-project/MAIN.md +21 -0
  38. package/templates/base-project/README.md +164 -0
  39. package/templates/base-project/apps/web/.env.example +99 -0
  40. package/templates/base-project/apps/web/Dockerfile +38 -0
  41. package/templates/base-project/apps/web/biome.json +8 -0
  42. package/templates/base-project/apps/web/jsconfig.json +9 -0
  43. package/templates/base-project/apps/web/next.config.js +154 -0
  44. package/templates/base-project/apps/web/package.json +42 -0
  45. package/templates/base-project/apps/web/postcss.config.mjs +7 -0
  46. package/templates/base-project/apps/web/public/.well-known/security.txt +3 -0
  47. package/templates/base-project/apps/web/public/quark.svg +47 -0
  48. package/templates/base-project/apps/web/scripts/prepare-standalone.mjs +71 -0
  49. package/templates/base-project/apps/web/src/app/_components/AsciiPanel.js +103 -0
  50. package/templates/base-project/apps/web/src/app/_components/HealthIndicator.js +85 -0
  51. package/templates/base-project/apps/web/src/app/_components/HomeThemeToggle.js +63 -0
  52. package/templates/base-project/apps/web/src/app/_components/QuarkAnimation.js +168 -0
  53. package/templates/base-project/apps/web/src/app/_components/SyncedPanels.js +212 -0
  54. package/templates/base-project/apps/web/src/app/_components/UmamiReplayRecorder.js +198 -0
  55. package/templates/base-project/apps/web/src/app/_components/UmamiWebVitals.js +39 -0
  56. package/templates/base-project/apps/web/src/app/api/auth/[...nextauth]/route.js +7 -0
  57. package/templates/base-project/apps/web/src/app/api/auth/apple/route.js +82 -0
  58. package/templates/base-project/apps/web/src/app/api/auth/google/route.js +59 -0
  59. package/templates/base-project/apps/web/src/app/api/auth/refresh/route.js +48 -0
  60. package/templates/base-project/apps/web/src/app/api/auth/register/route.js +63 -0
  61. package/templates/base-project/apps/web/src/app/api/auth/token/route.js +44 -0
  62. package/templates/base-project/apps/web/src/app/api/csrf/route.js +40 -0
  63. package/templates/base-project/apps/web/src/app/api/device/register/route.js +57 -0
  64. package/templates/base-project/apps/web/src/app/api/error-handler.js +23 -0
  65. package/templates/base-project/apps/web/src/app/api/files/[id]/route.js +89 -0
  66. package/templates/base-project/apps/web/src/app/api/files/route.js +120 -0
  67. package/templates/base-project/apps/web/src/app/api/health/route.js +160 -0
  68. package/templates/base-project/apps/web/src/app/api/users/[id]/route.js +54 -0
  69. package/templates/base-project/apps/web/src/app/api/users/me/route.js +67 -0
  70. package/templates/base-project/apps/web/src/app/api/users/route.js +45 -0
  71. package/templates/base-project/apps/web/src/app/auth/error/page.js +83 -0
  72. package/templates/base-project/apps/web/src/app/auth/forgot-password/page.js +58 -0
  73. package/templates/base-project/apps/web/src/app/auth/provider-loading.js +25 -0
  74. package/templates/base-project/apps/web/src/app/auth/register/RegisterPageClient.js +340 -0
  75. package/templates/base-project/apps/web/src/app/auth/register/page.js +17 -0
  76. package/templates/base-project/apps/web/src/app/auth/signin/SignInPageClient.js +230 -0
  77. package/templates/base-project/apps/web/src/app/auth/signin/page.js +10 -0
  78. package/templates/base-project/apps/web/src/app/favicon.ico +0 -0
  79. package/templates/base-project/apps/web/src/app/global-error.js +58 -0
  80. package/templates/base-project/apps/web/src/app/globals.css +1166 -0
  81. package/templates/base-project/apps/web/src/app/icon.svg +47 -0
  82. package/templates/base-project/apps/web/src/app/layout.js +57 -0
  83. package/templates/base-project/apps/web/src/app/manifest.js +12 -0
  84. package/templates/base-project/apps/web/src/app/not-found.js +39 -0
  85. package/templates/base-project/apps/web/src/app/page.js +262 -0
  86. package/templates/base-project/apps/web/src/app/robots.js +23 -0
  87. package/templates/base-project/apps/web/src/app/sitemap.js +14 -0
  88. package/templates/base-project/apps/web/src/lib/analytics/umami-before-send.js +29 -0
  89. package/templates/base-project/apps/web/src/lib/analytics/umami-config.js +95 -0
  90. package/templates/base-project/apps/web/src/lib/analytics/umami-csp.js +24 -0
  91. package/templates/base-project/apps/web/src/lib/analytics/umami-marketing.js +131 -0
  92. package/templates/base-project/apps/web/src/lib/analytics/umami-replay.js +204 -0
  93. package/templates/base-project/apps/web/src/lib/analytics/umami-web-vitals.js +237 -0
  94. package/templates/base-project/apps/web/src/lib/analytics/umami.js +57 -0
  95. package/templates/base-project/apps/web/src/lib/auth-middleware.js +82 -0
  96. package/templates/base-project/apps/web/src/lib/auth-signup.js +5 -0
  97. package/templates/base-project/apps/web/src/lib/auth.js +191 -0
  98. package/templates/base-project/apps/web/src/lib/csrf-cookie.js +11 -0
  99. package/templates/base-project/apps/web/src/lib/jwt.js +84 -0
  100. package/templates/base-project/apps/web/src/lib/load-crm-config.js +35 -0
  101. package/templates/base-project/apps/web/src/lib/normalize-auth-request.js +33 -0
  102. package/templates/base-project/apps/web/src/lib/proxy-auth.js +80 -0
  103. package/templates/base-project/apps/web/src/lib/seo/indexing.js +25 -0
  104. package/templates/base-project/apps/web/src/lib/seo/site-metadata.js +74 -0
  105. package/templates/base-project/apps/web/src/lib/sitemap-entries.js +22 -0
  106. package/templates/base-project/apps/web/src/preflight.js +55 -0
  107. package/templates/base-project/apps/web/src/proxy.js +328 -0
  108. package/templates/base-project/biome.json +52 -0
  109. package/templates/base-project/docker-compose.override.yml +17 -0
  110. package/templates/base-project/docker-compose.yml +37 -0
  111. package/templates/base-project/docs/FIRST_FEATURE.md +74 -0
  112. package/templates/base-project/docs/START_HERE.md +70 -0
  113. package/templates/base-project/docs/adr/README.md +42 -0
  114. package/templates/base-project/package.json +58 -0
  115. package/templates/base-project/packages/db/package.json +38 -0
  116. package/templates/base-project/packages/db/prisma/migrations/20260202061128_initial/migration.sql +202 -0
  117. package/templates/base-project/packages/db/prisma/migrations/migration_lock.toml +3 -0
  118. package/templates/base-project/packages/db/prisma/schema.prisma +161 -0
  119. package/templates/base-project/packages/db/prisma/seed.js +152 -0
  120. package/templates/base-project/packages/db/prisma.config.js +27 -0
  121. package/templates/base-project/packages/db/src/client.js +75 -0
  122. package/templates/base-project/packages/db/src/connection.js +44 -0
  123. package/templates/base-project/packages/db/src/context.js +275 -0
  124. package/templates/base-project/packages/db/src/index.js +5 -0
  125. package/templates/base-project/packages/db/src/ping.js +66 -0
  126. package/templates/base-project/packages/db/src/queries.js +292 -0
  127. package/templates/base-project/packages/db/src/schemas.js +30 -0
  128. package/templates/base-project/packages/db/src/umami.js +299 -0
  129. package/templates/base-project/pnpm-workspace.yaml +20 -0
  130. package/templates/base-project/scripts/check-loading.mjs +49 -0
  131. package/templates/base-project/scripts/check-standards.mjs +186 -0
  132. package/templates/base-project/scripts/clean-workspace.mjs +479 -0
  133. package/templates/base-project/scripts/dev-preflight.mjs +48 -0
  134. package/templates/base-project/scripts/doctor.js +408 -0
  135. package/templates/base-project/scripts/prepare.js +490 -0
  136. package/templates/base-project/scripts/run-tests.mjs +71 -0
  137. package/templates/base-project/skills/add-dashboard/SKILL.md +28 -0
  138. package/templates/base-project/skills/add-endpoint/SKILL.md +29 -0
  139. package/templates/base-project/skills/add-model/SKILL.md +28 -0
  140. package/templates/base-project/skills/ecommerce/SKILL.md +224 -0
  141. package/templates/base-project/skills/ecommerce-cart/SKILL.md +193 -0
  142. package/templates/base-project/skills/ecommerce-catalog/SKILL.md +179 -0
  143. package/templates/base-project/skills/ecommerce-checkout/SKILL.md +195 -0
  144. package/templates/base-project/skills/i18n/SKILL.md +211 -0
  145. package/templates/base-project/skills/payment/SKILL.md +280 -0
  146. package/templates/base-project/skills/quark-skills/SKILL.md +37 -0
  147. package/templates/base-project/turbo.json +143 -0
  148. package/templates/config/package.json +20 -0
  149. package/templates/config/src/app-url.js +134 -0
  150. package/templates/config/src/environment.js +284 -0
  151. package/templates/config/src/index.js +16 -0
  152. package/templates/config/src/load-config.js +157 -0
  153. package/templates/config/src/rate-limit.js +136 -0
  154. package/templates/config/src/redis.js +43 -0
  155. package/templates/config/src/validate-env.js +532 -0
  156. package/templates/jobs/README.md +52 -0
  157. package/templates/jobs/package.json +9 -0
  158. package/templates/jobs/src/definitions.js +13 -0
  159. package/templates/jobs/src/index.js +1 -0
  160. package/templates/mobile/.env.example +16 -0
  161. package/templates/mobile/CHECKLIST.md +40 -0
  162. package/templates/mobile/README.md +130 -0
  163. package/templates/mobile/app/(app)/_layout.tsx +83 -0
  164. package/templates/mobile/app/(app)/index.tsx +147 -0
  165. package/templates/mobile/app/(app)/profile.tsx +204 -0
  166. package/templates/mobile/app/(app)/settings.tsx +80 -0
  167. package/templates/mobile/app/(auth)/_layout.tsx +10 -0
  168. package/templates/mobile/app/(auth)/sign-in.tsx +140 -0
  169. package/templates/mobile/app/(auth)/sign-up.tsx +178 -0
  170. package/templates/mobile/app/+not-found.tsx +32 -0
  171. package/templates/mobile/app/_layout.tsx +18 -0
  172. package/templates/mobile/app.json +47 -0
  173. package/templates/mobile/assets/adaptive-icon.png +0 -0
  174. package/templates/mobile/assets/icon.png +0 -0
  175. package/templates/mobile/assets/notification-icon.png +0 -0
  176. package/templates/mobile/assets/splash.png +0 -0
  177. package/templates/mobile/biome.json +27 -0
  178. package/templates/mobile/components/AuthGate.tsx +19 -0
  179. package/templates/mobile/components/ThemeProvider.tsx +23 -0
  180. package/templates/mobile/eas.json +29 -0
  181. package/templates/mobile/hooks/use-auth.ts +127 -0
  182. package/templates/mobile/lib/api-client.ts +138 -0
  183. package/templates/mobile/lib/api.ts +83 -0
  184. package/templates/mobile/lib/auth-providers-google.ts +74 -0
  185. package/templates/mobile/lib/auth-providers.ts +74 -0
  186. package/templates/mobile/lib/auth.ts +100 -0
  187. package/templates/mobile/lib/config.ts +14 -0
  188. package/templates/mobile/lib/errors.ts +46 -0
  189. package/templates/mobile/lib/notifications.ts +77 -0
  190. package/templates/mobile/lib/storage.ts +25 -0
  191. package/templates/mobile/lib/theme-tokens.ts +16 -0
  192. package/templates/mobile/package.json +37 -0
  193. package/templates/mobile/tsconfig.json +10 -0
  194. package/templates/pwa/app/_components/PWARegister.js +15 -0
  195. package/templates/pwa/app/manifest.js +32 -0
  196. package/templates/pwa/public/sw.js +72 -0
  197. package/templates/ui/README.md +44 -0
  198. package/templates/ui/package.json +21 -0
  199. package/templates/ui/src/badge.js +23 -0
  200. package/templates/ui/src/button.js +111 -0
  201. package/templates/ui/src/card.js +128 -0
  202. package/templates/ui/src/checkbox.js +20 -0
  203. package/templates/ui/src/container.js +13 -0
  204. package/templates/ui/src/dialog.js +137 -0
  205. package/templates/ui/src/error-banner.js +15 -0
  206. package/templates/ui/src/footer.js +239 -0
  207. package/templates/ui/src/form-field.integration-test.js +142 -0
  208. package/templates/ui/src/form-field.js +50 -0
  209. package/templates/ui/src/index.js +24 -0
  210. package/templates/ui/src/input.js +11 -0
  211. package/templates/ui/src/label.js +14 -0
  212. package/templates/ui/src/lightbox.integration-test.js +167 -0
  213. package/templates/ui/src/lightbox.js +243 -0
  214. package/templates/ui/src/logo.js +52 -0
  215. package/templates/ui/src/navbar.js +602 -0
  216. package/templates/ui/src/password-input.js +31 -0
  217. package/templates/ui/src/rich-text.js +514 -0
  218. package/templates/ui/src/select.js +317 -0
  219. package/templates/ui/src/skeleton.js +10 -0
  220. package/templates/ui/src/spinner.js +31 -0
  221. package/templates/ui/src/table.js +169 -0
  222. package/templates/ui/src/textarea.js +11 -0
  223. package/templates/ui/src/theme-constants.js +24 -0
  224. package/templates/ui/src/theme.js +196 -0
  225. package/templates/ui/src/toast.js +206 -0
  226. package/templates/worker/Dockerfile +64 -0
  227. package/templates/worker/README.md +56 -0
  228. package/templates/worker/package.json +36 -0
  229. package/templates/worker/src/config/pricing.js +46 -0
  230. package/templates/worker/src/handlers/email-job-validation.js +36 -0
  231. package/templates/worker/src/handlers/email.js +98 -0
  232. package/templates/worker/src/handlers/files.js +59 -0
  233. package/templates/worker/src/handlers/index.js +20 -0
  234. package/templates/worker/src/handlers/push-notification.js +234 -0
  235. package/templates/worker/src/index.js +505 -0
  236. package/templates/worker/src/lib/railway.js +438 -0
  237. package/templates/worker/src/lib/tokens.js +81 -0
@@ -0,0 +1,243 @@
1
+ "use client";
2
+ import { ChevronLeft, ChevronRight, X } from "lucide-react";
3
+ import React, { useEffect, useRef, useState } from "react";
4
+
5
+ const BACKDROP_CLS =
6
+ "absolute inset-0 z-0 bg-[--lightbox-backdrop] px-3 py-4 transition-opacity duration-200 ease-out sm:px-6 sm:py-8 cursor-pointer";
7
+ const DIALOG_CLS =
8
+ "relative z-10 mx-auto flex h-full w-full max-w-6xl flex-col p-3 transition-all duration-200 ease-out sm:p-5";
9
+ const NAV_BTN_CLS =
10
+ "inline-flex items-center gap-1.5 rounded-[--radius-default] border border-[--lightbox-btn-border] px-3 py-1.5 text-sm font-medium text-[--lightbox-btn-text] transition-colors duration-200 hover:bg-[--lightbox-btn-hover-bg] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--lightbox-btn-ring)] cursor-pointer";
11
+ const CLOSE_BTN_CLS =
12
+ "rounded-[--radius-default] border border-[--lightbox-btn-border] font-medium text-[--lightbox-btn-text] transition-colors duration-200 hover:bg-[--lightbox-btn-hover-bg] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--lightbox-btn-ring)] flex items-center cursor-pointer";
13
+
14
+ const IMG_CLS =
15
+ "max-h-[72vh] w-auto max-w-full rounded-[--radius-default] object-contain transition-all duration-200 ease-out";
16
+
17
+ export function Lightbox({
18
+ src,
19
+ alt = "",
20
+ caption = "",
21
+ onClose,
22
+ onPrevious,
23
+ onNext,
24
+ showPrevious = false,
25
+ showNext = false,
26
+ currentIndex = 1,
27
+ totalCount = 1,
28
+ open = false,
29
+ className = "",
30
+ }) {
31
+ const [visible, setVisible] = useState(false);
32
+ const closeButtonRef = useRef(null);
33
+
34
+ useEffect(() => {
35
+ if (!open) {
36
+ setVisible(false);
37
+ return;
38
+ }
39
+ const frame = requestAnimationFrame(() => setVisible(true));
40
+ return () => cancelAnimationFrame(frame);
41
+ }, [open]);
42
+
43
+ useEffect(() => {
44
+ if (!open) return;
45
+ const prev = document.body.style.overflow;
46
+ document.body.style.overflow = "hidden";
47
+ return () => {
48
+ document.body.style.overflow = prev;
49
+ };
50
+ }, [open]);
51
+
52
+ useEffect(() => {
53
+ if (!open || !visible) return;
54
+ closeButtonRef.current?.focus();
55
+ }, [open, visible]);
56
+
57
+ useEffect(() => {
58
+ if (!open) return;
59
+ function handleKeyDown(e) {
60
+ if (e.key === "Escape") {
61
+ e.preventDefault();
62
+ onClose?.();
63
+ } else if (e.key === "ArrowLeft" && onPrevious) {
64
+ e.preventDefault();
65
+ onPrevious();
66
+ } else if (e.key === "ArrowRight" && onNext) {
67
+ e.preventDefault();
68
+ onNext();
69
+ }
70
+ }
71
+ window.addEventListener("keydown", handleKeyDown);
72
+ return () => window.removeEventListener("keydown", handleKeyDown);
73
+ }, [open, onClose, onPrevious, onNext]);
74
+
75
+ if (!open) return null;
76
+
77
+ const visibleCls = visible ? "opacity-100" : "opacity-0";
78
+ const visibleTransformCls = visible
79
+ ? "translate-y-0 opacity-100"
80
+ : "translate-y-2 opacity-0";
81
+ const visibleScaleCls = visible
82
+ ? "scale-100 opacity-100"
83
+ : "scale-95 opacity-0";
84
+
85
+ const dialogChildren = [
86
+ React.createElement(
87
+ "div",
88
+ {
89
+ key: "header",
90
+ className: "mb-3 flex items-center justify-between gap-3",
91
+ },
92
+ React.createElement("span", { key: "spacer" }),
93
+ React.createElement(
94
+ "button",
95
+ {
96
+ key: "close",
97
+ type: "button",
98
+ ref: closeButtonRef,
99
+ onClick: onClose,
100
+ className: CLOSE_BTN_CLS,
101
+ style: {
102
+ paddingLeft: "var(--lightbox-close-padding-x)",
103
+ paddingRight: "var(--lightbox-close-padding-x)",
104
+ paddingTop: "var(--lightbox-close-padding-y)",
105
+ paddingBottom: "var(--lightbox-close-padding-y)",
106
+ fontSize: "var(--lightbox-close-font-size)",
107
+ },
108
+ },
109
+ React.createElement(X, { className: "size-4", "aria-hidden": true }),
110
+ ),
111
+ ),
112
+ React.createElement(
113
+ "div",
114
+ {
115
+ key: "image",
116
+ className: "flex min-h-0 flex-1 items-center justify-center",
117
+ },
118
+ React.createElement("img", {
119
+ src,
120
+ alt,
121
+ className: `${IMG_CLS} ${visibleScaleCls}`,
122
+ }),
123
+ ),
124
+ ];
125
+
126
+ if (caption) {
127
+ dialogChildren.push(
128
+ React.createElement(
129
+ "p",
130
+ {
131
+ key: "caption",
132
+ className: "mt-3 text-sm leading-6 text-[--lightbox-caption-text]",
133
+ },
134
+ caption,
135
+ ),
136
+ );
137
+ }
138
+
139
+ if (showPrevious || showNext) {
140
+ const navChildren = [];
141
+ if (showPrevious) {
142
+ navChildren.push(
143
+ React.createElement(
144
+ "button",
145
+ {
146
+ key: "prev",
147
+ type: "button",
148
+ onClick: onPrevious,
149
+ className: NAV_BTN_CLS,
150
+ style: {
151
+ paddingLeft: "var(--lightbox-btn-padding-x)",
152
+ paddingRight: "var(--lightbox-btn-padding-x)",
153
+ paddingTop: "var(--lightbox-btn-padding-y)",
154
+ paddingBottom: "var(--lightbox-btn-padding-y)",
155
+ fontSize: "var(--lightbox-btn-font-size)",
156
+ },
157
+ },
158
+ React.createElement(ChevronLeft, {
159
+ className: "size-4",
160
+ "aria-hidden": true,
161
+ }),
162
+ " Previous",
163
+ ),
164
+ );
165
+ }
166
+ if (totalCount > 1) {
167
+ navChildren.push(
168
+ React.createElement(
169
+ "p",
170
+ {
171
+ key: "counter",
172
+ className: "text-center text-[--lightbox-counter-text]",
173
+ style: {
174
+ minWidth: "var(--lightbox-counter-min-width)",
175
+ fontSize: "var(--lightbox-counter-font-size)",
176
+ fontFamily: "var(--lightbox-counter-font-family)",
177
+ textTransform: "var(--lightbox-counter-text-transform)",
178
+ letterSpacing: "var(--lightbox-counter-text-tracking)",
179
+ },
180
+ },
181
+ `${currentIndex} / ${totalCount}`,
182
+ ),
183
+ );
184
+ }
185
+ if (showNext) {
186
+ navChildren.push(
187
+ React.createElement(
188
+ "button",
189
+ {
190
+ key: "next",
191
+ type: "button",
192
+ onClick: onNext,
193
+ className: NAV_BTN_CLS,
194
+ style: {
195
+ paddingLeft: "var(--lightbox-btn-padding-x)",
196
+ paddingRight: "var(--lightbox-btn-padding-x)",
197
+ paddingTop: "var(--lightbox-btn-padding-y)",
198
+ paddingBottom: "var(--lightbox-btn-padding-y)",
199
+ fontSize: "var(--lightbox-btn-font-size)",
200
+ },
201
+ },
202
+ "Next ",
203
+ React.createElement(ChevronRight, {
204
+ className: "size-4",
205
+ "aria-hidden": true,
206
+ }),
207
+ ),
208
+ );
209
+ }
210
+ dialogChildren.push(
211
+ React.createElement(
212
+ "div",
213
+ {
214
+ key: "nav",
215
+ className: "mt-4 flex items-center justify-center",
216
+ style: { gap: "var(--lightbox-nav-gap)" },
217
+ },
218
+ ...navChildren,
219
+ ),
220
+ );
221
+ }
222
+
223
+ return React.createElement(
224
+ "div",
225
+ { className: `fixed inset-0 z-[90] ${className}`.trim() },
226
+ React.createElement("button", {
227
+ type: "button",
228
+ "aria-label": "Close lightbox",
229
+ className: `${BACKDROP_CLS} ${visibleCls}`,
230
+ onClick: onClose,
231
+ }),
232
+ React.createElement(
233
+ "div",
234
+ {
235
+ role: "dialog",
236
+ "aria-modal": true,
237
+ "aria-label": alt || "Image lightbox",
238
+ className: `${DIALOG_CLS} ${visibleTransformCls}`,
239
+ },
240
+ ...dialogChildren,
241
+ ),
242
+ );
243
+ }
@@ -0,0 +1,52 @@
1
+ import React from "react";
2
+
3
+ /**
4
+ * QuarkLogo - inline SVG of the Quark ring+dash mark.
5
+ * Pure server component. Accepts `size` (number, default 40) and `className`.
6
+ */
7
+ export function QuarkLogo({ size = 40, className = "", ...props }) {
8
+ return React.createElement(
9
+ "svg",
10
+ {
11
+ xmlns: "http://www.w3.org/2000/svg",
12
+ viewBox: "0 0 200 200",
13
+ fill: "none",
14
+ width: size,
15
+ height: size,
16
+ "aria-hidden": "true",
17
+ className,
18
+ ...props,
19
+ },
20
+ // Dark arc - upper semicircle
21
+ React.createElement("path", {
22
+ d: "M 35,100 A 65,65 0 0,1 165,100",
23
+ stroke: "var(--quark-logo-dark-arc, #2d3436)",
24
+ strokeWidth: 26,
25
+ strokeLinecap: "butt",
26
+ }),
27
+ // Blue arc - bottom-left
28
+ React.createElement("path", {
29
+ d: "M 119.1,162.1 A 65,65 0 0,1 35,100",
30
+ stroke: "var(--logo-blue-arc)",
31
+ strokeWidth: 26,
32
+ strokeLinecap: "butt",
33
+ }),
34
+ // Red arc - tiny pre-gap sliver
35
+ React.createElement("path", {
36
+ d: "M 165,100 A 65,65 0 0,1 161.5,121",
37
+ stroke: "var(--logo-red-arc)",
38
+ strokeWidth: 26,
39
+ strokeLinecap: "butt",
40
+ }),
41
+ // Red dash - radial tail through the gap
42
+ React.createElement("line", {
43
+ x1: 116.3,
44
+ y1: 116.8,
45
+ x2: 172,
46
+ y2: 174.2,
47
+ stroke: "var(--logo-red-dash)",
48
+ strokeWidth: 28,
49
+ strokeLinecap: "butt",
50
+ }),
51
+ );
52
+ }