diff --git a/.env.example b/.env.example index e0e6cdb..12358c6 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,7 @@ PROJECT_NAME=jama # Image version to run (set by build.sh, or use 'latest') -JAMA_VERSION=0.9.21 +JAMA_VERSION=0.9.22 # App port — the host port Docker maps to the container PORT=3000 diff --git a/backend/package.json b/backend/package.json index 6eb9e95..8b32f9c 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "jama-backend", - "version": "0.9.21", + "version": "0.9.22", "description": "TeamChat backend server", "main": "src/index.js", "scripts": { diff --git a/backend/src/data/help.md b/backend/src/data/help.md index 4811d6f..70828ce 100644 --- a/backend/src/data/help.md +++ b/backend/src/data/help.md @@ -2,26 +2,32 @@ Welcome to **JAMA** — your private, self-hosted team messaging app. +**JAMA** - **J**ust **A**nother **M**essaging **A**pp + --- ## What is JAMA? -JAMA is a privately hosted chat system. It does not reply on any internet services. It can be host on a network that does not have internet. There is not personal information, other than your first and last name and your email address (both can be ficticious). The first and last name is used for your team to identify you and your email is to ensure a unique login name. You email is not shared with other users. There is no phone or email validate to use this site. If your forgot your password, there is a convenient get help option on the login page. +JAMA is a private chat system that doesn’t need the internet to work—you can host it on a completely offline network. Even if you do run JAMA while you're online, it stays locked inside its own "container," so it never reaches out to other internet services. -Even if this application is online, it still does not use any internet services, everything is self-contained within the JAMA container. +We keep things private, too: the only info we ask for is a name and an email, and technically speaking they don't even have to be real. Your name just helps your team know who you are, and your email is only used as your login (it's never shares with anyone else). --- +There’s no annoying phone or email verification to deal with, so you can jump right in. If you ever get locked out, just hit the "Get Help" link on the login page. JAMA is easy and intuitive, you're going to love it. + +---- +---- ## Security ### 🛡️ Your Privacy Assured -The only people that can read your direct messages (**person 2 person** or **group**) are the members of the message group. No one else, including JAMA admins, know which private message groups exist or which you are part of, unless they are member. +**Encryption**, the JAMA database is fully encrypted. Your posts are protected from prying eyes, including the JAMA administrators. + +The only people that can read your direct messages (**person 2 person** or **group**) are the members of your message group. No one else knows, including JAMA admins, which direct message groups exist or which you are part of, well, unless they are a member of the group. With the database being encrypted there is no easy way to access your data. **Every user**, at minimum, can read all public messages. -**Encryption**, the JAMA database is fully encrypted. Your posts are protected from prying eyes, including your JAMA administrators. - ---- +---- +---- ## Navigating JAMA @@ -29,11 +35,10 @@ The only people that can read your direct messages (**person 2 person** or **gro The sidebar shows all your message groups and direct conversations. Tap or click any group to open it. - **#** prefix indicates a **Public** group — visible to all users -- **Lock** icon indicates a **Private** group — invite only -- **Bold** group names have unread messages -- The last message preview shows **You:** if you sent it +- **Bold** group names, with a notification badge means you have unread messages +- A message with the newest post with alway be listed at the top +- The last message preview shows a message from a user in your group, or **You:** if you sent it ---- ## Sending Messages @@ -44,15 +49,15 @@ Type your message in the input box at the bottom and press **Enter** to send. - Use the **camera** icon to take a photo directly (mobile only) ### Mentioning Someone -Type **@** followed by the person's name to mention them. Select from the dropdown that appears. Mentioned users receive a notification. +Type **@** will bring a group user list, select a users real name to mention them. Users receive a notification. -Example: `@[John Smith]` will notify John. +Example: `@[John Smith]` will notify John Smith of the message. ### Replying to a Message -Hover over any message and click the **reply arrow** to quote and reply to it. +Hover over any message and click the **reply arrow** in the pop-up to quote and reply to it. ### Reacting to a Message -Hover over any message and select a common emoji or click the **emoji** button to bring up a full list to select from. +Hover over any message and select a common emoji in the pop-up to or click the **emoji** button to bring up a full list to select from. --- @@ -69,7 +74,7 @@ _**Message Window**_ 1. Click the users avatar in a message window to bring up the profile 2. Click **Direct Message** -_**Note:** users have the ability to disable direct and private messages in their profile. If set, they will not be listed in the "New Chat" list and the "Direct Message" button is not enabled._ +> _Users have the ability to disable direct and private messages in their profile. If set, they will not be listed in the "New Chat" user list and the "Direct Message" button is not enabled._ --- @@ -82,9 +87,9 @@ To create a group conversation: 3. Enter a **Message Name** 4. Click **Create** -> If a message group with the exact same members already exists, you will be redirected to it automatically. This helps to avoid duplication. +> _If a message group with the exact same members already exists, you will be redirected to it automatically. This helps to avoid duplication._ -_**Note:** User have the option to leave any direct message conversation by selecting the "Message Info" button in the top right corner in the message title._ +_**Note:** Users have the option to leave any direct message group by selecting the "Message Info" button in the top right corner in the message title._ --- diff --git a/backend/src/models/db.js b/backend/src/models/db.js index ecac3f0..bafc87e 100644 --- a/backend/src/models/db.js +++ b/backend/src/models/db.js @@ -170,6 +170,7 @@ function initDb() { insertSetting.run('pwa_icon_192', ''); insertSetting.run('pwa_icon_512', ''); insertSetting.run('color_title', ''); + insertSetting.run('color_title_dark', ''); insertSetting.run('color_avatar_public', ''); insertSetting.run('color_avatar_dm', ''); diff --git a/backend/src/routes/settings.js b/backend/src/routes/settings.js index c081b05..d418aba 100644 --- a/backend/src/routes/settings.js +++ b/backend/src/routes/settings.js @@ -115,12 +115,13 @@ router.post('/icon-groupinfo', authMiddleware, adminMiddleware, uploadGroupInfo. // Reset all settings to defaults (admin) router.patch('/colors', authMiddleware, adminMiddleware, (req, res) => { - const { colorTitle, colorAvatarPublic, colorAvatarDm } = req.body; + const { colorTitle, colorTitleDark, colorAvatarPublic, colorAvatarDm } = req.body; const db = getDb(); const upd = db.prepare("INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = ?, updated_at = datetime('now')"); - if (colorTitle !== undefined) upd.run('color_title', colorTitle || '', colorTitle || ''); + if (colorTitle !== undefined) upd.run('color_title', colorTitle || '', colorTitle || ''); + if (colorTitleDark !== undefined) upd.run('color_title_dark', colorTitleDark || '', colorTitleDark || ''); if (colorAvatarPublic !== undefined) upd.run('color_avatar_public', colorAvatarPublic || '', colorAvatarPublic || ''); - if (colorAvatarDm !== undefined) upd.run('color_avatar_dm', colorAvatarDm || '', colorAvatarDm || ''); + if (colorAvatarDm !== undefined) upd.run('color_avatar_dm', colorAvatarDm || '', colorAvatarDm || ''); res.json({ success: true }); }); @@ -129,7 +130,7 @@ router.post('/reset', authMiddleware, adminMiddleware, (req, res) => { const originalName = process.env.APP_NAME || 'jama'; db.prepare("UPDATE settings SET value = ?, updated_at = datetime('now') WHERE key = 'app_name'").run(originalName); db.prepare("UPDATE settings SET value = '', updated_at = datetime('now') WHERE key = 'logo_url'").run(); - db.prepare("UPDATE settings SET value = '', updated_at = datetime('now') WHERE key IN ('icon_newchat', 'icon_groupinfo', 'pwa_icon_192', 'pwa_icon_512', 'color_title', 'color_avatar_public', 'color_avatar_dm')").run(); + db.prepare("UPDATE settings SET value = '', updated_at = datetime('now') WHERE key IN ('icon_newchat', 'icon_groupinfo', 'pwa_icon_192', 'pwa_icon_512', 'color_title', 'color_title_dark', 'color_avatar_public', 'color_avatar_dm')").run(); res.json({ success: true }); }); diff --git a/build.sh b/build.sh index a26a9ba..48d87b5 100644 --- a/build.sh +++ b/build.sh @@ -13,7 +13,7 @@ # ───────────────────────────────────────────────────────────── set -euo pipefail -VERSION="${1:-0.9.21}" +VERSION="${1:-0.9.22}" ACTION="${2:-}" REGISTRY="${REGISTRY:-}" IMAGE_NAME="jama" diff --git a/frontend/package.json b/frontend/package.json index 0f473e6..80ffa3d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "jama-frontend", - "version": "0.9.21", + "version": "0.9.22", "private": true, "scripts": { "dev": "vite", diff --git a/frontend/src/components/BrandingModal.jsx b/frontend/src/components/BrandingModal.jsx index d9dd05e..a66e8f2 100644 --- a/frontend/src/components/BrandingModal.jsx +++ b/frontend/src/components/BrandingModal.jsx @@ -2,7 +2,8 @@ import { useState, useEffect, useRef, useCallback } from 'react'; import { api } from '../utils/api.js'; import { useToast } from '../contexts/ToastContext.jsx'; -const DEFAULT_TITLE_COLOR = '#1a73e8'; +const DEFAULT_TITLE_COLOR = '#1a73e8'; // light mode default +const DEFAULT_TITLE_DARK_COLOR = '#60a5fa'; // dark mode default (lighter blue readable on dark bg) const DEFAULT_PUBLIC_COLOR = '#1a73e8'; const DEFAULT_DM_COLOR = '#a142f4'; @@ -10,6 +11,45 @@ const COLOUR_SUGGESTIONS = [ '#1a73e8', '#a142f4', '#e53935', '#fa7b17', '#fdd835', '#34a853', ]; +// ── Title Colour Row — one row per mode ────────────────────────────────────── + +function TitleColourRow({ bgColor, bgLabel, textColor, appName, onChange }) { + const [mode, setMode] = useState('idle'); // 'idle' | 'custom' + + return ( +