@nuraly/lumenjs 0.1.2 → 0.1.4

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 (337) hide show
  1. package/README.md +76 -235
  2. package/dist/auth/config.d.ts +23 -0
  3. package/dist/auth/config.js +115 -0
  4. package/dist/auth/guard.d.ts +12 -0
  5. package/dist/auth/guard.js +28 -0
  6. package/dist/auth/index.d.ts +3 -0
  7. package/dist/auth/index.js +1 -0
  8. package/dist/auth/middleware.d.ts +23 -0
  9. package/dist/auth/middleware.js +89 -0
  10. package/dist/auth/native-auth.d.ts +73 -0
  11. package/dist/auth/native-auth.js +293 -0
  12. package/dist/auth/oidc-client.d.ts +17 -0
  13. package/dist/auth/oidc-client.js +123 -0
  14. package/dist/auth/providers/google.d.ts +23 -0
  15. package/dist/auth/providers/google.js +25 -0
  16. package/dist/auth/providers/index.d.ts +2 -0
  17. package/dist/auth/providers/index.js +1 -0
  18. package/dist/auth/routes/login.d.ts +8 -0
  19. package/dist/auth/routes/login.js +98 -0
  20. package/dist/auth/routes/logout.d.ts +4 -0
  21. package/dist/auth/routes/logout.js +79 -0
  22. package/dist/auth/routes/oidc-callback.d.ts +3 -0
  23. package/dist/auth/routes/oidc-callback.js +70 -0
  24. package/dist/auth/routes/password.d.ts +5 -0
  25. package/dist/auth/routes/password.js +149 -0
  26. package/dist/auth/routes/signup.d.ts +3 -0
  27. package/dist/auth/routes/signup.js +81 -0
  28. package/dist/auth/routes/token.d.ts +4 -0
  29. package/dist/auth/routes/token.js +70 -0
  30. package/dist/auth/routes/utils.d.ts +7 -0
  31. package/dist/auth/routes/utils.js +35 -0
  32. package/dist/auth/routes/verify.d.ts +3 -0
  33. package/dist/auth/routes/verify.js +26 -0
  34. package/dist/auth/routes.d.ts +8 -0
  35. package/dist/auth/routes.js +110 -0
  36. package/dist/auth/session.d.ts +8 -0
  37. package/dist/auth/session.js +54 -0
  38. package/dist/auth/token.d.ts +33 -0
  39. package/dist/auth/token.js +90 -0
  40. package/dist/auth/types.d.ts +156 -0
  41. package/dist/auth/types.js +2 -0
  42. package/dist/build/build-client.d.ts +15 -0
  43. package/dist/build/build-client.js +45 -0
  44. package/dist/build/build-prerender.d.ts +11 -0
  45. package/dist/build/build-prerender.js +159 -0
  46. package/dist/build/build-server.d.ts +17 -0
  47. package/dist/build/build-server.js +98 -0
  48. package/dist/build/build.js +52 -120
  49. package/dist/build/scan.d.ts +19 -0
  50. package/dist/build/scan.js +77 -6
  51. package/dist/build/serve-api.js +8 -2
  52. package/dist/build/serve-loaders.d.ts +4 -2
  53. package/dist/build/serve-loaders.js +128 -10
  54. package/dist/build/serve-ssr.js +38 -11
  55. package/dist/build/serve-static.js +3 -3
  56. package/dist/build/serve.js +229 -14
  57. package/dist/cli.js +37 -6
  58. package/dist/communication/encryption.d.ts +35 -0
  59. package/dist/communication/encryption.js +90 -0
  60. package/dist/communication/handlers/context.d.ts +27 -0
  61. package/dist/communication/handlers/context.js +1 -0
  62. package/dist/communication/handlers/conversation.d.ts +24 -0
  63. package/dist/communication/handlers/conversation.js +113 -0
  64. package/dist/communication/handlers/file-upload.d.ts +17 -0
  65. package/dist/communication/handlers/file-upload.js +62 -0
  66. package/dist/communication/handlers/messaging.d.ts +30 -0
  67. package/dist/communication/handlers/messaging.js +237 -0
  68. package/dist/communication/handlers/presence.d.ts +15 -0
  69. package/dist/communication/handlers/presence.js +76 -0
  70. package/dist/communication/handlers.d.ts +5 -0
  71. package/dist/communication/handlers.js +5 -0
  72. package/dist/communication/index.d.ts +9 -0
  73. package/dist/communication/index.js +7 -0
  74. package/dist/communication/link-preview.d.ts +18 -0
  75. package/dist/communication/link-preview.js +115 -0
  76. package/dist/communication/schema.d.ts +10 -0
  77. package/dist/communication/schema.js +101 -0
  78. package/dist/communication/server.d.ts +86 -0
  79. package/dist/communication/server.js +212 -0
  80. package/dist/communication/signaling.d.ts +43 -0
  81. package/dist/communication/signaling.js +271 -0
  82. package/dist/communication/store.d.ts +71 -0
  83. package/dist/communication/store.js +289 -0
  84. package/dist/communication/types.d.ts +454 -0
  85. package/dist/communication/types.js +1 -0
  86. package/dist/create.d.ts +1 -0
  87. package/dist/create.js +55 -0
  88. package/dist/db/auto-migrate.d.ts +3 -0
  89. package/dist/db/auto-migrate.js +100 -0
  90. package/dist/db/client.d.ts +3 -0
  91. package/dist/db/client.js +18 -0
  92. package/dist/db/context.d.ts +2 -0
  93. package/dist/db/context.js +9 -0
  94. package/dist/db/index.d.ts +23 -0
  95. package/dist/db/index.js +258 -0
  96. package/dist/db/seed.d.ts +12 -0
  97. package/dist/db/seed.js +88 -0
  98. package/dist/db/table.d.ts +10 -0
  99. package/dist/db/table.js +12 -0
  100. package/dist/dev-server/config.d.ts +14 -0
  101. package/dist/dev-server/config.js +26 -9
  102. package/dist/dev-server/index-html.d.ts +3 -0
  103. package/dist/dev-server/index-html.js +18 -6
  104. package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
  105. package/dist/dev-server/nuralyui-aliases.js +115 -94
  106. package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
  107. package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
  108. package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
  109. package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
  110. package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
  111. package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
  112. package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
  113. package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
  114. package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
  115. package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
  116. package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
  117. package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
  118. package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
  119. package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
  120. package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
  121. package/dist/dev-server/plugins/vite-plugin-loaders.d.ts +0 -1
  122. package/dist/dev-server/plugins/vite-plugin-loaders.js +311 -42
  123. package/dist/dev-server/plugins/vite-plugin-routes.js +18 -6
  124. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  125. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  126. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  127. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  128. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  129. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  130. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
  131. package/dist/dev-server/server.js +128 -12
  132. package/dist/dev-server/ssr-render.d.ts +2 -1
  133. package/dist/dev-server/ssr-render.js +107 -48
  134. package/dist/editor/ai/backend.d.ts +20 -0
  135. package/dist/editor/ai/backend.js +104 -0
  136. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  137. package/dist/editor/ai/claude-code-client.js +145 -0
  138. package/dist/editor/ai/opencode-client.d.ts +14 -0
  139. package/dist/editor/ai/opencode-client.js +125 -0
  140. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  141. package/dist/editor/ai/snapshot-store.js +35 -0
  142. package/dist/editor/ai/types.d.ts +30 -0
  143. package/dist/editor/ai/types.js +136 -0
  144. package/dist/editor/ai-chat-panel.d.ts +13 -0
  145. package/dist/editor/ai-chat-panel.js +587 -0
  146. package/dist/editor/ai-markdown.d.ts +10 -0
  147. package/dist/editor/ai-markdown.js +70 -0
  148. package/dist/editor/ai-project-panel.d.ts +11 -0
  149. package/dist/editor/ai-project-panel.js +332 -0
  150. package/dist/editor/ast-modification.d.ts +11 -0
  151. package/dist/editor/ast-modification.js +1 -0
  152. package/dist/editor/ast-service.d.ts +30 -0
  153. package/dist/editor/ast-service.js +180 -0
  154. package/dist/editor/css-rules.d.ts +54 -0
  155. package/dist/editor/css-rules.js +423 -0
  156. package/dist/editor/editor-api-client.d.ts +51 -0
  157. package/dist/editor/editor-api-client.js +162 -0
  158. package/dist/editor/editor-bridge.d.ts +1 -0
  159. package/dist/editor/editor-bridge.js +17 -8
  160. package/dist/editor/editor-toolbar.d.ts +14 -0
  161. package/dist/editor/editor-toolbar.js +115 -0
  162. package/dist/editor/file-editor.d.ts +9 -0
  163. package/dist/editor/file-editor.js +236 -0
  164. package/dist/editor/file-service.d.ts +16 -0
  165. package/dist/editor/file-service.js +52 -0
  166. package/dist/editor/i18n-key-gen.d.ts +1 -0
  167. package/dist/editor/i18n-key-gen.js +7 -0
  168. package/dist/editor/inline-text-edit.d.ts +5 -0
  169. package/dist/editor/inline-text-edit.js +173 -92
  170. package/dist/editor/overlay-events.d.ts +5 -0
  171. package/dist/editor/overlay-events.js +364 -0
  172. package/dist/editor/overlay-hmr.d.ts +2 -0
  173. package/dist/editor/overlay-hmr.js +75 -0
  174. package/dist/editor/overlay-selection.d.ts +29 -0
  175. package/dist/editor/overlay-selection.js +148 -0
  176. package/dist/editor/overlay-utils.d.ts +12 -0
  177. package/dist/editor/overlay-utils.js +59 -0
  178. package/dist/editor/properties-panel-persist.d.ts +14 -0
  179. package/dist/editor/properties-panel-persist.js +70 -0
  180. package/dist/editor/properties-panel-rows.d.ts +10 -0
  181. package/dist/editor/properties-panel-rows.js +349 -0
  182. package/dist/editor/properties-panel-styles.d.ts +4 -0
  183. package/dist/editor/properties-panel-styles.js +174 -0
  184. package/dist/editor/properties-panel.d.ts +4 -0
  185. package/dist/editor/properties-panel.js +148 -0
  186. package/dist/editor/property-registry.d.ts +16 -0
  187. package/dist/editor/property-registry.js +303 -0
  188. package/dist/editor/standalone-file-panel.d.ts +0 -0
  189. package/dist/editor/standalone-file-panel.js +1 -0
  190. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  191. package/dist/editor/standalone-overlay-dom.js +1 -0
  192. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  193. package/dist/editor/standalone-overlay-styles.js +1 -0
  194. package/dist/editor/standalone-overlay.d.ts +1 -0
  195. package/dist/editor/standalone-overlay.js +76 -0
  196. package/dist/editor/syntax-highlighter.d.ts +4 -0
  197. package/dist/editor/syntax-highlighter.js +81 -0
  198. package/dist/editor/text-toolbar.d.ts +11 -0
  199. package/dist/editor/text-toolbar.js +327 -0
  200. package/dist/editor/toolbar-styles.d.ts +4 -0
  201. package/dist/editor/toolbar-styles.js +198 -0
  202. package/dist/email/index.d.ts +32 -0
  203. package/dist/email/index.js +154 -0
  204. package/dist/email/providers/resend.d.ts +2 -0
  205. package/dist/email/providers/resend.js +24 -0
  206. package/dist/email/providers/sendgrid.d.ts +2 -0
  207. package/dist/email/providers/sendgrid.js +31 -0
  208. package/dist/email/providers/smtp.d.ts +13 -0
  209. package/dist/email/providers/smtp.js +125 -0
  210. package/dist/email/template-engine.d.ts +18 -0
  211. package/dist/email/template-engine.js +116 -0
  212. package/dist/email/templates/base.d.ts +9 -0
  213. package/dist/email/templates/base.js +65 -0
  214. package/dist/email/templates/password-reset.d.ts +5 -0
  215. package/dist/email/templates/password-reset.js +15 -0
  216. package/dist/email/templates/verify-email.d.ts +5 -0
  217. package/dist/email/templates/verify-email.js +15 -0
  218. package/dist/email/templates/welcome.d.ts +5 -0
  219. package/dist/email/templates/welcome.js +13 -0
  220. package/dist/email/types.d.ts +49 -0
  221. package/dist/email/types.js +1 -0
  222. package/dist/llms/generate.d.ts +46 -0
  223. package/dist/llms/generate.js +185 -0
  224. package/dist/permissions/guard.d.ts +28 -0
  225. package/dist/permissions/guard.js +30 -0
  226. package/dist/permissions/index.d.ts +6 -0
  227. package/dist/permissions/index.js +3 -0
  228. package/dist/permissions/service.d.ts +80 -0
  229. package/dist/permissions/service.js +210 -0
  230. package/dist/permissions/tables.d.ts +5 -0
  231. package/dist/permissions/tables.js +68 -0
  232. package/dist/permissions/types.d.ts +33 -0
  233. package/dist/permissions/types.js +1 -0
  234. package/dist/runtime/app-shell.js +163 -0
  235. package/dist/runtime/auth.d.ts +10 -0
  236. package/dist/runtime/auth.js +30 -0
  237. package/dist/runtime/communication.d.ts +137 -0
  238. package/dist/runtime/communication.js +228 -0
  239. package/dist/runtime/error-boundary.d.ts +23 -0
  240. package/dist/runtime/error-boundary.js +120 -0
  241. package/dist/runtime/i18n.d.ts +6 -1
  242. package/dist/runtime/i18n.js +42 -21
  243. package/dist/runtime/router-data.d.ts +5 -0
  244. package/dist/runtime/router-data.js +121 -16
  245. package/dist/runtime/router-hydration.js +25 -0
  246. package/dist/runtime/router.d.ts +21 -1
  247. package/dist/runtime/router.js +221 -39
  248. package/dist/runtime/socket-client.d.ts +2 -0
  249. package/dist/runtime/socket-client.js +30 -0
  250. package/dist/runtime/webrtc.d.ts +47 -0
  251. package/dist/runtime/webrtc.js +178 -0
  252. package/dist/shared/graceful-shutdown.d.ts +8 -0
  253. package/dist/shared/graceful-shutdown.js +36 -0
  254. package/dist/shared/health.d.ts +8 -0
  255. package/dist/shared/health.js +25 -0
  256. package/dist/shared/llms-txt.d.ts +31 -0
  257. package/dist/shared/llms-txt.js +85 -0
  258. package/dist/shared/logger.d.ts +32 -0
  259. package/dist/shared/logger.js +93 -0
  260. package/dist/shared/meta.d.ts +27 -0
  261. package/dist/shared/meta.js +71 -0
  262. package/dist/shared/middleware-runner.d.ts +9 -0
  263. package/dist/shared/middleware-runner.js +29 -0
  264. package/dist/shared/rate-limit.d.ts +18 -0
  265. package/dist/shared/rate-limit.js +71 -0
  266. package/dist/shared/request-id.d.ts +5 -0
  267. package/dist/shared/request-id.js +18 -0
  268. package/dist/shared/route-matching.js +16 -1
  269. package/dist/shared/security-headers.d.ts +18 -0
  270. package/dist/shared/security-headers.js +38 -0
  271. package/dist/shared/socket-io-setup.d.ts +11 -0
  272. package/dist/shared/socket-io-setup.js +51 -0
  273. package/dist/shared/types.d.ts +16 -0
  274. package/dist/shared/utils.d.ts +37 -7
  275. package/dist/shared/utils.js +175 -26
  276. package/dist/storage/adapters/local.d.ts +44 -0
  277. package/dist/storage/adapters/local.js +85 -0
  278. package/dist/storage/adapters/s3.d.ts +32 -0
  279. package/dist/storage/adapters/s3.js +116 -0
  280. package/dist/storage/adapters/types.d.ts +53 -0
  281. package/dist/storage/adapters/types.js +1 -0
  282. package/dist/storage/index.d.ts +76 -0
  283. package/dist/storage/index.js +83 -0
  284. package/package.json +20 -1
  285. package/templates/blog/api/posts.ts +6 -0
  286. package/templates/blog/data/migrations/001_init.sql +13 -0
  287. package/templates/blog/lumenjs.config.ts +3 -0
  288. package/templates/blog/package.json +14 -0
  289. package/templates/blog/pages/_layout.ts +25 -0
  290. package/templates/blog/pages/index.ts +65 -0
  291. package/templates/blog/pages/posts/[slug].ts +60 -0
  292. package/templates/blog/pages/tag/[tag].ts +44 -0
  293. package/templates/dashboard/api/stats.ts +10 -0
  294. package/templates/dashboard/data/migrations/001_init.sql +13 -0
  295. package/templates/dashboard/lumenjs.config.ts +3 -0
  296. package/templates/dashboard/package.json +14 -0
  297. package/templates/dashboard/pages/_layout.ts +25 -0
  298. package/templates/dashboard/pages/index.ts +72 -0
  299. package/templates/dashboard/pages/settings/index.ts +29 -0
  300. package/templates/default/lumenjs.config.ts +3 -0
  301. package/templates/default/package.json +14 -0
  302. package/templates/default/pages/index.ts +24 -0
  303. package/templates/social/api/posts/[id].ts +14 -0
  304. package/templates/social/api/posts.ts +11 -0
  305. package/templates/social/api/profile/[username].ts +10 -0
  306. package/templates/social/api/upload.ts +19 -0
  307. package/templates/social/data/migrations/001_init.sql +78 -0
  308. package/templates/social/data/migrations/002_add_image_url.sql +1 -0
  309. package/templates/social/data/migrations/003_auth.sql +7 -0
  310. package/templates/social/docs/architecture.md +76 -0
  311. package/templates/social/docs/components.md +100 -0
  312. package/templates/social/docs/data.md +89 -0
  313. package/templates/social/docs/pages.md +96 -0
  314. package/templates/social/docs/theming.md +52 -0
  315. package/templates/social/lib/media.ts +130 -0
  316. package/templates/social/lumenjs.auth.ts +21 -0
  317. package/templates/social/lumenjs.config.ts +3 -0
  318. package/templates/social/package.json +5 -0
  319. package/templates/social/pages/_layout.ts +239 -0
  320. package/templates/social/pages/apps/[id].ts +173 -0
  321. package/templates/social/pages/apps/index.ts +116 -0
  322. package/templates/social/pages/auth/login.ts +92 -0
  323. package/templates/social/pages/bookmarks.ts +57 -0
  324. package/templates/social/pages/explore.ts +73 -0
  325. package/templates/social/pages/index.ts +351 -0
  326. package/templates/social/pages/messages.ts +298 -0
  327. package/templates/social/pages/new.ts +77 -0
  328. package/templates/social/pages/notifications.ts +73 -0
  329. package/templates/social/pages/post/[id].ts +124 -0
  330. package/templates/social/pages/profile/[username].ts +100 -0
  331. package/templates/social/pages/settings/accessibility.ts +153 -0
  332. package/templates/social/pages/settings/account.ts +260 -0
  333. package/templates/social/pages/settings/help.ts +141 -0
  334. package/templates/social/pages/settings/language.ts +103 -0
  335. package/templates/social/pages/settings/privacy.ts +183 -0
  336. package/templates/social/pages/settings/security.ts +133 -0
  337. package/templates/social/pages/settings.ts +185 -0
