@nuraly/lumenjs 0.1.3 → 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 (333) hide show
  1. package/README.md +62 -282
  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 +48 -120
  49. package/dist/build/scan.d.ts +17 -0
  50. package/dist/build/scan.js +76 -6
  51. package/dist/build/serve-api.js +8 -2
  52. package/dist/build/serve-loaders.d.ts +4 -4
  53. package/dist/build/serve-loaders.js +26 -18
  54. package/dist/build/serve-ssr.js +38 -11
  55. package/dist/build/serve-static.js +3 -3
  56. package/dist/build/serve.js +218 -15
  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/index.d.ts +17 -13
  93. package/dist/db/index.js +205 -26
  94. package/dist/db/seed.d.ts +12 -0
  95. package/dist/db/seed.js +88 -0
  96. package/dist/db/table.d.ts +10 -0
  97. package/dist/db/table.js +12 -0
  98. package/dist/dev-server/config.d.ts +11 -0
  99. package/dist/dev-server/config.js +23 -20
  100. package/dist/dev-server/index-html.d.ts +3 -0
  101. package/dist/dev-server/index-html.js +18 -6
  102. package/dist/dev-server/nuralyui-aliases.d.ts +0 -4
  103. package/dist/dev-server/nuralyui-aliases.js +115 -94
  104. package/dist/dev-server/plugins/vite-plugin-api-routes.js +29 -5
  105. package/dist/dev-server/plugins/vite-plugin-auth.d.ts +6 -0
  106. package/dist/dev-server/plugins/vite-plugin-auth.js +223 -0
  107. package/dist/dev-server/plugins/vite-plugin-auto-define.d.ts +16 -0
  108. package/dist/dev-server/plugins/vite-plugin-auto-define.js +111 -0
  109. package/dist/dev-server/plugins/vite-plugin-communication.d.ts +6 -0
  110. package/dist/dev-server/plugins/vite-plugin-communication.js +205 -0
  111. package/dist/dev-server/plugins/vite-plugin-editor-api.d.ts +6 -0
  112. package/dist/dev-server/plugins/vite-plugin-editor-api.js +318 -0
  113. package/dist/dev-server/plugins/vite-plugin-i18n.js +69 -2
  114. package/dist/dev-server/plugins/vite-plugin-lit-dedup.d.ts +6 -0
  115. package/dist/dev-server/plugins/vite-plugin-lit-dedup.js +78 -34
  116. package/dist/dev-server/plugins/vite-plugin-lit-hmr.js +44 -2
  117. package/dist/dev-server/plugins/vite-plugin-llms.d.ts +2 -0
  118. package/dist/dev-server/plugins/vite-plugin-llms.js +92 -0
  119. package/dist/dev-server/plugins/vite-plugin-loaders.js +146 -13
  120. package/dist/dev-server/plugins/vite-plugin-routes.js +15 -5
  121. package/dist/dev-server/plugins/vite-plugin-socketio.d.ts +2 -0
  122. package/dist/dev-server/plugins/vite-plugin-socketio.js +51 -0
  123. package/dist/dev-server/plugins/vite-plugin-source-annotator.d.ts +2 -0
  124. package/dist/dev-server/plugins/vite-plugin-source-annotator.js +26 -3
  125. package/dist/dev-server/plugins/vite-plugin-storage.d.ts +10 -0
  126. package/dist/dev-server/plugins/vite-plugin-storage.js +126 -0
  127. package/dist/dev-server/plugins/vite-plugin-virtual-modules.js +111 -2
  128. package/dist/dev-server/server.js +127 -13
  129. package/dist/dev-server/ssr-render.d.ts +2 -1
  130. package/dist/dev-server/ssr-render.js +107 -48
  131. package/dist/editor/ai/backend.d.ts +20 -0
  132. package/dist/editor/ai/backend.js +104 -0
  133. package/dist/editor/ai/claude-code-client.d.ts +20 -0
  134. package/dist/editor/ai/claude-code-client.js +145 -0
  135. package/dist/editor/ai/opencode-client.d.ts +14 -0
  136. package/dist/editor/ai/opencode-client.js +125 -0
  137. package/dist/editor/ai/snapshot-store.d.ts +22 -0
  138. package/dist/editor/ai/snapshot-store.js +35 -0
  139. package/dist/editor/ai/types.d.ts +30 -0
  140. package/dist/editor/ai/types.js +136 -0
  141. package/dist/editor/ai-chat-panel.d.ts +13 -0
  142. package/dist/editor/ai-chat-panel.js +587 -0
  143. package/dist/editor/ai-markdown.d.ts +10 -0
  144. package/dist/editor/ai-markdown.js +70 -0
  145. package/dist/editor/ai-project-panel.d.ts +11 -0
  146. package/dist/editor/ai-project-panel.js +332 -0
  147. package/dist/editor/ast-modification.d.ts +11 -0
  148. package/dist/editor/ast-modification.js +1 -0
  149. package/dist/editor/ast-service.d.ts +30 -0
  150. package/dist/editor/ast-service.js +180 -0
  151. package/dist/editor/css-rules.d.ts +54 -0
  152. package/dist/editor/css-rules.js +423 -0
  153. package/dist/editor/editor-api-client.d.ts +51 -0
  154. package/dist/editor/editor-api-client.js +162 -0
  155. package/dist/editor/editor-bridge.d.ts +1 -0
  156. package/dist/editor/editor-bridge.js +17 -8
  157. package/dist/editor/editor-toolbar.d.ts +14 -0
  158. package/dist/editor/editor-toolbar.js +115 -0
  159. package/dist/editor/file-editor.d.ts +9 -0
  160. package/dist/editor/file-editor.js +236 -0
  161. package/dist/editor/file-service.d.ts +16 -0
  162. package/dist/editor/file-service.js +52 -0
  163. package/dist/editor/i18n-key-gen.d.ts +1 -0
  164. package/dist/editor/i18n-key-gen.js +7 -0
  165. package/dist/editor/inline-text-edit.d.ts +5 -0
  166. package/dist/editor/inline-text-edit.js +173 -92
  167. package/dist/editor/overlay-events.d.ts +5 -0
  168. package/dist/editor/overlay-events.js +364 -0
  169. package/dist/editor/overlay-hmr.d.ts +2 -0
  170. package/dist/editor/overlay-hmr.js +75 -0
  171. package/dist/editor/overlay-selection.d.ts +29 -0
  172. package/dist/editor/overlay-selection.js +148 -0
  173. package/dist/editor/overlay-utils.d.ts +12 -0
  174. package/dist/editor/overlay-utils.js +59 -0
  175. package/dist/editor/properties-panel-persist.d.ts +14 -0
  176. package/dist/editor/properties-panel-persist.js +70 -0
  177. package/dist/editor/properties-panel-rows.d.ts +10 -0
  178. package/dist/editor/properties-panel-rows.js +349 -0
  179. package/dist/editor/properties-panel-styles.d.ts +4 -0
  180. package/dist/editor/properties-panel-styles.js +174 -0
  181. package/dist/editor/properties-panel.d.ts +4 -0
  182. package/dist/editor/properties-panel.js +148 -0
  183. package/dist/editor/property-registry.d.ts +16 -0
  184. package/dist/editor/property-registry.js +303 -0
  185. package/dist/editor/standalone-file-panel.d.ts +0 -0
  186. package/dist/editor/standalone-file-panel.js +1 -0
  187. package/dist/editor/standalone-overlay-dom.d.ts +0 -0
  188. package/dist/editor/standalone-overlay-dom.js +1 -0
  189. package/dist/editor/standalone-overlay-styles.d.ts +0 -0
  190. package/dist/editor/standalone-overlay-styles.js +1 -0
  191. package/dist/editor/standalone-overlay.d.ts +1 -0
  192. package/dist/editor/standalone-overlay.js +76 -0
  193. package/dist/editor/syntax-highlighter.d.ts +4 -0
  194. package/dist/editor/syntax-highlighter.js +81 -0
  195. package/dist/editor/text-toolbar.d.ts +11 -0
  196. package/dist/editor/text-toolbar.js +327 -0
  197. package/dist/editor/toolbar-styles.d.ts +4 -0
  198. package/dist/editor/toolbar-styles.js +198 -0
  199. package/dist/email/index.d.ts +32 -0
  200. package/dist/email/index.js +154 -0
  201. package/dist/email/providers/resend.d.ts +2 -0
  202. package/dist/email/providers/resend.js +24 -0
  203. package/dist/email/providers/sendgrid.d.ts +2 -0
  204. package/dist/email/providers/sendgrid.js +31 -0
  205. package/dist/email/providers/smtp.d.ts +13 -0
  206. package/dist/email/providers/smtp.js +125 -0
  207. package/dist/email/template-engine.d.ts +18 -0
  208. package/dist/email/template-engine.js +116 -0
  209. package/dist/email/templates/base.d.ts +9 -0
  210. package/dist/email/templates/base.js +65 -0
  211. package/dist/email/templates/password-reset.d.ts +5 -0
  212. package/dist/email/templates/password-reset.js +15 -0
  213. package/dist/email/templates/verify-email.d.ts +5 -0
  214. package/dist/email/templates/verify-email.js +15 -0
  215. package/dist/email/templates/welcome.d.ts +5 -0
  216. package/dist/email/templates/welcome.js +13 -0
  217. package/dist/email/types.d.ts +49 -0
  218. package/dist/email/types.js +1 -0
  219. package/dist/llms/generate.d.ts +46 -0
  220. package/dist/llms/generate.js +185 -0
  221. package/dist/permissions/guard.d.ts +28 -0
  222. package/dist/permissions/guard.js +30 -0
  223. package/dist/permissions/index.d.ts +6 -0
  224. package/dist/permissions/index.js +3 -0
  225. package/dist/permissions/service.d.ts +80 -0
  226. package/dist/permissions/service.js +210 -0
  227. package/dist/permissions/tables.d.ts +5 -0
  228. package/dist/permissions/tables.js +68 -0
  229. package/dist/permissions/types.d.ts +33 -0
  230. package/dist/permissions/types.js +1 -0
  231. package/dist/runtime/app-shell.js +163 -0
  232. package/dist/runtime/auth.d.ts +10 -0
  233. package/dist/runtime/auth.js +30 -0
  234. package/dist/runtime/communication.d.ts +137 -0
  235. package/dist/runtime/communication.js +228 -0
  236. package/dist/runtime/error-boundary.d.ts +23 -0
  237. package/dist/runtime/error-boundary.js +120 -0
  238. package/dist/runtime/i18n.d.ts +6 -1
  239. package/dist/runtime/i18n.js +42 -21
  240. package/dist/runtime/router-data.d.ts +3 -0
  241. package/dist/runtime/router-data.js +102 -17
  242. package/dist/runtime/router-hydration.js +25 -0
  243. package/dist/runtime/router.d.ts +16 -1
  244. package/dist/runtime/router.js +188 -42
  245. package/dist/runtime/socket-client.d.ts +2 -0
  246. package/dist/runtime/socket-client.js +30 -0
  247. package/dist/runtime/webrtc.d.ts +47 -0
  248. package/dist/runtime/webrtc.js +178 -0
  249. package/dist/shared/graceful-shutdown.d.ts +8 -0
  250. package/dist/shared/graceful-shutdown.js +36 -0
  251. package/dist/shared/health.d.ts +8 -0
  252. package/dist/shared/health.js +25 -0
  253. package/dist/shared/llms-txt.d.ts +31 -0
  254. package/dist/shared/llms-txt.js +85 -0
  255. package/dist/shared/logger.d.ts +32 -0
  256. package/dist/shared/logger.js +93 -0
  257. package/dist/shared/meta.d.ts +27 -0
  258. package/dist/shared/meta.js +71 -0
  259. package/dist/shared/middleware-runner.d.ts +9 -0
  260. package/dist/shared/middleware-runner.js +29 -0
  261. package/dist/shared/rate-limit.d.ts +18 -0
  262. package/dist/shared/rate-limit.js +71 -0
  263. package/dist/shared/request-id.d.ts +5 -0
  264. package/dist/shared/request-id.js +18 -0
  265. package/dist/shared/route-matching.js +16 -1
  266. package/dist/shared/security-headers.d.ts +18 -0
  267. package/dist/shared/security-headers.js +38 -0
  268. package/dist/shared/socket-io-setup.d.ts +11 -0
  269. package/dist/shared/socket-io-setup.js +51 -0
  270. package/dist/shared/types.d.ts +14 -0
  271. package/dist/shared/utils.d.ts +33 -7
  272. package/dist/shared/utils.js +164 -27
  273. package/dist/storage/adapters/local.d.ts +44 -0
  274. package/dist/storage/adapters/local.js +85 -0
  275. package/dist/storage/adapters/s3.d.ts +32 -0
  276. package/dist/storage/adapters/s3.js +116 -0
  277. package/dist/storage/adapters/types.d.ts +53 -0
  278. package/dist/storage/adapters/types.js +1 -0
  279. package/dist/storage/index.d.ts +76 -0
  280. package/dist/storage/index.js +83 -0
  281. package/package.json +19 -7
  282. package/templates/blog/api/posts.ts +4 -18
  283. package/templates/blog/data/migrations/001_init.sql +6 -5
  284. package/templates/blog/lumenjs.config.ts +3 -0
  285. package/templates/blog/package.json +14 -0
  286. package/templates/blog/pages/_layout.ts +25 -0
  287. package/templates/blog/pages/index.ts +48 -22
  288. package/templates/blog/pages/posts/[slug].ts +45 -20
  289. package/templates/blog/pages/tag/[tag].ts +44 -0
  290. package/templates/dashboard/api/stats.ts +8 -5
  291. package/templates/dashboard/lumenjs.config.ts +3 -0
  292. package/templates/dashboard/package.json +14 -0
  293. package/templates/dashboard/pages/_layout.ts +25 -0
  294. package/templates/dashboard/pages/index.ts +54 -23
  295. package/templates/dashboard/pages/settings/index.ts +29 -0
  296. package/templates/default/lumenjs.config.ts +3 -0
  297. package/templates/default/package.json +14 -0
  298. package/templates/default/pages/index.ts +24 -0
  299. package/templates/social/api/posts/[id].ts +14 -0
  300. package/templates/social/api/posts.ts +11 -0
  301. package/templates/social/api/profile/[username].ts +10 -0
  302. package/templates/social/api/upload.ts +19 -0
  303. package/templates/social/data/migrations/001_init.sql +78 -0
  304. package/templates/social/data/migrations/002_add_image_url.sql +1 -0
  305. package/templates/social/data/migrations/003_auth.sql +7 -0
  306. package/templates/social/docs/architecture.md +76 -0
  307. package/templates/social/docs/components.md +100 -0
  308. package/templates/social/docs/data.md +89 -0
  309. package/templates/social/docs/pages.md +96 -0
  310. package/templates/social/docs/theming.md +52 -0
  311. package/templates/social/lib/media.ts +130 -0
  312. package/templates/social/lumenjs.auth.ts +21 -0
  313. package/templates/social/lumenjs.config.ts +3 -0
  314. package/templates/social/package.json +5 -0
  315. package/templates/social/pages/_layout.ts +239 -0
  316. package/templates/social/pages/apps/[id].ts +173 -0
  317. package/templates/social/pages/apps/index.ts +116 -0
  318. package/templates/social/pages/auth/login.ts +92 -0
  319. package/templates/social/pages/bookmarks.ts +57 -0
  320. package/templates/social/pages/explore.ts +73 -0
  321. package/templates/social/pages/index.ts +351 -0
  322. package/templates/social/pages/messages.ts +298 -0
  323. package/templates/social/pages/new.ts +77 -0
  324. package/templates/social/pages/notifications.ts +73 -0
  325. package/templates/social/pages/post/[id].ts +124 -0
  326. package/templates/social/pages/profile/[username].ts +100 -0
  327. package/templates/social/pages/settings/accessibility.ts +153 -0
  328. package/templates/social/pages/settings/account.ts +260 -0
  329. package/templates/social/pages/settings/help.ts +141 -0
  330. package/templates/social/pages/settings/language.ts +103 -0
  331. package/templates/social/pages/settings/privacy.ts +183 -0
  332. package/templates/social/pages/settings/security.ts +133 -0
  333. package/templates/social/pages/settings.ts +185 -0
