diff --git a/apps/context/apps/web/src/app.css b/apps/context/apps/web/src/app.css new file mode 100644 index 000000000..c29749613 --- /dev/null +++ b/apps/context/apps/web/src/app.css @@ -0,0 +1,10 @@ +@import "tailwindcss"; +@import "@manacore/shared-tailwind/themes.css"; + +/* Scan shared packages for Tailwind classes */ +@source "../../../../packages/shared-ui/src"; +@source "../../../../packages/shared-auth-ui/src"; +@source "../../../../packages/shared-branding/src"; +@source "../../../../packages/shared-theme-ui/src"; +@source "../../../../packages/shared-theme-ui/src/components"; +@source "../../../../packages/shared-theme-ui/src/pages"; diff --git a/apps/context/apps/web/src/app.html b/apps/context/apps/web/src/app.html new file mode 100644 index 000000000..77a5ff52c --- /dev/null +++ b/apps/context/apps/web/src/app.html @@ -0,0 +1,12 @@ + + +
+ + + + %sveltekit.head% + + +{message}
++ {truncateText(doc.content.replace(/^#.*\n?/, ''), 150)} +
+ {/if} +{space.description}
+ {/if} +{formatDate(space.created_at)}
+$2')
+ // Inline code
+ .replace(/`([^`]+)`/g, '$1')
+ // Headers
+ .replace(/^### (.+)$/gm, '$1') + // Unordered lists + .replace(/^[-*] (.+)$/gm, '
')
+ .replace(/\n/g, '
');
+
+ // Wrap in paragraph if not already wrapped
+ if (!html.startsWith('<')) {
+ html = '
' + html + '
'; + } + + return html; +} diff --git a/apps/context/apps/web/src/lib/utils/text.ts b/apps/context/apps/web/src/lib/utils/text.ts new file mode 100644 index 000000000..8abb408cb --- /dev/null +++ b/apps/context/apps/web/src/lib/utils/text.ts @@ -0,0 +1,49 @@ +/** + * Counts words in a text string + */ +export function countWords(text: string): number { + if (!text) return 0; + return text + .trim() + .split(/\s+/) + .filter((w) => w.length > 0).length; +} + +/** + * Estimates token count (1 token ≈ 4 characters) + */ +export function estimateTokens(text: string): number { + if (!text) return 0; + return Math.ceil(text.length / 4); +} + +/** + * Formats a date string for display + */ +export function formatDate(dateString: string): string { + const date = new Date(dateString); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMin = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMs / 3600000); + const diffDays = Math.floor(diffMs / 86400000); + + if (diffMin < 1) return 'Gerade eben'; + if (diffMin < 60) return `vor ${diffMin} Min.`; + if (diffHours < 24) return `vor ${diffHours} Std.`; + if (diffDays < 7) return `vor ${diffDays} Tagen`; + + return date.toLocaleDateString('de-DE', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }); +} + +/** + * Truncates text to a given length + */ +export function truncateText(text: string, maxLength: number): string { + if (!text || text.length <= maxLength) return text || ''; + return text.substring(0, maxLength - 3) + '...'; +} diff --git a/apps/context/apps/web/src/routes/(app)/+layout.svelte b/apps/context/apps/web/src/routes/(app)/+layout.svelte new file mode 100644 index 000000000..dc0dc677a --- /dev/null +++ b/apps/context/apps/web/src/routes/(app)/+layout.svelte @@ -0,0 +1,305 @@ + + +Dein Wissensmanagement Hub
++ Erstelle deinen ersten Space und beginne mit dem Schreiben. +
+ ++ {documentsStore.stats.total} Dokumente, {documentsStore.stats.totalWords.toLocaleString()} Wörter +
+Keine Dokumente gefunden
+ ++ Dokumente enthalten dein Wissen, Kontext-Referenzen und AI-Prompts. +
+ +Dokument nicht gefunden
+ + Zurück zur Übersicht + +Keine Spaces gefunden für "{searchQuery}"
++ Spaces helfen dir, dein Wissen zu organisieren. Erstelle deinen ersten Space, um loszulegen. +
+ +{space.description}
+ {/if} +Keine Dokumente in diesem Space
+ +Aktuelles Guthaben
+Tokens
+Tokens verbraucht
+Keine Daten vorhanden
+ {/if} ++ {formatTransactionType(tx.transaction_type)} +
++ Input: {tx.prompt_tokens?.toLocaleString()} + Output: {tx.completion_tokens?.toLocaleString()} + = {tx.total_tokens?.toLocaleString()} +
+ {/if} +Noch keine Transaktionen
+ {/if} ++ {#if isOnline} + Du wirst gleich weitergeleitet... + {:else} + Einige Funktionen sind offline nicht verfügbar. Bitte überprüfe deine Internetverbindung. + {/if} +
+ + {#if !isOnline} +