theme select
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
# Ditchcord
|
# Zep
|
||||||
|
|
||||||
Ditchcord is a self-hosted, privacy-oriented chat application built with **Svelte 5** and **SpacetimeDB**. Designed as a modern, lightweight alternative to commercial platforms, it prioritizes performance, low-latency communication, and high feature density without the bloat.
|
Zep is a self-hosted, privacy-oriented chat application built with **Svelte 5** and **SpacetimeDB**. Designed as a modern, lightweight alternative to commercial platforms, it prioritizes performance, low-latency communication, and high feature density without the bloat.
|
||||||
|
|
||||||
## 🚀 Features
|
## 🚀 Features
|
||||||
|
|
||||||
Ditchcord offers a rich, Discord-inspired user experience backed by a highly scalable, WebAssembly-powered database architecture.
|
Zep offers a rich, Discord-inspired user experience backed by a highly scalable, WebAssembly-powered database architecture.
|
||||||
|
|
||||||
* **Multi-Server & Channel Support:** Organize your communities with dedicated Text, Voice, and Threaded channels.
|
* **Multi-Server & Channel Support:** Organize your communities with dedicated Text, Voice, and Threaded channels.
|
||||||
* **Blazing Fast Pagination:** Uses a sophisticated hybrid "Recent Activity Cache" to load channels instantly, with on-demand expansion for deep history scrollback.
|
* **Blazing Fast Pagination:** Uses a sophisticated hybrid "Recent Activity Cache" to load channels instantly, with on-demand expansion for deep history scrollback.
|
||||||
@@ -15,7 +15,7 @@ Ditchcord offers a rich, Discord-inspired user experience backed by a highly sca
|
|||||||
|
|
||||||
## 🗺️ Roadmap
|
## 🗺️ Roadmap
|
||||||
|
|
||||||
We are actively developing Ditchcord. Here is what's coming next:
|
We are actively developing Zep. Here is what's coming next:
|
||||||
|
|
||||||
* [ ] **Direct Messaging:** Private, 1-on-1 conversations outside of server contexts.
|
* [ ] **Direct Messaging:** Private, 1-on-1 conversations outside of server contexts.
|
||||||
* [ ] **Mentions & Notifications:** Robust `@user` and `@role` tagging with RLS-protected notification delivery.
|
* [ ] **Mentions & Notifications:** Robust `@user` and `@role` tagging with RLS-protected notification delivery.
|
||||||
@@ -32,7 +32,7 @@ We are actively developing Ditchcord. Here is what's coming next:
|
|||||||
* **Desktop:** Tauri (Planned/Configured)
|
* **Desktop:** Tauri (Planned/Configured)
|
||||||
|
|
||||||
### Architecture Highlights
|
### Architecture Highlights
|
||||||
Ditchcord leverages **SpacetimeDB's client-side cache model** to eliminate traditional REST API bottlenecks.
|
Zep leverages **SpacetimeDB's client-side cache model** to eliminate traditional REST API bottlenecks.
|
||||||
* **Zero-Latency Switching:** The client subscribes to a lightweight `recent_message` table for all joined servers on startup. This populates the UI instantly when switching channels.
|
* **Zero-Latency Switching:** The client subscribes to a lightweight `recent_message` table for all joined servers on startup. This populates the UI instantly when switching channels.
|
||||||
* **Surgical Subscriptions:** The heavy `message` history table is only subscribed to on-demand when a user explicitly requests older messages, saving bandwidth and memory.
|
* **Surgical Subscriptions:** The heavy `message` history table is only subscribed to on-demand when a user explicitly requests older messages, saving bandwidth and memory.
|
||||||
* **WASM Reducers:** All database mutations (sending messages, updating profiles) are handled by deterministic TypeScript reducers compiled to WebAssembly and executed transactionally on the server.
|
* **WASM Reducers:** All database mutations (sending messages, updating profiles) are handled by deterministic TypeScript reducers compiled to WebAssembly and executed transactionally on the server.
|
||||||
@@ -56,7 +56,7 @@ Ditchcord leverages **SpacetimeDB's client-side cache model** to eliminate tradi
|
|||||||
```
|
```
|
||||||
3. Publish the module to your SpacetimeDB instance (e.g., `maincloud` or a local instance). *Note: The first publish creates the database.*
|
3. Publish the module to your SpacetimeDB instance (e.g., `maincloud` or a local instance). *Note: The first publish creates the database.*
|
||||||
```bash
|
```bash
|
||||||
spacetime publish --server maincloud ditchcord
|
spacetime publish --server maincloud zep
|
||||||
```
|
```
|
||||||
4. Generate the TypeScript bindings for the frontend:
|
4. Generate the TypeScript bindings for the frontend:
|
||||||
```bash
|
```bash
|
||||||
@@ -76,7 +76,7 @@ Ditchcord leverages **SpacetimeDB's client-side cache model** to eliminate tradi
|
|||||||
3. Configure your environment variables (create a `.env.local` file if necessary) to point to your published SpacetimeDB instance:
|
3. Configure your environment variables (create a `.env.local` file if necessary) to point to your published SpacetimeDB instance:
|
||||||
```env
|
```env
|
||||||
VITE_SPACETIMEDB_HOST=wss://maincloud.spacetimedb.com
|
VITE_SPACETIMEDB_HOST=wss://maincloud.spacetimedb.com
|
||||||
VITE_SPACETIMEDB_DB_NAME=ditchcord
|
VITE_SPACETIMEDB_DB_NAME=zep
|
||||||
```
|
```
|
||||||
4. Run the development server:
|
4. Run the development server:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Ditchcord</title>
|
<title>Zep</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "ditchcord",
|
"name": "zep",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
+15
-1
@@ -1 +1,15 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="zepGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||||
|
<stop offset="0%" stop-color="#c77dff" />
|
||||||
|
<stop offset="100%" stop-color="#7b2cbf" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||||
|
<feGaussianBlur stdDeviation="8" result="blur" />
|
||||||
|
<feComposite in="SourceGraphic" in2="blur" operator="over" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<rect width="256" height="256" rx="64" fill="#0a0714" />
|
||||||
|
<path d="M60 70 L196 70 L110 186 L196 186" fill="none" stroke="url(#zepGrad)" stroke-width="32" stroke-linecap="round" stroke-linejoin="round" filter="url(#glow)" />
|
||||||
|
<path d="M60 70 L196 70 L110 186 L196 186" fill="none" stroke="#ffffff" stroke-width="12" stroke-linecap="round" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 853 B |
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "ditchcord",
|
"name": "zep",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1225,7 +1225,7 @@ export const init = spacetimedb.init((ctx) => {
|
|||||||
if (!hasServers) {
|
if (!hasServers) {
|
||||||
const s = ctx.db.server.insert({
|
const s = ctx.db.server.insert({
|
||||||
id: 0n,
|
id: 0n,
|
||||||
name: "Ditchcord",
|
name: "Zep",
|
||||||
owner: undefined,
|
owner: undefined,
|
||||||
});
|
});
|
||||||
ctx.db.channel.insert({
|
ctx.db.channel.insert({
|
||||||
|
|||||||
Generated
+12
-12
@@ -713,18 +713,6 @@ dependencies = [
|
|||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ditchcord"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tauri",
|
|
||||||
"tauri-build",
|
|
||||||
"tauri-plugin-log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dlopen2"
|
name = "dlopen2"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -5193,6 +5181,18 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zep"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"tauri-build",
|
||||||
|
"tauri-plugin-log",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.48"
|
version = "0.8.48"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ditchcord"
|
name = "zep"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "ditchcord - self-hosted communication"
|
description = "zep - self-hosted communication"
|
||||||
authors = ["Adam Lamers"]
|
authors = ["Adam Lamers"]
|
||||||
license = ""
|
license = ""
|
||||||
repository = ""
|
repository = ""
|
||||||
@@ -11,7 +11,7 @@ rust-version = "1.77.2"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "ditchcord_lib"
|
name = "zep_lib"
|
||||||
crate-type = ["staticlib", "cdylib", "rlib"]
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
ditchcord_lib::run();
|
zep_lib::run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"productName": "ditchcord",
|
"productName": "zep",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"identifier": "com.ditchcord.chat",
|
"identifier": "com.zep.chat",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../dist",
|
"frontendDist": "../dist",
|
||||||
"devUrl": "http://localhost:5173",
|
"devUrl": "http://localhost:5173",
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"title": "Ditchcord",
|
"title": "Zep",
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 600,
|
"height": 600,
|
||||||
"resizable": true,
|
"resizable": true,
|
||||||
|
|||||||
+158
-37
@@ -1,4 +1,114 @@
|
|||||||
:root {
|
:root {
|
||||||
|
--server-sidebar-width: 72px;
|
||||||
|
--channel-sidebar-width: 240px;
|
||||||
|
--font-primary:
|
||||||
|
"gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
--font-display:
|
||||||
|
"gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
--font-code:
|
||||||
|
source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||||
|
--status-positive: var(--status-positive);
|
||||||
|
--status-danger: var(--status-danger);
|
||||||
|
--status-warning: var(--status-warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Premium Midnight Purple (Amethyst) */
|
||||||
|
.theme-amethyst, :root {
|
||||||
|
--background-primary: #161126;
|
||||||
|
--background-secondary: #0f0a1a;
|
||||||
|
--background-tertiary: #0a0714;
|
||||||
|
--background-accent: #241b3d;
|
||||||
|
--header-primary: #f3eeff;
|
||||||
|
--text-normal: #e0d1f0;
|
||||||
|
--text-muted: #9a8cbb;
|
||||||
|
--interactive-normal: #b3a5d1;
|
||||||
|
--interactive-hover: #ffffff;
|
||||||
|
--brand: #9d4edd;
|
||||||
|
--brand-hover: #7b2cbf;
|
||||||
|
--background-modifier-hover: rgba(157, 78, 221, 0.15);
|
||||||
|
--background-modifier-active: rgba(157, 78, 221, 0.3);
|
||||||
|
--background-modifier-selected: rgba(157, 78, 221, 0.3);
|
||||||
|
--background-floating: #0a0714;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Slate Cyan (Cyber) */
|
||||||
|
.theme-cyan {
|
||||||
|
--background-primary: #121826;
|
||||||
|
--background-secondary: #0c111a;
|
||||||
|
--background-tertiary: #080c13;
|
||||||
|
--background-accent: #1f2937;
|
||||||
|
--header-primary: #f8fafc;
|
||||||
|
--text-normal: #cbd5e1;
|
||||||
|
--text-muted: #64748b;
|
||||||
|
--interactive-normal: #94a3b8;
|
||||||
|
--interactive-hover: #f1f5f9;
|
||||||
|
--brand: #00d2ff;
|
||||||
|
--brand-hover: #00a8cc;
|
||||||
|
--background-modifier-hover: rgba(0, 210, 255, 0.15);
|
||||||
|
--background-modifier-active: rgba(0, 210, 255, 0.3);
|
||||||
|
--background-modifier-selected: rgba(0, 210, 255, 0.3);
|
||||||
|
--background-floating: #080c13;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deep Sea Green (Emerald) */
|
||||||
|
.theme-emerald {
|
||||||
|
--background-primary: #061a14;
|
||||||
|
--background-secondary: #04120e;
|
||||||
|
--background-tertiary: #020a08;
|
||||||
|
--background-accent: #0d2e24;
|
||||||
|
--header-primary: #e6fffa;
|
||||||
|
--text-normal: #b2f5ea;
|
||||||
|
--text-muted: #4e9a84;
|
||||||
|
--interactive-normal: #81e6d9;
|
||||||
|
--interactive-hover: #ffffff;
|
||||||
|
--brand: #10b981;
|
||||||
|
--brand-hover: #059669;
|
||||||
|
--background-modifier-hover: rgba(16, 185, 129, 0.15);
|
||||||
|
--background-modifier-active: rgba(16, 185, 129, 0.3);
|
||||||
|
--background-modifier-selected: rgba(16, 185, 129, 0.3);
|
||||||
|
--background-floating: #020a08;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Crimson Rose (Rose) */
|
||||||
|
.theme-rose {
|
||||||
|
--background-primary: #1a0a0f;
|
||||||
|
--background-secondary: #12060a;
|
||||||
|
--background-tertiary: #0a0305;
|
||||||
|
--background-accent: #2e0d16;
|
||||||
|
--header-primary: #fff5f7;
|
||||||
|
--text-normal: #fed7e2;
|
||||||
|
--text-muted: #9b4e64;
|
||||||
|
--interactive-normal: #fbb6ce;
|
||||||
|
--interactive-hover: #ffffff;
|
||||||
|
--brand: #f43f5e;
|
||||||
|
--brand-hover: #e11d48;
|
||||||
|
--background-modifier-hover: rgba(244, 63, 94, 0.15);
|
||||||
|
--background-modifier-active: rgba(244, 63, 94, 0.3);
|
||||||
|
--background-modifier-selected: rgba(244, 63, 94, 0.3);
|
||||||
|
--background-floating: #0a0305;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Amber Gold (Amber) */
|
||||||
|
.theme-amber {
|
||||||
|
--background-primary: #1a1405;
|
||||||
|
--background-secondary: #120e03;
|
||||||
|
--background-tertiary: #0a0802;
|
||||||
|
--background-accent: #2e240d;
|
||||||
|
--header-primary: #fffaf0;
|
||||||
|
--text-normal: #fef3c7;
|
||||||
|
--text-muted: #9a7b4e;
|
||||||
|
--interactive-normal: #fcd34d;
|
||||||
|
--interactive-hover: #ffffff;
|
||||||
|
--brand: #f59e0b;
|
||||||
|
--brand-hover: #d97706;
|
||||||
|
--background-modifier-hover: rgba(245, 158, 11, 0.15);
|
||||||
|
--background-modifier-active: rgba(245, 158, 11, 0.3);
|
||||||
|
--background-modifier-selected: rgba(245, 158, 11, 0.3);
|
||||||
|
--background-floating: #0a0802;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic Dark (Standard) */
|
||||||
|
.theme-dark {
|
||||||
--background-primary: #313338;
|
--background-primary: #313338;
|
||||||
--background-secondary: #2b2d31;
|
--background-secondary: #2b2d31;
|
||||||
--background-tertiary: #1e1f22;
|
--background-tertiary: #1e1f22;
|
||||||
@@ -10,23 +120,32 @@
|
|||||||
--interactive-hover: #dbdee1;
|
--interactive-hover: #dbdee1;
|
||||||
--brand: #5865f2;
|
--brand: #5865f2;
|
||||||
--brand-hover: #4752c4;
|
--brand-hover: #4752c4;
|
||||||
--server-sidebar-width: 72px;
|
|
||||||
--channel-sidebar-width: 240px;
|
|
||||||
--background-modifier-hover: rgba(78, 80, 88, 0.3);
|
--background-modifier-hover: rgba(78, 80, 88, 0.3);
|
||||||
--background-modifier-active: rgba(78, 80, 88, 0.6);
|
--background-modifier-active: rgba(78, 80, 88, 0.6);
|
||||||
--background-modifier-selected: rgba(78, 80, 88, 0.6);
|
--background-modifier-selected: rgba(78, 80, 88, 0.6);
|
||||||
--background-floating: #1e1f22;
|
--background-floating: #1e1f22;
|
||||||
--status-positive: #23a559;
|
|
||||||
--status-danger: #f23f43;
|
|
||||||
--status-warning: #f0b232;
|
|
||||||
--font-primary:
|
|
||||||
"gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
--font-display:
|
|
||||||
"gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
||||||
--font-code:
|
|
||||||
source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Generic Light (Standard) */
|
||||||
|
.theme-light {
|
||||||
|
--background-primary: #ffffff;
|
||||||
|
--background-secondary: #f2f3f5;
|
||||||
|
--background-tertiary: #e3e5e8;
|
||||||
|
--background-accent: #ebedef;
|
||||||
|
--header-primary: #060607;
|
||||||
|
--text-normal: #313338;
|
||||||
|
--text-muted: #5c6067;
|
||||||
|
--interactive-normal: #4e5058;
|
||||||
|
--interactive-hover: #060607;
|
||||||
|
--brand: #5865f2;
|
||||||
|
--brand-hover: #4752c4;
|
||||||
|
--background-modifier-hover: rgba(78, 80, 88, 0.1);
|
||||||
|
--background-modifier-active: rgba(78, 80, 88, 0.2);
|
||||||
|
--background-modifier-selected: rgba(78, 80, 88, 0.2);
|
||||||
|
--background-floating: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: var(--font-primary);
|
font-family: var(--font-primary);
|
||||||
@@ -173,7 +292,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.server-dropdown-item.danger:hover {
|
.server-dropdown-item.danger:hover {
|
||||||
background-color: #f23f43;
|
background-color: var(--status-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.server-dropdown-item.muted {
|
.server-dropdown-item.muted {
|
||||||
@@ -249,13 +368,14 @@ body {
|
|||||||
|
|
||||||
/* User Info Bar */
|
/* User Info Bar */
|
||||||
.user-info-bar {
|
.user-info-bar {
|
||||||
background-color: #232428;
|
background-color: var(--background-tertiary);
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: 52px;
|
height: 52px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info-main {
|
.user-info-main {
|
||||||
@@ -290,7 +410,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.avatar.talking {
|
.avatar.talking {
|
||||||
border: 2px solid #23a559;
|
border: 2px solid var(--status-positive);
|
||||||
box-shadow: 0 0 0 2px rgba(35, 165, 89, 0.15);
|
box-shadow: 0 0 0 2px rgba(35, 165, 89, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +485,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.avatar.talking {
|
.avatar.talking {
|
||||||
border: 2px solid #23a559;
|
border: 2px solid var(--status-positive);
|
||||||
box-shadow: 0 0 0 2px rgba(35, 165, 89, 0.15);
|
box-shadow: 0 0 0 2px rgba(35, 165, 89, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +568,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-btn.danger.active {
|
.icon-btn.danger.active {
|
||||||
color: #f23f43;
|
color: var(--status-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Main Content Area */
|
/* Main Content Area */
|
||||||
@@ -903,7 +1023,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.video-tile.talking {
|
.video-tile.talking {
|
||||||
border-color: #23a559;
|
border-color: var(--status-positive);
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-tile video {
|
.video-tile video {
|
||||||
@@ -1107,7 +1227,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sharing-badge {
|
.sharing-badge {
|
||||||
background-color: #f23f43;
|
background-color: var(--status-danger);
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 0.6rem;
|
font-size: 0.6rem;
|
||||||
padding: 1px 4px;
|
padding: 1px 4px;
|
||||||
@@ -1152,18 +1272,18 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-dot.green {
|
.status-dot.green {
|
||||||
background-color: #23a559;
|
background-color: var(--status-positive);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot.yellow {
|
.status-dot.yellow {
|
||||||
background-color: #f0b232;
|
background-color: var(--status-warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-dot.red {
|
.status-dot.red {
|
||||||
background-color: #f23f43;
|
background-color: var(--status-danger);
|
||||||
}
|
}
|
||||||
.status-dot.grey {
|
.status-dot.grey {
|
||||||
background-color: #80848e;
|
background-color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connection Popover */
|
/* Connection Popover */
|
||||||
@@ -1212,13 +1332,13 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.popover-status.green {
|
.popover-status.green {
|
||||||
color: #23a559;
|
color: var(--status-positive);
|
||||||
}
|
}
|
||||||
.popover-status.yellow {
|
.popover-status.yellow {
|
||||||
color: #f0b232;
|
color: var(--status-warning);
|
||||||
}
|
}
|
||||||
.popover-status.red {
|
.popover-status.red {
|
||||||
color: #f23f43;
|
color: var(--status-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-info {
|
.popover-info {
|
||||||
@@ -1379,7 +1499,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
background-color: #f23f43;
|
background-color: var(--status-danger);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
@@ -1393,7 +1513,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger:hover {
|
.btn-danger:hover {
|
||||||
background-color: #d83c3e;
|
background-color: var(--status-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-danger.small {
|
.btn-danger.small {
|
||||||
@@ -1463,7 +1583,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-error {
|
.login-error {
|
||||||
color: #fa777a;
|
color: var(--status-danger);
|
||||||
background-color: rgba(250, 119, 122, 0.1);
|
background-color: rgba(250, 119, 122, 0.1);
|
||||||
border: 1px solid rgba(250, 119, 122, 0.2);
|
border: 1px solid rgba(250, 119, 122, 0.2);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@@ -1475,12 +1595,12 @@ body {
|
|||||||
|
|
||||||
/* Voice Connected Bar */
|
/* Voice Connected Bar */
|
||||||
.voice-status-bar {
|
.voice-status-bar {
|
||||||
background-color: #232428;
|
background-color: var(--background-tertiary);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.voice-info {
|
.voice-info {
|
||||||
@@ -1489,7 +1609,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.voice-connected-text {
|
.voice-connected-text {
|
||||||
color: #23a559;
|
color: var(--status-positive);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@@ -1500,7 +1620,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.screen-share-btn {
|
.screen-share-btn {
|
||||||
background-color: #3f4147;
|
background-color: var(--background-accent);
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
@@ -1512,15 +1632,15 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.screen-share-btn:hover {
|
.screen-share-btn:hover {
|
||||||
background-color: #4f5157;
|
background-color: var(--background-modifier-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-share-btn.active {
|
.screen-share-btn.active {
|
||||||
background-color: #f23f43;
|
background-color: var(--status-danger);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-share-btn.active:hover {
|
.screen-share-btn.active:hover {
|
||||||
background-color: #d83c3e;
|
opacity: 0.9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-share-controls {
|
.screen-share-controls {
|
||||||
@@ -1564,11 +1684,12 @@ body {
|
|||||||
.context-menu {
|
.context-menu {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 3000;
|
z-index: 3000;
|
||||||
background: #18191c;
|
background: var(--background-floating);
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
min-width: 180px;
|
min-width: 180px;
|
||||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.24);
|
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.24);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.context-menu-header {
|
.context-menu-header {
|
||||||
@@ -1599,7 +1720,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.context-menu-item:hover {
|
.context-menu-item:hover {
|
||||||
background: var(--primary);
|
background: var(--brand);
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-3
@@ -2,15 +2,22 @@
|
|||||||
import { AuthGate } from "./auth";
|
import { AuthGate } from "./auth";
|
||||||
import { ChatContainer } from "./chat";
|
import { ChatContainer } from "./chat";
|
||||||
import { connectionState } from "./connection.svelte";
|
import { connectionState } from "./connection.svelte";
|
||||||
|
import { themeService } from "./chat/services/theme.svelte";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
|
||||||
let showServerSettings = $state(false);
|
let showServerSettings = $state(false);
|
||||||
|
|
||||||
|
// Apply theme class to body globally
|
||||||
|
$effect(() => {
|
||||||
|
const theme = themeService.theme;
|
||||||
|
document.body.className = `theme-${theme}`;
|
||||||
|
});
|
||||||
|
|
||||||
function handleReconnect() {
|
function handleReconnect() {
|
||||||
console.log("App: Reconnection requested. Reloading page...");
|
console.log("App: Reconnection requested. Reloading page...");
|
||||||
// If we are showing settings, we should keep showing them after reload
|
// If we are showing settings, we should keep showing them after reload
|
||||||
if (showServerSettings) {
|
if (showServerSettings) {
|
||||||
localStorage.setItem("ditchcord_changing_server", "true");
|
localStorage.setItem("zep_changing_server", "true");
|
||||||
}
|
}
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
@@ -19,9 +26,9 @@
|
|||||||
console.log("App: Setting showServerSettings to", val);
|
console.log("App: Setting showServerSettings to", val);
|
||||||
showServerSettings = val;
|
showServerSettings = val;
|
||||||
if (val) {
|
if (val) {
|
||||||
localStorage.setItem("ditchcord_changing_server", "true");
|
localStorage.setItem("zep_changing_server", "true");
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem("ditchcord_changing_server");
|
localStorage.removeItem("zep_changing_server");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
isMaincloud = stdbHost === MAINCLOUD_URI || stdbHost === "";
|
isMaincloud = stdbHost === MAINCLOUD_URI || stdbHost === "";
|
||||||
if (isMaincloud) stdbHost = MAINCLOUD_URI;
|
if (isMaincloud) stdbHost = MAINCLOUD_URI;
|
||||||
|
|
||||||
const isChanging = localStorage.getItem("ditchcord_changing_server") === "true";
|
const isChanging = localStorage.getItem("zep_changing_server") === "true";
|
||||||
if (isChanging) {
|
if (isChanging) {
|
||||||
isSettingsExpanded = true;
|
isSettingsExpanded = true;
|
||||||
userWantsToConnect = false;
|
userWantsToConnect = false;
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
<path d="M30 20 Q70 20 70 50 Q70 80 30 80" fill="none" stroke="currentColor" stroke-width="8" stroke-linecap="round" class="logo-d" />
|
<path d="M30 20 Q70 20 70 50 Q70 80 30 80" fill="none" stroke="currentColor" stroke-width="8" stroke-linecap="round" class="logo-d" />
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<h1>Ditchcord</h1>
|
<h1>Zep</h1>
|
||||||
<p class="tagline">Decentralized. Private. Fast.</p>
|
<p class="tagline">Decentralized. Private. Fast.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@
|
|||||||
id="stdb-db"
|
id="stdb-db"
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={stdbDbName}
|
bind:value={stdbDbName}
|
||||||
placeholder="ditchcord"
|
placeholder="zep"
|
||||||
style="background-color: var(--background-tertiary); color: var(--text-normal); border: 1px solid var(--background-modifier-accent); border-radius: 4px; padding: 10px;"
|
style="background-color: var(--background-tertiary); color: var(--text-normal); border: 1px solid var(--background-modifier-accent); border-radius: 4px; padding: 10px;"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -147,7 +147,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-dot.green { background-color: var(--status-positive); }
|
.status-dot.green { background-color: var(--status-positive); }
|
||||||
.status-dot.grey { background-color: #80848e; }
|
.status-dot.grey { background-color: var(--text-muted); }
|
||||||
|
|
||||||
.profile-info {
|
.profile-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
<button
|
<button
|
||||||
class="server-icon"
|
class="server-icon"
|
||||||
onclick={() => (chat.showDiscoveryModal = true)}
|
onclick={() => (chat.showDiscoveryModal = true)}
|
||||||
style="color: #23a559;"
|
style="color: var(--status-positive);"
|
||||||
title="Discover Servers"
|
title="Discover Servers"
|
||||||
>
|
>
|
||||||
<i class="fas fa-search"></i>
|
<i class="fas fa-search"></i>
|
||||||
|
|||||||
@@ -5,6 +5,16 @@
|
|||||||
|
|
||||||
const chat = getContext<ChatService>("chat");
|
const chat = getContext<ChatService>("chat");
|
||||||
|
|
||||||
|
const themes = [
|
||||||
|
{ id: "dark", name: "Dark", color: "#5865f2", bg: "#313338" },
|
||||||
|
{ id: "light", name: "Light", color: "#5865f2", bg: "#ffffff" },
|
||||||
|
{ id: "amethyst", name: "Amethyst", color: "#9d4edd", bg: "#0f0a1a" },
|
||||||
|
{ id: "cyan", name: "Cyber Cyan", color: "#00d2ff", bg: "#0c111a" },
|
||||||
|
{ id: "emerald", name: "Emerald Sea", color: "#10b981", bg: "#04120e" },
|
||||||
|
{ id: "rose", name: "Crimson Rose", color: "#f43f5e", bg: "#12060a" },
|
||||||
|
{ id: "amber", name: "Amber Gold", color: "#f59e0b", bg: "#120e03" },
|
||||||
|
];
|
||||||
|
|
||||||
let newEmojiName = $state("");
|
let newEmojiName = $state("");
|
||||||
let newEmojiFile = $state<File | null>(null);
|
let newEmojiFile = $state<File | null>(null);
|
||||||
let isEmojiUploading = $state(false);
|
let isEmojiUploading = $state(false);
|
||||||
@@ -42,6 +52,39 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="section">
|
<div class="section">
|
||||||
|
<div class="section-header-description">
|
||||||
|
<h3>Appearance</h3>
|
||||||
|
<p>Choose a color scheme that fits your style.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="theme-selection-container">
|
||||||
|
{#each themes as theme}
|
||||||
|
<button
|
||||||
|
class="theme-card"
|
||||||
|
class:active={chat.ui.theme === theme.id}
|
||||||
|
onclick={() => chat.ui.setTheme(theme.id)}
|
||||||
|
style="--theme-accent: {theme.color}; --theme-bg: {theme.bg};"
|
||||||
|
>
|
||||||
|
<div class="theme-preview">
|
||||||
|
<div class="theme-preview-sidebar"></div>
|
||||||
|
<div class="theme-preview-content">
|
||||||
|
<div class="theme-preview-header"></div>
|
||||||
|
<div class="theme-preview-msg"></div>
|
||||||
|
<div class="theme-preview-msg short"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="theme-name">{theme.name}</span>
|
||||||
|
{#if chat.ui.theme === theme.id}
|
||||||
|
<div class="theme-active-check">
|
||||||
|
<i class="fas fa-check-circle"></i>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="section" style="margin-top: 32px;">
|
||||||
<div class="section-header-description">
|
<div class="section-header-description">
|
||||||
<h3>Custom Emojis</h3>
|
<h3>Custom Emojis</h3>
|
||||||
<p>Personalize your experience by uploading unique emojis. They'll be automatically optimized for the best performance.</p>
|
<p>Personalize your experience by uploading unique emojis. They'll be automatically optimized for the best performance.</p>
|
||||||
@@ -120,6 +163,95 @@
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.theme-selection-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
||||||
|
gap: 16px;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-card {
|
||||||
|
background-color: var(--background-secondary);
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
transition: all 0.2s;
|
||||||
|
position: relative;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-card:hover {
|
||||||
|
background-color: var(--background-modifier-hover);
|
||||||
|
border-color: var(--background-modifier-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-card.active {
|
||||||
|
border-color: var(--theme-accent);
|
||||||
|
background-color: var(--background-modifier-selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview {
|
||||||
|
height: 60px;
|
||||||
|
background-color: var(--theme-bg);
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview-sidebar {
|
||||||
|
width: 20px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
border-right: 1px solid rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview-content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview-header {
|
||||||
|
height: 6px;
|
||||||
|
width: 60%;
|
||||||
|
background-color: var(--theme-accent);
|
||||||
|
border-radius: 2px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview-msg {
|
||||||
|
height: 4px;
|
||||||
|
width: 90%;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview-msg.short {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-name {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-active-check {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
color: var(--theme-accent);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.emoji-management-container {
|
.emoji-management-container {
|
||||||
background-color: var(--background-secondary);
|
background-color: var(--background-secondary);
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as Types from "../../module_bindings/types";
|
|||||||
import { getUsername, formatTime } from "../utils";
|
import { getUsername, formatTime } from "../utils";
|
||||||
import { DatabaseService } from "./database.svelte";
|
import { DatabaseService } from "./database.svelte";
|
||||||
import { NavigationService } from "./navigation.svelte";
|
import { NavigationService } from "./navigation.svelte";
|
||||||
import { UIService } from "./ui.svelte";
|
import { ThemeService, themeService } from "./theme.svelte";
|
||||||
import { AuthContextService } from "./auth-context.svelte";
|
import { AuthContextService } from "./auth-context.svelte";
|
||||||
import { MessagingService } from "./messaging.svelte";
|
import { MessagingService } from "./messaging.svelte";
|
||||||
import { VoiceService } from "./voice.svelte";
|
import { VoiceService } from "./voice.svelte";
|
||||||
@@ -15,7 +15,7 @@ import { ServerManagementService } from "./server-management.svelte";
|
|||||||
export class ChatService {
|
export class ChatService {
|
||||||
#db: DatabaseService;
|
#db: DatabaseService;
|
||||||
#nav: NavigationService;
|
#nav: NavigationService;
|
||||||
#ui: UIService;
|
#ui: ThemeService = themeService;
|
||||||
#auth: AuthContextService;
|
#auth: AuthContextService;
|
||||||
#msg: MessagingService;
|
#msg: MessagingService;
|
||||||
#voice: VoiceService;
|
#voice: VoiceService;
|
||||||
@@ -30,7 +30,7 @@ export class ChatService {
|
|||||||
this.identity = initialIdentity;
|
this.identity = initialIdentity;
|
||||||
|
|
||||||
this.#db = new DatabaseService();
|
this.#db = new DatabaseService();
|
||||||
this.#ui = new UIService();
|
// this.#ui = new ThemeService(); // Removed to use shared themeService
|
||||||
this.#nav = new NavigationService(this.#db, () => this.identity);
|
this.#nav = new NavigationService(this.#db, () => this.identity);
|
||||||
this.#auth = new AuthContextService(this.#db, () => this.identity);
|
this.#auth = new AuthContextService(this.#db, () => this.identity);
|
||||||
this.#msg = new MessagingService(this.#db, this.#nav, () => this.identity);
|
this.#msg = new MessagingService(this.#db, this.#nav, () => this.identity);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ export class MessagingService {
|
|||||||
} else {
|
} else {
|
||||||
queries.push("SELECT * FROM custom_emoji");
|
queries.push("SELECT * FROM custom_emoji");
|
||||||
queries.push("SELECT * FROM system_configuration");
|
queries.push("SELECT * FROM system_configuration");
|
||||||
queries.push("SELECT * FROM server WHERE name = 'Ditchcord'");
|
queries.push("SELECT * FROM server WHERE name = 'Zep'");
|
||||||
}
|
}
|
||||||
|
|
||||||
let userQuery = "SELECT * FROM user WHERE online = true";
|
let userQuery = "SELECT * FROM user WHERE online = true";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { SvelteMap } from "svelte/reactivity";
|
import { SvelteMap } from "svelte/reactivity";
|
||||||
|
|
||||||
export class UIService {
|
export class ThemeService {
|
||||||
showCreateServerModal = $state(false);
|
showCreateServerModal = $state(false);
|
||||||
newServerName = $state("");
|
newServerName = $state("");
|
||||||
showCreateChannelModal = $state(false);
|
showCreateChannelModal = $state(false);
|
||||||
@@ -16,6 +16,16 @@ export class UIService {
|
|||||||
viewingProfileUser = $state<any | null>(null);
|
viewingProfileUser = $state<any | null>(null);
|
||||||
userContextMenu = $state<{ x: number, y: number, user: any } | null>(null);
|
userContextMenu = $state<{ x: number, y: number, user: any } | null>(null);
|
||||||
|
|
||||||
|
// Theme management
|
||||||
|
theme = $state(localStorage.getItem("zep_theme") || "dark");
|
||||||
|
|
||||||
|
setTheme(newTheme: string) {
|
||||||
|
this.theme = newTheme;
|
||||||
|
localStorage.setItem("zep_theme", newTheme);
|
||||||
|
}
|
||||||
|
|
||||||
// Track collapsed state of embeds by key: `${messageId}-${index}`
|
// Track collapsed state of embeds by key: `${messageId}-${index}`
|
||||||
embedCollapsedStates = new SvelteMap<string, boolean>();
|
embedCollapsedStates = new SvelteMap<string, boolean>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const themeService = new ThemeService();
|
||||||
+1
-1
@@ -41,7 +41,7 @@ export const getStdbHost = () =>
|
|||||||
getEnv("VITE_SPACETIMEDB_HOST", "wss://maincloud.spacetimedb.com");
|
getEnv("VITE_SPACETIMEDB_HOST", "wss://maincloud.spacetimedb.com");
|
||||||
export const getStdbDbName = () =>
|
export const getStdbDbName = () =>
|
||||||
localStorage.getItem(DB_NAME_KEY) ||
|
localStorage.getItem(DB_NAME_KEY) ||
|
||||||
getEnv("VITE_SPACETIMEDB_DB_NAME", "ditchcord");
|
getEnv("VITE_SPACETIMEDB_DB_NAME", "zep");
|
||||||
|
|
||||||
let _connection: DbConnection | null = null;
|
let _connection: DbConnection | null = null;
|
||||||
export const getConnection = () => _connection;
|
export const getConnection = () => _connection;
|
||||||
|
|||||||
+6
-6
@@ -9,17 +9,17 @@
|
|||||||
|
|
||||||
/* ----- Color Variables ----- */
|
/* ----- Color Variables ----- */
|
||||||
:root {
|
:root {
|
||||||
--theme-color: #3dc373;
|
--theme-color: #9d4edd;
|
||||||
--theme-color-contrast: #08180e;
|
--theme-color-contrast: #ffffff;
|
||||||
--textbox-color: #edfef4;
|
--textbox-color: #241b3d;
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
--theme-color: #4cf490;
|
--theme-color: #9d4edd;
|
||||||
--theme-color-contrast: #132219;
|
--theme-color-contrast: #ffffff;
|
||||||
--textbox-color: #0f311d;
|
--textbox-color: #0a0714;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ import "@fortawesome/fontawesome-free/css/all.min.css";
|
|||||||
import "./index.css";
|
import "./index.css";
|
||||||
import App from "./App.svelte";
|
import App from "./App.svelte";
|
||||||
|
|
||||||
console.log("Ditchcord: Starting app...");
|
console.log("Zep: Starting app...");
|
||||||
|
|
||||||
const app = mount(App, {
|
const app = mount(App, {
|
||||||
target: document.getElementById("root")!,
|
target: document.getElementById("root")!,
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "node_modules/wrangler/config-schema.json",
|
"$schema": "node_modules/wrangler/config-schema.json",
|
||||||
"name": "ditchcord",
|
"name": "zep",
|
||||||
"compatibility_date": "2026-04-04",
|
"compatibility_date": "2026-04-04",
|
||||||
"observability": {
|
"observability": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user