diff --git a/apps/matrix/CLAUDE.md b/apps/matrix/CLAUDE.md index 6132c4512..b84f56f87 100644 --- a/apps/matrix/CLAUDE.md +++ b/apps/matrix/CLAUDE.md @@ -1,19 +1,20 @@ -# Matrix Client +# Manalink -Self-hosted Matrix chat client built with SvelteKit and matrix-js-sdk. +Secure Matrix messaging client - a bridge to decentralized communication. ## Project Overview -A minimal, privacy-focused Matrix client that connects to your self-hosted Synapse server (matrix.mana.how). +Manalink is a privacy-focused Matrix client built with SvelteKit. It connects to Matrix homeservers (default: matrix.mana.how) and supports PWA installation for mobile devices. ### Tech Stack | Layer | Technology | |-------|------------| | Frontend | SvelteKit 2, Svelte 5 (runes), Tailwind CSS 4 | -| Matrix SDK | matrix-js-sdk | +| Matrix SDK | matrix-js-sdk + matrix-sdk-crypto-wasm | | State Management | Svelte 5 runes ($state, $derived) | | Icons | @manacore/shared-icons (Phosphor) | +| PWA | @vite-pwa/sveltekit + Workbox | | Date Handling | date-fns | ## Project Structure @@ -21,7 +22,7 @@ A minimal, privacy-focused Matrix client that connects to your self-hosted Synap ``` apps/matrix/ ├── apps/ -│ └── web/ # SvelteKit web client +│ └── web/ # SvelteKit web client (PWA) │ ├── src/ │ │ ├── routes/ │ │ │ ├── (auth)/ # Login flow @@ -31,10 +32,16 @@ apps/matrix/ │ │ ├── matrix/ # Matrix SDK integration │ │ │ ├── store.svelte.ts # Reactive Matrix store │ │ │ ├── client.ts # Login/auth functions +│ │ │ ├── crypto.ts # E2EE utilities │ │ │ ├── types.ts # TypeScript types │ │ │ └── polyfills.ts # Browser polyfills │ │ └── components/ -│ │ └── chat/ # Chat UI components +│ │ ├── chat/ # Chat UI components +│ │ ├── call/ # VoIP call components +│ │ └── crypto/ # E2EE verification UI +│ ├── static/ # PWA icons and assets +│ ├── scripts/ +│ │ └── generate-icons.mjs # Icon generation script │ └── package.json └── packages/ └── shared/ # Shared types @@ -43,15 +50,42 @@ apps/matrix/ ## Development ```bash -# Start the Matrix web client +# Start the web client pnpm dev:matrix:web # Or from monorepo root pnpm matrix:dev + +# Generate PWA icons (after changing favicon.svg) +cd apps/matrix/apps/web && node scripts/generate-icons.mjs ``` The client runs on **http://localhost:5180** +## PWA Features + +Manalink is a Progressive Web App with: + +- **Installable** on iOS/Android homescreen +- **Offline support** via Service Worker caching +- **Push notifications** (Web Push API) +- **App shortcuts** for quick actions + +### Caching Strategy + +| Content | Strategy | TTL | +|---------|----------|-----| +| Matrix API | NetworkFirst | 5 min | +| Images/Avatars | CacheFirst | 30 days | +| Fonts | CacheFirst | 1 year | +| App Shell | StaleWhileRevalidate | - | + +### Installation + +1. Open https://[your-domain] in a mobile browser +2. Tap "Add to Home Screen" (iOS) or install prompt (Android/Chrome) +3. Launch from homescreen for fullscreen app experience + ## Key Files ### Matrix Store (`src/lib/matrix/store.svelte.ts`) @@ -90,26 +124,30 @@ if (result.success) { ## Features ### Phase 1 (Current) -- [x] Password login +- [x] Password login + SSO (Mana Core) - [x] Room list (DMs and groups) -- [x] Message timeline +- [x] Message timeline with pagination - [x] Send text messages - [x] Typing indicators - [x] Read receipts -- [x] Unread counts -- [x] Message pagination (load more) +- [x] Unread/highlight counts +- [x] Room creation +- [x] Room settings +- [x] Message search +- [x] PWA support -### Phase 2 (Planned) +### Phase 2 (In Progress) - [ ] End-to-end encryption (E2EE) - [ ] File/image uploads - [ ] Message editing/deletion -- [ ] Room creation - [ ] User search/invite +- [ ] Message reactions ### Phase 3 (Future) - [ ] VoIP calls (WebRTC) - [ ] Video calls - [ ] Screen sharing +- [ ] Capacitor native wrapper ## Configuration @@ -133,15 +171,24 @@ matrix-js-sdk requires polyfills for browser usage. These are automatically load ### Vite Configuration -Special Vite config in `vite.config.ts`: +Special Vite config for Matrix SDK + PWA: ```typescript -define: { - global: 'globalThis', +// WASM headers for crypto +server: { + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, }, -optimizeDeps: { - include: ['buffer', 'events'], -} +// PWA plugin +plugins: [ + SvelteKitPWA({ + registerType: 'autoUpdate', + manifest: { ... }, + workbox: { ... }, + }), +], ``` ### Client-Side Only @@ -172,8 +219,16 @@ This is a known issue with typed-event-emitter. Make sure polyfills are loaded b The initial sync can take time depending on room history. Check `matrixStore.syncState` for status. +### PWA not installing + +1. Ensure HTTPS is enabled +2. Check manifest.json is served correctly +3. Verify icons exist at specified paths +4. Check DevTools > Application > Manifest for errors + ## Related Documentation - [Matrix Client-Server API](https://spec.matrix.org/latest/client-server-api/) - [matrix-js-sdk docs](https://matrix-org.github.io/matrix-js-sdk/) - [Synapse Admin API](https://element-hq.github.io/synapse/latest/admin_api/) +- [Vite PWA Plugin](https://vite-pwa-org.netlify.app/frameworks/sveltekit.html) diff --git a/apps/matrix/apps/web/package.json b/apps/matrix/apps/web/package.json index ade0c85a6..aed2bae0f 100644 --- a/apps/matrix/apps/web/package.json +++ b/apps/matrix/apps/web/package.json @@ -20,20 +20,20 @@ "@sveltejs/vite-plugin-svelte": "^5.0.3", "@tailwindcss/vite": "^4.1.7", "@types/node": "^22.15.21", + "@vite-pwa/sveltekit": "^1.1.0", "prettier": "^3.5.3", "prettier-plugin-svelte": "^3.4.0", + "sharp": "^0.33.5", "svelte": "^5.41.0", "svelte-check": "^4.3.3", "tailwindcss": "^4.1.7", "tslib": "^2.8.1", "typescript": "^5.9.3", - "vite": "^6.3.5" + "vite": "^6.3.5", + "vite-plugin-pwa": "^1.2.0", + "workbox-window": "^7.4.0" }, "dependencies": { - "matrix-js-sdk": "^37.1.0", - "@matrix-org/matrix-sdk-crypto-wasm": "^13.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", "@manacore/shared-auth": "workspace:*", "@manacore/shared-branding": "workspace:*", "@manacore/shared-i18n": "workspace:*", @@ -41,7 +41,11 @@ "@manacore/shared-tailwind": "workspace:*", "@manacore/shared-theme": "workspace:*", "@manacore/shared-ui": "workspace:*", + "@matrix-org/matrix-sdk-crypto-wasm": "^13.0.0", + "buffer": "^6.0.3", "date-fns": "^4.1.0", + "events": "^3.3.0", + "matrix-js-sdk": "^37.1.0", "svelte-i18n": "^4.0.1" } } diff --git a/apps/matrix/apps/web/scripts/generate-icons.mjs b/apps/matrix/apps/web/scripts/generate-icons.mjs new file mode 100644 index 000000000..4a0e0f23d --- /dev/null +++ b/apps/matrix/apps/web/scripts/generate-icons.mjs @@ -0,0 +1,50 @@ +#!/usr/bin/env node +/** + * Generate PWA icons from SVG favicon + * Run: node scripts/generate-icons.mjs + * Requires: npm install -D sharp + */ + +import { readFileSync, writeFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const staticDir = join(__dirname, '..', 'static'); + +// Icon sizes to generate +const sizes = [ + { name: 'favicon.png', size: 32 }, + { name: 'pwa-192x192.png', size: 192 }, + { name: 'pwa-512x512.png', size: 512 }, + { name: 'apple-touch-icon.png', size: 180 }, +]; + +async function generateIcons() { + try { + const sharp = (await import('sharp')).default; + const svgPath = join(staticDir, 'favicon.svg'); + const svgBuffer = readFileSync(svgPath); + + for (const { name, size } of sizes) { + const outputPath = join(staticDir, name); + await sharp(svgBuffer).resize(size, size).png().toFile(outputPath); + console.log(`Generated: ${name} (${size}x${size})`); + } + + console.log('\nAll icons generated successfully!'); + } catch (error) { + if (error.code === 'ERR_MODULE_NOT_FOUND') { + console.error('Sharp is not installed. Run: pnpm add -D sharp'); + console.log('\nAlternatively, use an online tool to convert the SVG:'); + console.log('1. Open static/favicon.svg in a browser'); + console.log('2. Use https://realfavicongenerator.net/ to generate icons'); + console.log('3. Replace the placeholder PNGs in static/'); + } else { + console.error('Error generating icons:', error); + } + process.exit(1); + } +} + +generateIcons(); diff --git a/apps/matrix/apps/web/src/app.html b/apps/matrix/apps/web/src/app.html index 8997ef202..a49fca6f4 100644 --- a/apps/matrix/apps/web/src/app.html +++ b/apps/matrix/apps/web/src/app.html @@ -1,13 +1,31 @@ - +
- - -Wähle eine Unterhaltung aus der Seitenleiste oder starte einen neuen Chat
diff --git a/apps/matrix/apps/web/src/routes/(auth)/login/+page.svelte b/apps/matrix/apps/web/src/routes/(auth)/login/+page.svelte index 144e61884..7da5ac743 100644 --- a/apps/matrix/apps/web/src/routes/(auth)/login/+page.svelte +++ b/apps/matrix/apps/web/src/routes/(auth)/login/+page.svelte @@ -35,9 +35,7 @@ // Theme state let userThemePreference = $state<'light' | 'dark' | null>(null); let systemIsDark = $state( - typeof window !== 'undefined' - ? window.matchMedia('(prefers-color-scheme: dark)').matches - : true + typeof window !== 'undefined' ? window.matchMedia('(prefers-color-scheme: dark)').matches : true ); let isDark = $derived( @@ -142,14 +140,10 @@