@@ -0,0 +1,116 @@
1
+ import { LitElement, html, css } from 'lit';
2
+
3
+ const svg = {
4
+ search: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>`,
5
+ };
6
+
7
+ export async function loader() {
8
+ return {
9
+ featured: [
10
+ { id: 'poll', name: 'Polls', desc: 'Create polls and surveys for your community', color: '#7c3aed', icon: 'bar-chart' },
11
+ { id: 'calendar', name: 'Calendar', desc: 'Track events, meetings, and deadlines', color: '#3b49df', icon: 'calendar' },
12
+ { id: 'notes', name: 'Quick Notes', desc: 'Markdown notes that sync across devices', color: '#22c55e', icon: 'file-text' },
13
+ ],
14
+ categories: ['Productivity', 'Entertainment', 'Finance', 'Social', 'Developer Tools', 'Health'],
15
+ apps: [
16
+ { id: 'poll', name: 'Poll Creator', desc: 'Create polls and surveys for your feed', category: 'Social', color: '#7c3aed' },
17
+ { id: 'calendar', name: 'Mini Calendar', desc: 'Track events and meetings', category: 'Productivity', color: '#3b49df' },
18
+ { id: 'notes', name: 'Quick Notes', desc: 'Markdown notes with cloud sync', category: 'Productivity', color: '#22c55e' },
19
+ { id: 'timer', name: 'Focus Timer', desc: 'Pomodoro timer for deep work', category: 'Productivity', color: '#ef4444' },
20
+ { id: 'weather', name: 'Weather', desc: 'Local weather and forecasts', category: 'Entertainment', color: '#f59e0b' },
21
+ { id: 'stocks', name: 'Stock Tracker', desc: 'Watch your portfolio in real-time', category: 'Finance', color: '#10b981' },
22
+ { id: 'news', name: 'News Feed', desc: 'Curated tech news from top sources', category: 'Entertainment', color: '#6366f1' },
23
+ { id: 'tasks', name: 'Task Board', desc: 'Kanban-style task management', category: 'Productivity', color: '#8b5cf6' },
24
+ { id: 'translate', name: 'Translator', desc: 'Translate text between languages', category: 'Developer Tools', color: '#06b6d4' },
25
+ { id: 'code', name: 'Code Snippets', desc: 'Save and share code snippets', category: 'Developer Tools', color: '#0f172a' },
26
+ { id: 'fitness', name: 'Step Counter', desc: 'Track daily steps and activity', category: 'Health', color: '#ec4899' },
27
+ { id: 'budget', name: 'Budget Tracker', desc: 'Track expenses and income', category: 'Finance', color: '#14b8a6' },
28
+ ],
29
+ };
30
+ }
31
+
32
+ export class PageApps extends LitElement {
33
+ static properties = { loaderData: { type: Object }, _category: { state: true } };
34
+ loaderData: any = {};
35
+ _category: string = '';
36
+
37
+ static styles = css`
38
+ :host { display: block; }
39
+ .card { background: var(--bg); border-radius: 6px; border: 1px solid var(--border); overflow: hidden; margin-bottom: 12px; }
40
+ h2 { font-size: 20px; font-weight: 700; padding: 16px 20px 8px; margin: 0; }
41
+
42
+ .search-wrap { padding: 0 20px 16px; position: relative; }
43
+ .search-icon { position: absolute; left: 32px; top: 50%; transform: translateY(-50%); color: var(--text-secondary); display: flex; }
44
+ .search { width: 100%; padding: 10px 12px 10px 36px; border: 1px solid var(--border); border-radius: 9999px; font-size: 14px; outline: none; background: var(--input-bg); }
45
+ .search:focus { border-color: var(--accent); background: var(--bg); }
46
+
47
+ .featured { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; padding: 0 20px 16px; }
48
+ .feat-card { border: 1px solid var(--border); border-radius: 12px; padding: 16px; cursor: pointer; text-decoration: none; color: inherit; transition: box-shadow 0.15s; }
49
+ .feat-card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
50
+ .feat-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 18px; font-weight: 700; }
51
+ .feat-name { font-size: 15px; font-weight: 700; margin-top: 10px; }
52
+ .feat-desc { font-size: 12px; color: var(--text-secondary); margin-top: 4px; line-height: 1.3; }
53
+
54
+ .categories { display: flex; gap: 6px; padding: 0 20px 12px; overflow-x: auto; scrollbar-width: none; }
55
+ .categories::-webkit-scrollbar { display: none; }
56
+ .cat-btn { padding: 6px 14px; border-radius: 9999px; border: 1px solid var(--border); background: var(--bg); font-size: 13px; color: var(--text-secondary); cursor: pointer; white-space: nowrap; font-weight: 500; }
57
+ .cat-btn:hover { border-color: var(--accent); color: var(--accent); }
58
+ .cat-btn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
59
+
60
+ .app-list { padding: 0 20px 8px; }
61
+ .app-item { display: flex; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border-light); align-items: center; }
62
+ .app-item:last-child { border-bottom: none; }
63
+ .app-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 16px; font-weight: 700; flex-shrink: 0; }
64
+ .app-info { flex: 1; min-width: 0; }
65
+ .app-name { font-size: 14px; font-weight: 700; }
66
+ .app-desc { font-size: 12px; color: var(--text-secondary); margin-top: 1px; }
67
+ .app-cat { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; }
68
+ .open-btn { padding: 5px 14px; border-radius: 9999px; border: 1px solid var(--accent); color: var(--accent); background: var(--bg); font-size: 12px; font-weight: 600; cursor: pointer; text-decoration: none; }
69
+ .open-btn:hover { background: rgba(124,58,237,0.1); }
70
+
71
+ @media (max-width: 640px) { .featured { grid-template-columns: 1fr; } }
72
+ `;
73
+
74
+ render() {
75
+ const { featured, categories, apps } = this.loaderData;
76
+ const filtered = this._category ? apps?.filter((a: any) => a.category === this._category) : apps;
77
+ return html`
78
+ <div class="card">
79
+ <h2>Apps</h2>
80
+ <div class="search-wrap">
81
+ <span class="search-icon">${svg.search}</span>
82
+ <input class="search" type="text" placeholder="Search apps...">
83
+ </div>
84
+ <h2 style="font-size:16px;padding-top:0">Featured</h2>
85
+ <div class="featured">
86
+ ${(featured || []).map((f: any) => html`
87
+ <a class="feat-card" href="/apps/${f.id}">
88
+ <div class="feat-icon" style="background:${f.color}">${f.name.charAt(0)}</div>
89
+ <div class="feat-name">${f.name}</div>
90
+ <div class="feat-desc">${f.desc}</div>
91
+ </a>
92
+ `)}
93
+ </div>
94
+ <div class="categories">
95
+ <button class="cat-btn ${this._category === '' ? 'active' : ''}" @click=${() => this._category = ''}>All</button>
96
+ ${(categories || []).map((c: string) => html`
97
+ <button class="cat-btn ${this._category === c ? 'active' : ''}" @click=${() => this._category = c}>${c}</button>
98
+ `)}
99
+ </div>
100
+ <div class="app-list">
101
+ ${(filtered || []).map((a: any) => html`
102
+ <div class="app-item">
103
+ <div class="app-icon" style="background:${a.color}">${a.name.charAt(0)}</div>
104
+ <div class="app-info">
105
+ <div class="app-name">${a.name}</div>
106
+ <div class="app-desc">${a.desc}</div>
107
+ <div class="app-cat">${a.category}</div>
108
+ </div>
109
+ <a class="open-btn" href="/apps/${a.id}">Open</a>
110
+ </div>
111
+ `)}
112
+ </div>
113
+ </div>
114
+ `;
115
+ }
116
+ }
@@ -0,0 +1,92 @@
1
+ import { LitElement, html, css } from 'lit';
2
+
3
+ // Google 'G' logo SVG (official colors)
4
+ const googleLogo = html`<svg width="18" height="18" viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg">
5
+ <path d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 01-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z" fill="#4285F4"/>
6
+ <path d="M9 18c2.43 0 4.467-.806 5.956-2.18l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 009 18z" fill="#34A853"/>
7
+ <path d="M3.964 10.71A5.41 5.41 0 013.682 9c0-.593.102-1.17.282-1.71V4.958H.957A8.996 8.996 0 000 9c0 1.452.348 2.827.957 4.042l3.007-2.332z" fill="#FBBC05"/>
8
+ <path d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 00.957 4.958L3.964 6.29C4.672 4.163 6.656 3.58 9 3.58z" fill="#EA4335"/>
9
+ </svg>`;
10
+
11
+ export async function loader({ query }: any) {
12
+ return {
13
+ error: query?.error ?? null,
14
+ returnTo: query?.returnTo ?? '/',
15
+ };
16
+ }
17
+
18
+ export class PageAuthLogin extends LitElement {
19
+ static properties = { loaderData: { type: Object } };
20
+ loaderData: any = {};
21
+
22
+ static styles = css`
23
+ :host { display: flex; align-items: center; justify-content: center; min-height: 80vh; padding: 24px 16px; }
24
+
25
+ .card {
26
+ width: 100%; max-width: 380px;
27
+ background: var(--bg); border: 1px solid var(--border);
28
+ border-radius: 16px; padding: 40px 32px;
29
+ text-align: center;
30
+ box-shadow: 0 4px 24px rgba(0,0,0,0.06);
31
+ }
32
+
33
+ .logo {
34
+ width: 52px; height: 52px; border-radius: 50%;
35
+ background: var(--accent); color: #fff;
36
+ font-size: 24px; font-weight: 900;
37
+ display: flex; align-items: center; justify-content: center;
38
+ margin: 0 auto 20px;
39
+ }
40
+
41
+ h1 { font-size: 22px; font-weight: 800; margin: 0 0 6px; color: var(--text); }
42
+ p { font-size: 14px; color: var(--text-secondary); margin: 0 0 28px; }
43
+
44
+ .error {
45
+ background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px;
46
+ color: #dc2626; font-size: 13px; padding: 10px 14px;
47
+ margin-bottom: 20px; text-align: left;
48
+ }
49
+
50
+ .google-btn {
51
+ display: flex; align-items: center; justify-content: center; gap: 10px;
52
+ width: 100%; padding: 11px 20px;
53
+ background: var(--bg); color: var(--text);
54
+ border: 1px solid var(--border); border-radius: 8px;
55
+ font-size: 14px; font-weight: 600;
56
+ text-decoration: none; cursor: pointer;
57
+ transition: background 0.15s, border-color 0.15s;
58
+ }
59
+ .google-btn:hover { background: var(--bg-secondary); border-color: var(--accent); }
60
+
61
+ .divider { display: flex; align-items: center; gap: 12px; margin: 20px 0; color: var(--text-tertiary); font-size: 12px; }
62
+ .divider::before, .divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
63
+
64
+ .terms { font-size: 12px; color: var(--text-tertiary); margin-top: 20px; line-height: 1.5; }
65
+ `;
66
+
67
+ render() {
68
+ const { error, returnTo } = this.loaderData;
69
+ const loginUrl = `/__nk_auth/login/google?returnTo=${encodeURIComponent(returnTo ?? '/')}`;
70
+ const errorMsg = error === 'access_denied' ? 'Access was denied. Please try again.'
71
+ : error === 'state_mismatch' ? 'Login session expired. Please try again.'
72
+ : error ? 'Authentication failed. Please try again.'
73
+ : null;
74
+
75
+ return html`
76
+ <div class="card">
77
+ <div class="logo">N</div>
78
+ <h1>Sign in</h1>
79
+ <p>Welcome back — sign in to continue</p>
80
+
81
+ ${errorMsg ? html`<div class="error">${errorMsg}</div>` : ''}
82
+
83
+ <a class="google-btn" href="${loginUrl}">
84
+ ${googleLogo}
85
+ Continue with Google
86
+ </a>
87
+
88
+ <p class="terms">By signing in you agree to our Terms of Service and Privacy Policy.</p>
89
+ </div>
90
+ `;
91
+ }
92
+ }
@@ -0,0 +1,57 @@
1
+ import { LitElement, html, css } from 'lit';
2
+
3
+ const svg = {
4
+ bookmark: html`<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M19 21l-7-5-7 5V5a2 2 0 012-2h10a2 2 0 012 2z"/></svg>`,
5
+ };
6
+
7
+ export async function loader() {
8
+ return {
9
+ bookmarks: [
10
+ { id: 1, username: 'aymen', display_name: 'Aymen Labidi', initials: 'AL', color: '#7c3aed', title: 'Why file-based routing changes everything', saved: '2 hours ago' },
11
+ { id: 7, username: 'emma_data', display_name: 'Emma Williams', initials: 'EW', color: '#3572a5', title: 'Polars vs Pandas: a practical comparison', saved: '1 day ago' },
12
+ { id: 4, username: 'mike_ops', display_name: 'Mike Johnson', initials: 'MJ', color: '#22c55e', title: 'Migrating CI/CD to GitHub Actions: a retrospective', saved: '3 days ago' },
13
+ ],
14
+ };
15
+ }
16
+
17
+ export class PageBookmarks extends LitElement {
18
+ static properties = { loaderData: { type: Object } };
19
+ loaderData: any = {};
20
+
21
+ static styles = css`
22
+ :host { display: block; }
23
+ .card { background: var(--bg); border-radius: 6px; border: 1px solid var(--border); overflow: hidden; }
24
+ h2 { font-size: 20px; font-weight: 700; padding: 16px 20px; margin: 0; border-bottom: 1px solid var(--border-light); }
25
+ .item { display: flex; gap: 10px; padding: 12px 20px; border-bottom: 1px solid var(--border-light); cursor: pointer; }
26
+ .item:hover { background: var(--bg-hover); }
27
+ .item:last-child { border-bottom: none; }
28
+ .item-icon { width: 36px; height: 36px; border-radius: 8px; background: var(--bg-secondary); display: flex; align-items: center; justify-content: center; color: var(--accent); flex-shrink: 0; }
29
+ .item-body { flex: 1; }
30
+ .item-title { font-size: 15px; font-weight: 600; }
31
+ .item-title a { color: var(--text); text-decoration: none; }
32
+ .item-title a:hover { color: var(--accent); }
33
+ .item-meta { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
34
+ .empty { padding: 48px 20px; text-align: center; color: var(--text-secondary); font-size: 14px; }
35
+ `;
36
+
37
+ render() {
38
+ const bookmarks = this.loaderData.bookmarks || [];
39
+ return html`
40
+ <div class="card">
41
+ <h2>Bookmarks</h2>
42
+ ${bookmarks.length === 0
43
+ ? html`<div class="empty">No bookmarks yet</div>`
44
+ : bookmarks.map((b: any) => html`
45
+ <div class="item">
46
+ <div class="item-icon">${svg.bookmark}</div>
47
+ <div class="item-body">
48
+ <div class="item-title"><a href="/post/${b.id}">${b.title}</a></div>
49
+ <div class="item-meta">${b.display_name} · Saved ${b.saved}</div>
50
+ </div>
51
+ </div>
52
+ `)
53
+ }
54
+ </div>
55
+ `;
56
+ }
57
+ }
@@ -0,0 +1,73 @@
1
+ import { LitElement, html, css } from 'lit';
2
+
3
+ export async function loader() {
4
+ return {
5
+ tags: [
6
+ { name: 'webcomponents', count: 1250, color: '#3b49df' },
7
+ { name: 'typescript', count: 3400, color: '#3178c6' },
8
+ { name: 'devops', count: 890, color: '#e44d26' },
9
+ { name: 'machinelearning', count: 2100, color: '#f7df1e' },
10
+ { name: 'opensource', count: 1800, color: '#22c55e' },
11
+ { name: 'css', count: 4200, color: '#a855f7' },
12
+ { name: 'python', count: 5100, color: '#3572a5' },
13
+ { name: 'beginners', count: 6300, color: '#ef4444' },
14
+ ],
15
+ topPosts: [
16
+ { id: 9, display_name: 'Aymen Labidi', title: 'Building a commit message generator with Claude', likes: 112, comments: 18, time: '4 days ago' },
17
+ { id: 7, display_name: 'Emma Williams', title: 'Polars vs Pandas: a practical comparison', likes: 93, comments: 15, time: '3 days ago' },
18
+ { id: 5, display_name: 'Aymen Labidi', title: 'TypeScript\'s type system is secretly a language', likes: 85, comments: 12, time: '2 days ago' },
19
+ ],
20
+ };
21
+ }
22
+
23
+ export class PageExplore extends LitElement {
24
+ static properties = { loaderData: { type: Object } };
25
+ loaderData: any = {};
26
+
27
+ static styles = css`
28
+ :host { display: block; }
29
+ .card { background: var(--bg); border-radius: 6px; border: 1px solid var(--border); padding: 20px; margin-bottom: 12px; }
30
+ h2 { font-size: 20px; font-weight: 700; margin: 0 0 16px; }
31
+
32
+ .tags-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 8px; }
33
+ .tag-card { border: 1px solid var(--border); border-radius: 6px; padding: 12px 16px; cursor: pointer; transition: all 0.15s; }
34
+ .tag-card:hover { border-color: #d0d0d0; box-shadow: 0 2px 4px rgba(0,0,0,0.04); }
35
+ .tag-top { width: 100%; height: 6px; border-radius: 3px; margin-bottom: 8px; }
36
+ .tag-name { font-size: 16px; font-weight: 600; }
37
+ .tag-count { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }
38
+
39
+ .top-post { padding: 10px 0; border-bottom: 1px solid var(--border-light); }
40
+ .top-post:last-child { border-bottom: none; }
41
+ .top-title { font-size: 15px; font-weight: 600; }
42
+ .top-title a { color: var(--text); text-decoration: none; }
43
+ .top-title a:hover { color: var(--accent); }
44
+ .top-meta { font-size: 12px; color: var(--text-secondary); margin-top: 4px; }
45
+ `;
46
+
47
+ render() {
48
+ const { tags, topPosts } = this.loaderData;
49
+ return html`
50
+ <div class="card">
51
+ <h2>Popular Tags</h2>
52
+ <div class="tags-grid">
53
+ ${(tags || []).map((t: any) => html`
54
+ <div class="tag-card">
55
+ <div class="tag-top" style="background:${t.color}"></div>
56
+ <div class="tag-name">#${t.name}</div>
57
+ <div class="tag-count">${t.count.toLocaleString()} posts published</div>
58
+ </div>
59
+ `)}
60
+ </div>
61
+ </div>
62
+ <div class="card">
63
+ <h2>Top Posts This Week</h2>
64
+ ${(topPosts || []).map((p: any) => html`
65
+ <div class="top-post">
66
+ <div class="top-title"><a href="/post/${p.id}">${p.title}</a></div>
67
+ <div class="top-meta">${p.display_name} · ${p.likes} reactions · ${p.comments} comments · ${p.time}</div>
68
+ </div>
69
+ `)}
70
+ </div>
71
+ `;
72
+ }
73
+ }