diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f759ae2..5d1677a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,7 +18,8 @@ // 4173: VitePress Docs (Preview) // 5173: Web App (Must be strictly 5173 for Electron IPC compatibility) // 3000: Landing App (Isolated from Vite's default 517x blast radius) - "forwardPorts": [6060, 4173, 5173, 3000], + // 3005: Showcase App + "forwardPorts": [6060, 4173, 5173, 3000, 3005], "portsAttributes": { "6060": { @@ -33,6 +34,10 @@ "label": "Web App (Electron Target)", "onAutoForward": "notify" }, + "3005": { + "label": "Showcase App", + "onAutoForward": "notify" + }, "3000": { "label": "Landing App (Public)", "onAutoForward": "notify" diff --git a/apps/showcase/.eslintrc.cjs b/apps/showcase/.eslintrc.cjs new file mode 100644 index 0000000..a779c57 --- /dev/null +++ b/apps/showcase/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ['@repo/eslint-config/react.js'], +}; diff --git a/apps/showcase/index.html b/apps/showcase/index.html new file mode 100644 index 0000000..e09f575 --- /dev/null +++ b/apps/showcase/index.html @@ -0,0 +1,13 @@ + + +
+ + + +@repo/core-events — zero coupling, strict typing, high performance.
+ {DEVICE_EVENTS.PRINT_RECEIPT} event.
+ The PrinterListener listens for it and simulates interacting with a physical printer.
+ WS:STOCK_UPDATE every 20ms.
+ Each StockRow subscribes to the global event but only updates when{' '}
+ payload.id === row.id. The parent grid never re-renders.
+ @repo/core-storage
+ {AUTH_EVENTS.PROFILE_UPDATED}.
+ StorageSyncListener silently catches it in the background and saves to IndexedDB via secureIndexedDB.
+ | + Ticker + | ++ Price + | ++ Change + | ++ Volume + | ++ Renders + | +
|---|
+ Pipeline: Faro + Custom Span "booking.list.fetch" → Bearer Token → GET /bookings +
+ + + + {error && ( +
+ ❌ {error}
+
+ )}
+
+ {result && (
+
+ {JSON.stringify(result, null, 2)}
+
+ )}
+ + Current Active Language: {activeLang} +
+ + {/* ─── Admin Panel ──────────────────────────────────────────── */} ++ Simulate a backend CMS. Save the vocabulary overrides to IndexedDB. +
+ +
+ {dbPayloadStr}
+
+ + Change the language. The callback simulates a 1-second backend API request. +
+ +
+ common:save
+ {t('common:save')}
+
+ booking:select_date
+ {t('booking:select_date')}
+
+ Simulates a user logging in. It fetches the config directly from IndexedDB (mock database) and applies the + deep-merge override. +
+ +| Key | +Value | +
|---|---|
+ booking:module_name
+ |
+ {t('booking:module_name')} | +
+ booking:header.title
+ |
+ {t('booking:header.title')} | +
+ booking:header.subtitle
+ |
+ {t('booking:header.subtitle')} | +
+ Key: {LS_KEY} — stored encrypted at rest
+
+ Verify: DevTools → Application → Local Storage
+
{lsResult}
+
+ Key: {IDB_KEY} — plain JSON (not in ENCRYPTED_KEYS)
+
+ Verify: DevTools → Application → IndexedDB → app_db
+
{idbResult}
+ This is a highly important update. Please observe the following:
Thank you for your cooperation.
", + realPokeSelect: null, + multiRealPokeSelect: [] + } + }); + + const onSubmit = (data: any) => console.log('All Fields Submitted:', data); + const data = watch(); + + return ( +{JSON.stringify(data, null, 2)}
+ Start typing to see the live preview...
", + }, + }); + + // Micro-subscriptions via useWatch + const userType = useWatch({ control, name: 'userType' }); + const hasSpouse = useWatch({ control, name: 'hasSpouse' }); + const newsletter = useWatch({ control, name: 'newsletter' }); + const department = useWatch({ control, name: 'department' }); + const role = useWatch({ control, name: 'role' }); + const regions = useWatch({ control, name: 'regions' }); + const watchedRichTextLive = useWatch({ control, name: 'richTextLive' }); + + // Use the custom hook to cleanly unregister and reset fields when hidden + useConditionalField({ + condition: userType === 'CORPORATE', + name: 'corporateTaxId', + setValue, + unregister, + mode: 'unregister', + defaultValue: '', + }); + + useConditionalField({ + condition: hasSpouse === true, + name: 'spouseName', + setValue, + unregister, + mode: 'unregister', + defaultValue: '', + }); + + // Use the reset mode to clear values and errors without unregistering the field + useConditionalField({ + condition: newsletter === true, + name: 'newsletterEmail', + setValue, + clearErrors, + mode: 'reset', + defaultValue: '', + }); + + // Cascading Dropdown Logic: Department -> Role + const roleOptions: Record{JSON.stringify(allValues, null, 2)}
+ {JSON.stringify(data, null, 2)}
+ + Status Auto-Update: {status} +
+ + + +{JSON.stringify(liveConfig, null, 2)}
+