fix(assets): reference logo/favicon PNGs by URL instead of importing from public/
Importing images from public/ (`import X from '../../public/res/*.png'`) is
fragile under Vite with `publicDir: false` and can white-screen the dev app —
Vite tries to resolve the public/ path as a module. Switch the five logo/
favicon call sites to the repo's existing BASE_URL URL pattern
(`${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/...`), matching how
config.json, locales, and the Element Call widget are referenced. Resolves
identically in dev and the static-copied prod build (public/res -> dist/public/res).
Sounds under public/sound/ stay ESM-imported: that folder is not copied to
dist/ by vite-plugin-static-copy, so a URL reference would 404.
Also add a Local Development section to the README (no-backend model, npm ci /
npm start on :8080, which homeserver to log in against, OIDC-on-localhost note).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -167,6 +167,23 @@ The source code lives in `/root/code/cinny`. All changes should be made on the `
|
|||||||
|
|
||||||
See [LOTUS_FEATURES.md](LOTUS_FEATURES.md) for the full feature changelog and [LOTUS_TODO.md](LOTUS_TODO.md) for the work backlog.
|
See [LOTUS_FEATURES.md](LOTUS_FEATURES.md) for the full feature changelog and [LOTUS_TODO.md](LOTUS_TODO.md) for the work backlog.
|
||||||
|
|
||||||
|
### Local Development
|
||||||
|
|
||||||
|
Lotus Chat is a **pure client — there is no backend of its own to run.** It talks directly to a Matrix homeserver (Synapse) over HTTPS, so the only thing you run locally is the Vite dev server; it connects to a real homeserver for all data. If you were looking for "the backend to pair with it," there isn't one — that's the homeserver.
|
||||||
|
|
||||||
|
**Prerequisites:** Node 20+ (CI builds on Node 24) and npm.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm ci # deps; @lotusguild/* come from our Gitea npm registry (public read — no auth/token needed)
|
||||||
|
npm start # Vite dev server → http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
The dev server defaults to **port 8080** (`vite.config.js`); if 8080 is already in use it falls through to 8081+, so check the "Local:" URL Vite prints on startup. If it boots but the page renders blank, it's almost always a failed module/asset resolution, not a "missing backend" — open the devtools console and read the first error.
|
||||||
|
|
||||||
|
**Which homeserver / logging in:** `config.json` sets `defaultHomeserver: 0` → `matrix.lotusguild.org`, so you sign in with your normal `@you:matrix.lotusguild.org` account. That homeserver is **live production** — anything you send is real, so keep test traffic to a DM with yourself or a throwaway room. To develop fully isolated instead, point `config.json` at a throwaway `matrix.org` account (already in `homeserverList`) or a local Synapse.
|
||||||
|
|
||||||
|
- **SSO / OIDC works from localhost.** Login goes through Authelia via OIDC dynamic registration; the provider redirects back to `http://localhost:8080/…` and the client registers that redirect on the fly, so no server-side allow-listing is needed. After the callback you may see a `GET …/_matrix/media/v1/thumbnail/… 404` — that's just a missing avatar thumbnail, **not** a login failure.
|
||||||
|
|
||||||
### 🔱 Element Call fork ("Lotus Call") — LIVE
|
### 🔱 Element Call fork ("Lotus Call") — LIVE
|
||||||
|
|
||||||
Voice/video channels embed **Element Call**, which is now our **self-built fork**
|
Voice/video channels embed **Element Call**, which is now our **self-built fork**
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import { Page, PageContent, PageHeader } from '../../../components/page';
|
|||||||
import { SequenceCard } from '../../../components/sequence-card';
|
import { SequenceCard } from '../../../components/sequence-card';
|
||||||
import { SequenceCardStyle } from '../styles.css';
|
import { SequenceCardStyle } from '../styles.css';
|
||||||
import { SettingTile } from '../../../components/setting-tile';
|
import { SettingTile } from '../../../components/setting-tile';
|
||||||
import LotusLogo from '../../../../../public/res/Lotus.png';
|
import { trimTrailingSlash } from '../../../utils/common';
|
||||||
import pkg from '../../../../../package.json';
|
import pkg from '../../../../../package.json';
|
||||||
import { clearCacheAndReload } from '../../../../client/initMatrix';
|
import { clearCacheAndReload } from '../../../../client/initMatrix';
|
||||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||||
|
|
||||||
|
const LotusLogo = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/Lotus.png`;
|
||||||
|
|
||||||
type MSC1929Contact = {
|
type MSC1929Contact = {
|
||||||
matrix_id?: string;
|
matrix_id?: string;
|
||||||
email_address?: string;
|
email_address?: string;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
} from '../../hooks/useClientConfig';
|
} from '../../hooks/useClientConfig';
|
||||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
|
||||||
import { LOGIN_PATH, REGISTER_PATH, RESET_PASSWORD_PATH } from '../paths';
|
import { LOGIN_PATH, REGISTER_PATH, RESET_PASSWORD_PATH } from '../paths';
|
||||||
import LotusLogo from '../../../../public/res/Lotus.png';
|
import { trimTrailingSlash } from '../../utils/common';
|
||||||
import { ServerPicker } from './ServerPicker';
|
import { ServerPicker } from './ServerPicker';
|
||||||
import { AutoDiscoveryAction, autoDiscovery } from '../../cs-api';
|
import { AutoDiscoveryAction, autoDiscovery } from '../../cs-api';
|
||||||
import { SpecVersionsLoader } from '../../components/SpecVersionsLoader';
|
import { SpecVersionsLoader } from '../../components/SpecVersionsLoader';
|
||||||
@@ -31,6 +31,8 @@ import { AuthFlowsProvider } from '../../hooks/useAuthFlows';
|
|||||||
import { AuthServerProvider } from '../../hooks/useAuthServer';
|
import { AuthServerProvider } from '../../hooks/useAuthServer';
|
||||||
import { tryDecodeURIComponent } from '../../utils/dom';
|
import { tryDecodeURIComponent } from '../../utils/dom';
|
||||||
|
|
||||||
|
const LotusLogo = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/Lotus.png`;
|
||||||
|
|
||||||
const currentAuthPath = (pathname: string): string => {
|
const currentAuthPath = (pathname: string): string => {
|
||||||
if (matchPath(LOGIN_PATH, pathname)) {
|
if (matchPath(LOGIN_PATH, pathname)) {
|
||||||
return LOGIN_PATH;
|
return LOGIN_PATH;
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import type { OidcRegistrationClientMetadata } from 'matrix-js-sdk';
|
import type { OidcRegistrationClientMetadata } from 'matrix-js-sdk';
|
||||||
import LotusLogo from '../../../../../public/res/Lotus.png';
|
import { trimTrailingSlash } from '../../../utils/common';
|
||||||
import { OIDC_CALLBACK_PATH } from '../../paths';
|
import { OIDC_CALLBACK_PATH } from '../../paths';
|
||||||
import { getOriginBaseUrl, withOriginBaseUrl } from '../../pathUtils';
|
import { getOriginBaseUrl, withOriginBaseUrl } from '../../pathUtils';
|
||||||
|
|
||||||
|
const LotusLogo = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/Lotus.png`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Absolute URL the OIDC provider redirects back to after authorization.
|
* Absolute URL the OIDC provider redirects back to after authorization.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ import { manualDndAtom } from '../../state/manualDnd';
|
|||||||
import { isSnoozeActive, notificationSnoozeUntilAtom } from '../../state/notificationSnooze';
|
import { isSnoozeActive, notificationSnoozeUntilAtom } from '../../state/notificationSnooze';
|
||||||
import { isWithinTimeWindow } from '../../utils/timeWindow';
|
import { isWithinTimeWindow } from '../../utils/timeWindow';
|
||||||
import { roomToUnreadAtom } from '../../state/room/roomToUnread';
|
import { roomToUnreadAtom } from '../../state/room/roomToUnread';
|
||||||
import LogoSVG from '../../../../public/res/lotus.png';
|
import { trimTrailingSlash } from '../../utils/common';
|
||||||
import LogoUnreadSVG from '../../../../public/res/lotus-unread.png';
|
|
||||||
import LogoHighlightSVG from '../../../../public/res/lotus-highlight.png';
|
|
||||||
import NotificationSound from '../../../../public/sound/notification.ogg';
|
import NotificationSound from '../../../../public/sound/notification.ogg';
|
||||||
import InviteSound from '../../../../public/sound/invite.ogg';
|
import InviteSound from '../../../../public/sound/invite.ogg';
|
||||||
import { notificationPermission, setFavicon, showOsNotification } from '../../utils/dom';
|
import { notificationPermission, setFavicon, showOsNotification } from '../../utils/dom';
|
||||||
@@ -69,6 +67,10 @@ import {
|
|||||||
|
|
||||||
// Grace period after the initial sync settles before invite notifications arm, so
|
// Grace period after the initial sync settles before invite notifications arm, so
|
||||||
// the async invite-atom population lands first and isn't mistaken for new invites.
|
// the async invite-atom population lands first and isn't mistaken for new invites.
|
||||||
|
const LogoSVG = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/lotus.png`;
|
||||||
|
const LogoUnreadSVG = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/lotus-unread.png`;
|
||||||
|
const LogoHighlightSVG = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/lotus-highlight.png`;
|
||||||
|
|
||||||
const INVITE_NOTIFY_ARM_DELAY_MS = 3000;
|
const INVITE_NOTIFY_ARM_DELAY_MS = 3000;
|
||||||
|
|
||||||
function SystemEmojiFeature() {
|
function SystemEmojiFeature() {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Box, Button, Icon, Icons, Text, config, toRem } from 'folds';
|
import { Box, Button, Icon, Icons, Text, config, toRem } from 'folds';
|
||||||
import { Page, PageHero, PageHeroSection } from '../../components/page';
|
import { Page, PageHero, PageHeroSection } from '../../components/page';
|
||||||
import LotusLogo from '../../../../public/res/Lotus.png';
|
import { trimTrailingSlash } from '../../utils/common';
|
||||||
import pkg from '../../../../package.json';
|
import pkg from '../../../../package.json';
|
||||||
|
|
||||||
|
const LotusLogo = `${trimTrailingSlash(import.meta.env.BASE_URL)}/public/res/Lotus.png`;
|
||||||
|
|
||||||
export function WelcomePage() {
|
export function WelcomePage() {
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
|
|||||||
Reference in New Issue
Block a user