@@ -0,0 +1,14 @@
1
+ import { createFilePanel, loadFileList, saveCurrentFile, closeFilePanel, getFilePanel, getIsFilePanelOpen, setIsFilePanelOpen, getCurrentEditorFile } from './file-editor.js';
2
+ export { createFilePanel, loadFileList, saveCurrentFile, closeFilePanel, getFilePanel, getIsFilePanelOpen, setIsFilePanelOpen, getCurrentEditorFile, };
3
+ export declare function initToolbarRefs(refs: {
4
+ selectOverlay: HTMLDivElement;
5
+ selectedElement: {
6
+ current: HTMLElement | null;
7
+ };
8
+ deselect: () => void;
9
+ }): void;
10
+ export declare function getToolbar(): HTMLDivElement;
11
+ export declare function getIsEditorMode(): boolean;
12
+ export declare function createToolbar(): HTMLDivElement;
13
+ export declare function updateSelectionInfo(el: HTMLElement | null): void;
14
+ export declare function setMode(editMode: boolean): void;
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Editor Toolbar — main top bar with file browser, edit/preview toggle, and file editor.
3
+ */
4
+ import { parseSourceAttr } from './element-annotator.js';
5
+ import { setPreviewMode } from './editor-bridge.js';
6
+ import { injectToolbarStyles } from './toolbar-styles.js';
7
+ import { createFilePanel, loadFileList, saveCurrentFile, closeFilePanel, getFilePanel, getIsFilePanelOpen, setIsFilePanelOpen, getCurrentEditorFile, initFileEditorToolbar, } from './file-editor.js';
8
+ // Re-export file-editor exports for backwards compatibility
9
+ export { createFilePanel, loadFileList, saveCurrentFile, closeFilePanel, getFilePanel, getIsFilePanelOpen, setIsFilePanelOpen, getCurrentEditorFile, };
10
+ const isTouchDevice = ('ontouchstart' in window) || navigator.maxTouchPoints > 0;
11
+ let toolbar;
12
+ let isEditorMode = true;
13
+ // These are set by standalone-overlay during init
14
+ let selectOverlayRef;
15
+ let selectedElementRef;
16
+ let deselectFn;
17
+ export function initToolbarRefs(refs) {
18
+ selectOverlayRef = refs.selectOverlay;
19
+ selectedElementRef = refs.selectedElement;
20
+ deselectFn = refs.deselect;
21
+ }
22
+ export function getToolbar() {
23
+ return toolbar;
24
+ }
25
+ export function getIsEditorMode() {
26
+ return isEditorMode;
27
+ }
28
+ export function createToolbar() {
29
+ const bar = document.createElement('div');
30
+ bar.id = 'nk-editor-toolbar';
31
+ bar.innerHTML = `
32
+ <div class="nk-toolbar-inner">
33
+ <div class="nk-toolbar-left">
34
+ <button class="nk-tb-btn nk-tb-files" title="Browse Files">
35
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"/></svg>
36
+ <span class="nk-tb-files-label">Files</span>
37
+ </button>
38
+ <span class="nk-tb-divider"></span>
39
+ <button class="nk-tb-toggle" id="nk-tb-toggle" title="Toggle Edit / Preview">
40
+ <span class="nk-tb-toggle-edit active">Edit</span>
41
+ <span class="nk-tb-toggle-preview">Preview</span>
42
+ </button>
43
+ </div>
44
+ <div class="nk-toolbar-center" id="nk-tb-selection">
45
+ <span class="nk-tb-hint">${isTouchDevice ? 'Tap to select. Double-tap text to edit.' : 'Click to select. Double-click text to edit.'}</span>
46
+ </div>
47
+ <div class="nk-toolbar-right">
48
+ <div class="nk-tb-page-ai">
49
+ <span class="nk-tb-page-ai-icon">✦</span>
50
+ <input class="nk-tb-page-ai-input" type="text" placeholder="Ask AI about this page..." />
51
+ <button class="nk-tb-page-ai-send" disabled title="Send">▶</button>
52
+ </div>
53
+ <button class="nk-tb-btn nk-tb-project-ai" title="Project AI Chat" style="display:flex;align-items:center;gap:4px">
54
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>
55
+ <span class="nk-tb-project-ai-label">Chat</span>
56
+ </button>
57
+ <button class="nk-tb-btn nk-tb-deselect" style="display:none" title="Deselect">
58
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
59
+ </button>
60
+ </div>
61
+ </div>
62
+ `;
63
+ injectToolbarStyles();
64
+ document.body.appendChild(bar);
65
+ toolbar = bar;
66
+ // Wire up the toolbar reference for the file editor module
67
+ initFileEditorToolbar(bar);
68
+ return bar;
69
+ }
70
+ export function updateSelectionInfo(el) {
71
+ const center = document.getElementById('nk-tb-selection');
72
+ const deselectBtn = toolbar.querySelector('.nk-tb-deselect');
73
+ if (!el) {
74
+ center.innerHTML = `<span class="nk-tb-hint">${isTouchDevice ? 'Tap to select. Double-tap text to edit.' : 'Click to select. Double-click text to edit.'}</span>`;
75
+ deselectBtn.style.display = 'none';
76
+ return;
77
+ }
78
+ const sourceAttr = el.getAttribute('data-nk-source');
79
+ const source = sourceAttr ? parseSourceAttr(sourceAttr) : null;
80
+ const tag = el.tagName.toLowerCase();
81
+ const attrs = Array.from(el.attributes)
82
+ .filter(a => !a.name.startsWith('data-nk-'))
83
+ .map(a => a.value ? `${a.name}="${a.value}"` : a.name)
84
+ .slice(0, 3);
85
+ const attrStr = attrs.length ? ` <span class="nk-tb-attrs">${attrs.join(' ')}</span>` : '';
86
+ const sourceStr = source ? ` <span class="nk-tb-source">${source.file}:${source.line}</span>` : '';
87
+ center.innerHTML = `<span class="nk-tb-tag">&lt;${tag}&gt;</span>${attrStr}${sourceStr}`;
88
+ deselectBtn.style.display = 'inline-flex';
89
+ }
90
+ export function setMode(editMode) {
91
+ isEditorMode = editMode;
92
+ try {
93
+ localStorage.setItem('nk-editor-mode', editMode ? 'edit' : 'preview');
94
+ }
95
+ catch { }
96
+ const toggle = document.getElementById('nk-tb-toggle');
97
+ const editSpan = toggle.querySelector('.nk-tb-toggle-edit');
98
+ const previewSpan = toggle.querySelector('.nk-tb-toggle-preview');
99
+ const center = document.getElementById('nk-tb-selection');
100
+ setPreviewMode(!editMode);
101
+ if (editMode) {
102
+ editSpan.classList.add('active');
103
+ previewSpan.classList.remove('active');
104
+ center.innerHTML = `<span class="nk-tb-hint">${isTouchDevice ? 'Tap to select. Double-tap text to edit.' : 'Click to select. Double-click text to edit.'}</span>`;
105
+ }
106
+ else {
107
+ previewSpan.classList.add('active');
108
+ editSpan.classList.remove('active');
109
+ center.innerHTML = '<span class="nk-tb-hint">Preview mode — interact normally</span>';
110
+ // Deselect and close panels
111
+ deselectFn();
112
+ if (getIsFilePanelOpen())
113
+ closeFilePanel();
114
+ }
115
+ }
@@ -0,0 +1,9 @@
1
+ export declare function initFileEditorToolbar(tb: HTMLDivElement): void;
2
+ export declare function getFilePanel(): HTMLDivElement;
3
+ export declare function getIsFilePanelOpen(): boolean;
4
+ export declare function setIsFilePanelOpen(val: boolean): void;
5
+ export declare function getCurrentEditorFile(): string | null;
6
+ export declare function createFilePanel(): HTMLDivElement;
7
+ export declare function loadFileList(): Promise<void>;
8
+ export declare function saveCurrentFile(): Promise<void>;
9
+ export declare function closeFilePanel(): void;
@@ -0,0 +1,236 @@
1
+ /**
2
+ * File Editor — file panel, file list, editor opening/saving, and close logic.
3
+ */
4
+ import { highlightCode } from './syntax-highlighter.js';
5
+ import { readFile, writeFile } from './editor-api-client.js';
6
+ import { CodeJar } from 'codejar';
7
+ let filePanel;
8
+ let isFilePanelOpen = false;
9
+ let currentEditorFile = null;
10
+ let jar = null;
11
+ /** Provide the toolbar element so closeFilePanel can access it. */
12
+ let toolbarEl;
13
+ export function initFileEditorToolbar(tb) {
14
+ toolbarEl = tb;
15
+ }
16
+ export function getFilePanel() {
17
+ return filePanel;
18
+ }
19
+ export function getIsFilePanelOpen() {
20
+ return isFilePanelOpen;
21
+ }
22
+ export function setIsFilePanelOpen(val) {
23
+ isFilePanelOpen = val;
24
+ }
25
+ export function getCurrentEditorFile() {
26
+ return currentEditorFile;
27
+ }
28
+ export function createFilePanel() {
29
+ const panel = document.createElement('div');
30
+ panel.id = 'nk-file-panel';
31
+ panel.innerHTML = `
32
+ <div class="nk-fp-header">
33
+ <div class="nk-fp-tabs">
34
+ <button class="nk-fp-tab active" data-tab="files">Files</button>
35
+ <button class="nk-fp-tab" data-tab="pages">Pages</button>
36
+ </div>
37
+ <button class="nk-fp-close-btn" id="nk-fp-close">
38
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
39
+ </button>
40
+ </div>
41
+ <div class="nk-fp-list" id="nk-fp-list"></div>
42
+ <div class="nk-fp-pages" id="nk-fp-pages" style="display:none"></div>
43
+ `;
44
+ document.body.appendChild(panel);
45
+ // File editor panel
46
+ const editor = document.createElement('div');
47
+ editor.id = 'nk-file-editor';
48
+ editor.innerHTML = `
49
+ <div class="nk-fe-header">
50
+ <span class="nk-fe-path" id="nk-fe-path"></span>
51
+ <div class="nk-fe-btns">
52
+ <button class="nk-fe-save" id="nk-fe-save">Save</button>
53
+ <button class="nk-fe-cancel" id="nk-fe-close">Close</button>
54
+ </div>
55
+ </div>
56
+ <div class="nk-fe-editor" id="nk-fe-editor"></div>
57
+ `;
58
+ document.body.appendChild(editor);
59
+ // Initialize CodeJar with syntax highlighting and auto-save
60
+ let saveDebounce = null;
61
+ const editorEl = editor.querySelector('#nk-fe-editor');
62
+ jar = CodeJar(editorEl, highlightCode, { tab: ' ', spellcheck: false });
63
+ jar.onUpdate((code) => {
64
+ if (saveDebounce)
65
+ clearTimeout(saveDebounce);
66
+ saveDebounce = setTimeout(() => {
67
+ if (currentEditorFile) {
68
+ const saveBtn = document.getElementById('nk-fe-save');
69
+ saveBtn.textContent = 'Saving...';
70
+ writeFile(currentEditorFile, code).then(() => {
71
+ saveBtn.textContent = 'Saved!';
72
+ saveBtn.style.background = '#22c55e';
73
+ setTimeout(() => { saveBtn.textContent = 'Save'; saveBtn.style.background = ''; }, 1500);
74
+ }).catch(() => {
75
+ saveBtn.textContent = 'Error!';
76
+ saveBtn.style.background = '#ef4444';
77
+ setTimeout(() => { saveBtn.textContent = 'Save'; saveBtn.style.background = ''; }, 2000);
78
+ });
79
+ }
80
+ }, 1000);
81
+ });
82
+ // Tab switching
83
+ let pagesLoaded = false;
84
+ panel.addEventListener('click', (e) => {
85
+ const tab = e.target.closest('.nk-fp-tab');
86
+ if (!tab)
87
+ return;
88
+ const tabName = tab.dataset.tab;
89
+ panel.querySelectorAll('.nk-fp-tab').forEach(t => t.classList.remove('active'));
90
+ tab.classList.add('active');
91
+ const filesList = panel.querySelector('#nk-fp-list');
92
+ const pagesList = panel.querySelector('#nk-fp-pages');
93
+ if (tabName === 'files') {
94
+ filesList.style.display = '';
95
+ pagesList.style.display = 'none';
96
+ }
97
+ else {
98
+ filesList.style.display = 'none';
99
+ pagesList.style.display = '';
100
+ if (!pagesLoaded) {
101
+ pagesLoaded = true;
102
+ loadPagesList();
103
+ }
104
+ }
105
+ });
106
+ filePanel = panel;
107
+ return panel;
108
+ }
109
+ async function loadPagesList() {
110
+ const container = document.getElementById('nk-fp-pages');
111
+ if (!container)
112
+ return;
113
+ try {
114
+ const res = await fetch('/__nk_editor/routes');
115
+ const data = await res.json();
116
+ const routes = data.routes || [];
117
+ // Group by deepest layout
118
+ const groups = new Map();
119
+ for (const r of routes) {
120
+ const layoutLabel = r.layouts?.length ? r.layouts[r.layouts.length - 1].tagName : 'no-layout';
121
+ if (!groups.has(layoutLabel))
122
+ groups.set(layoutLabel, []);
123
+ groups.get(layoutLabel).push(r);
124
+ }
125
+ let html = '';
126
+ for (const [layout, groupRoutes] of groups) {
127
+ html += `<div class="nk-fp-layout-group">`;
128
+ html += `<div class="nk-fp-layout-label">${layout}</div>`;
129
+ for (const r of groupRoutes) {
130
+ const currentPath = window.location.pathname;
131
+ // Match current page (handle dynamic segments)
132
+ const routeRegex = r.path.replace(/:[^/]+/g, '[^/]+');
133
+ const isActive = new RegExp(`^${routeRegex}$`).test(currentPath);
134
+ html += `<div class="nk-fp-route${isActive ? ' active' : ''}" data-route="${r.path}">${r.path}</div>`;
135
+ }
136
+ html += `</div>`;
137
+ }
138
+ container.innerHTML = html;
139
+ container.addEventListener('click', (e) => {
140
+ const route = e.target.closest('.nk-fp-route');
141
+ if (!route)
142
+ return;
143
+ window.location.href = route.dataset.route;
144
+ });
145
+ }
146
+ catch {
147
+ container.innerHTML = '<div style="padding:12px;color:#f87171;font-size:11px">Failed to load pages</div>';
148
+ }
149
+ }
150
+ function getFileIcon(name) {
151
+ if (name.endsWith('.ts'))
152
+ return '<span style="color:#3178c6">TS</span>';
153
+ if (name.endsWith('.js'))
154
+ return '<span style="color:#f7df1e">JS</span>';
155
+ if (name.endsWith('.json'))
156
+ return '<span style="color:#94a3b8">{}</span>';
157
+ if (name.endsWith('.css'))
158
+ return '<span style="color:#38bdf8">#</span>';
159
+ return '<span style="color:#64748b">~</span>';
160
+ }
161
+ export async function loadFileList() {
162
+ const listEl = document.getElementById('nk-fp-list');
163
+ if (!listEl)
164
+ return;
165
+ try {
166
+ const res = await fetch('/__nk_editor/files');
167
+ const data = await res.json();
168
+ const files = data.files || [];
169
+ listEl.innerHTML = files.map(f => `<div class="nk-fp-item" data-file="${f}">
170
+ <span class="nk-fp-icon">${getFileIcon(f)}</span>
171
+ <span>${f}</span>
172
+ </div>`).join('');
173
+ listEl.addEventListener('click', (e) => {
174
+ const item = e.target.closest('.nk-fp-item');
175
+ if (!item)
176
+ return;
177
+ const file = item.dataset.file;
178
+ openFileEditor(file);
179
+ listEl.querySelectorAll('.nk-fp-item').forEach(el => el.classList.remove('active'));
180
+ item.classList.add('active');
181
+ });
182
+ }
183
+ catch {
184
+ listEl.innerHTML = '<div style="padding:12px;color:#f87171;font-size:11px">Failed to load files</div>';
185
+ }
186
+ }
187
+ async function openFileEditor(filePath) {
188
+ const editorPanel = document.getElementById('nk-file-editor');
189
+ const pathEl = document.getElementById('nk-fe-path');
190
+ // On mobile, close the file list to make room for the editor
191
+ if (window.innerWidth <= 640) {
192
+ filePanel.classList.remove('open');
193
+ }
194
+ try {
195
+ const data = await readFile(filePath);
196
+ currentEditorFile = filePath;
197
+ pathEl.textContent = filePath;
198
+ jar.updateCode(data.content);
199
+ editorPanel.classList.add('open');
200
+ }
201
+ catch {
202
+ pathEl.textContent = filePath;
203
+ jar.updateCode('// Error loading file');
204
+ editorPanel.classList.add('open');
205
+ }
206
+ }
207
+ export async function saveCurrentFile() {
208
+ if (!currentEditorFile || !jar)
209
+ return;
210
+ const saveBtn = document.getElementById('nk-fe-save');
211
+ try {
212
+ saveBtn.textContent = 'Saving...';
213
+ await writeFile(currentEditorFile, jar.toString());
214
+ saveBtn.textContent = 'Saved!';
215
+ saveBtn.style.background = '#22c55e';
216
+ setTimeout(() => {
217
+ saveBtn.textContent = 'Save';
218
+ saveBtn.style.background = '';
219
+ }, 1500);
220
+ }
221
+ catch {
222
+ saveBtn.textContent = 'Error!';
223
+ saveBtn.style.background = '#ef4444';
224
+ setTimeout(() => {
225
+ saveBtn.textContent = 'Save';
226
+ saveBtn.style.background = '';
227
+ }, 2000);
228
+ }
229
+ }
230
+ export function closeFilePanel() {
231
+ isFilePanelOpen = false;
232
+ filePanel.classList.remove('open');
233
+ toolbarEl.querySelector('.nk-tb-files').classList.remove('active');
234
+ document.getElementById('nk-file-editor')?.classList.remove('open');
235
+ currentEditorFile = null;
236
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * File service for the editor — scoped to a single project directory.
3
+ * Provides safe file CRUD with path-traversal protection.
4
+ */
5
+ export declare class EditorFileService {
6
+ private projectDir;
7
+ constructor(projectDir: string);
8
+ listFiles(): string[];
9
+ readFile(filePath: string): string;
10
+ writeFile(filePath: string, content: string): void;
11
+ private walkDir;
12
+ /**
13
+ * Resolve a file path within the project, preventing path traversal.
14
+ */
15
+ private resolveSafe;
16
+ }
@@ -0,0 +1,52 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ /**
4
+ * File service for the editor — scoped to a single project directory.
5
+ * Provides safe file CRUD with path-traversal protection.
6
+ */
7
+ export class EditorFileService {
8
+ constructor(projectDir) {
9
+ this.projectDir = projectDir;
10
+ }
11
+ listFiles() {
12
+ if (!fs.existsSync(this.projectDir))
13
+ return [];
14
+ const results = [];
15
+ this.walkDir(this.projectDir, results);
16
+ return results;
17
+ }
18
+ readFile(filePath) {
19
+ const resolved = this.resolveSafe(filePath);
20
+ return fs.readFileSync(resolved, 'utf-8');
21
+ }
22
+ writeFile(filePath, content) {
23
+ const resolved = this.resolveSafe(filePath);
24
+ fs.mkdirSync(path.dirname(resolved), { recursive: true });
25
+ fs.writeFileSync(resolved, content);
26
+ }
27
+ walkDir(dir, results) {
28
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
29
+ for (const entry of entries) {
30
+ const full = path.join(dir, entry.name);
31
+ const relative = path.relative(this.projectDir, full);
32
+ if (entry.isDirectory()) {
33
+ if (entry.name !== 'node_modules' && entry.name !== '.git' && entry.name !== '.lumenjs') {
34
+ this.walkDir(full, results);
35
+ }
36
+ }
37
+ else {
38
+ results.push(relative);
39
+ }
40
+ }
41
+ }
42
+ /**
43
+ * Resolve a file path within the project, preventing path traversal.
44
+ */
45
+ resolveSafe(filePath) {
46
+ const resolved = path.resolve(this.projectDir, filePath);
47
+ if (!resolved.startsWith(this.projectDir + path.sep) && resolved !== this.projectDir) {
48
+ throw new Error('Path traversal detected');
49
+ }
50
+ return resolved;
51
+ }
52
+ }
@@ -0,0 +1 @@
1
+ export declare function generateI18nKey(sourceFile: string, tag: string, text: string): string;
@@ -0,0 +1,7 @@
1
+ export function generateI18nKey(sourceFile, tag, text) {
2
+ const basename = sourceFile.split('/').pop()?.replace(/\.\w+$/, '') || 'page';
3
+ const slug = text.substring(0, 30).toLowerCase()
4
+ .replace(/[^a-z0-9]+/g, '_')
5
+ .replace(/^_|_$/g, '');
6
+ return `${basename}.${tag}.${slug}`;
7
+ }
@@ -1 +1,6 @@
1
+ /**
2
+ * Trigger inline text editing on an element directly.
3
+ * Called from standalone-overlay.ts on double-tap (mobile).
4
+ */
5
+ export declare function triggerInlineEdit(target: HTMLElement): boolean;
1
6
  export declare function setupInlineTextEdit(): void;