diff --git a/README.md b/README.md
index 2a1bb14..66c81f9 100644
--- a/README.md
+++ b/README.md
@@ -43,8 +43,8 @@ from the **Accounts** panel (each gets a one-time access key to hand over).
- Admin creates users (`username`, display name, avatar URL, theme) — the API
returns a `ka_…` access key **once**; keys are stored hashed (sha256).
- Users log in with `{ username, key }`. Regenerating a key revokes old sessions.
-- Per-account: display name, avatar URL (host images e.g. on `catbox.moe` and
- paste the link; empty = initials avatar), theme (`auto`/`light`/`dark`).
+- Per-account: display name, avatar (uploaded to the built-in CDN from profile
+ settings), theme (`auto`/`light`/`dark`), accent color, feature flags.
## API
@@ -60,6 +60,9 @@ from the **Accounts** panel (each gets a one-time access key to hand over).
| POST | `/api/admin/users/:id/regenerate` | admin | new key, old sessions revoked |
| GET/PATCH | `/api/admin/settings` | admin | feature flags: registrationEnabled, ocrEnabled |
| GET/POST | `/api/conversations` | Bearer | server-persisted chats (title, topic, model) |
+| GET | `/api/conversations/search?q=` | Bearer | search titles, topics + old prompts (with snippet) |
+| POST | `/api/admin/ollama/pull` | admin | pull a model from the Ollama library (NDJSON progress) |
+| DELETE | `/api/admin/ollama/models/:name` | admin | remove a local Ollama model |
| GET/PATCH/DELETE | `/api/conversations/:id` | owner | incl. messages on GET |
| POST/GET/DELETE | `/api/conversations/:id/share` | owner | public link `/share/:publicId` |
| GET | `/api/share/:publicId` | **public** | read-only shared chat JSON |
diff --git a/anoying_promt b/anoying_promt
index 935df77..3c750f3 100644
--- a/anoying_promt
+++ b/anoying_promt
@@ -27,3 +27,15 @@ Can refusing with a reason / accepting with reason / reviewing :
each new message in the conversations makes a new mail forwarded by (like real ticket)
precise that theses mail arent the official way and need to be responded into the official site (chat.kisakay.com/review)
makes beautiful simple easy - by design HTML for each type of mail
+
+--- UX bugs / improvements:
+class="flex w-full items-center gap-2.5 rounded-xl p-1.5 text-left transition hover:bg-stone-100 dark:hover:bg-zinc-800"
+the actual on:hover makes the two buttons together, seprared it goodly
+
+Use the new flower svgs built-in for the ai logo. Only one declaration of the logo, not copy-paste everywhere needing it. One constant and imported anywhere
+Make the loading screen smoother
+
+
+--- SETTINGS REWAMPING:
+Make a paginations system for users into the Admin Center.
+Filtering, by account timetamp, alphabetily filtered, unverified/etc...
diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md
index b24d6c4..d72c636 100644
--- a/docs/OPERATIONS.md
+++ b/docs/OPERATIONS.md
@@ -47,8 +47,8 @@ unshare. See `AGENTS.md`.
1. Log in as `admin` with the `APP_PASSWORD` key.
2. Open **Accounts** → *New account* → username (+ display name).
3. Copy the one-time `ka_…` key and hand it to the owner (chat, QR code, …).
-4. Users set their display name, avatar (upload box in profile settings, or a
- remote URL e.g. from `catbox.moe`) and theme in the profile settings.
+4. Users set their display name, avatar (upload a picture in the profile settings —
+ hosted on the built-in CDN), theme, accent color and feature flags in the settings.
5. Rotate a compromised key with the regenerate button (old sessions die);
delete removes the account with all its chats and shares.
diff --git a/frontend/index.html b/frontend/index.html
index 761a663..0a93baf 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -2,11 +2,40 @@
-
- KisAssistant
-
-
+
+ KisAssistant — private AI chat
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/public/robots.txt b/frontend/public/robots.txt
new file mode 100644
index 0000000..4ab1795
--- /dev/null
+++ b/frontend/public/robots.txt
@@ -0,0 +1,4 @@
+# KisAssistant — crawlers, LLM agents and scrapers are welcome on public pages.
+# Authenticated app routes (/api/* except /api/share/:id) require a Bearer key.
+User-agent: *
+Allow: /
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 49110c9..65423e9 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -9,7 +9,7 @@ import { ConvEditDialog, FilePreviewModal, SettingsModal, ShareModal } from "./c
import { AdminCenter } from "./components/AdminCenter.tsx";
import { SharePage } from "./components/SharePage.tsx";
import { ResetPage } from "./components/ResetPage.tsx";
-import { ConfirmDialog } from "./components/ui.tsx";
+import { ConfirmDialog, LoadingScreen } from "./components/ui.tsx";
function shareIdFromPath(): string | null {
const m = window.location.pathname.match(/^\/share\/([A-Za-z0-9_-]{6,64})\/?$/);
@@ -256,7 +256,7 @@ export function App() {
}
if (checking) {
- return
Loading…
;
+ return ;
}
if (!user) {
diff --git a/frontend/src/components/AdminCenter.tsx b/frontend/src/components/AdminCenter.tsx
index 6c8a8cb..fecd5da 100644
--- a/frontend/src/components/AdminCenter.tsx
+++ b/frontend/src/components/AdminCenter.tsx
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
import { ArrowLeft, LayoutDashboard, Mail, ShieldAlert, SlidersHorizontal, Users } from "lucide-react";
import { api } from "../lib/api.ts";
import { AdminPanel } from "./AdminPanel.tsx";
-import { Logo, Spinner, Switch } from "./ui.tsx";
+import { LoadingScreen, Logo, Spinner, Switch } from "./ui.tsx";
import { cn } from "../lib/cn.ts";
type Tab = "accounts" | "features" | "mail";
@@ -57,7 +57,7 @@ export function AdminCenter() {
}
if (allowed === null) {
- return
Checking admin access…
;
+ return ;
}
if (!allowed) {
diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx
index ad829ec..38c5fe4 100644
--- a/frontend/src/components/Sidebar.tsx
+++ b/frontend/src/components/Sidebar.tsx
@@ -11,7 +11,6 @@ import {
Share2,
Tag,
Trash2,
- Users,
X,
} from "lucide-react";
import type { Conversation, User } from "../lib/types.ts";
diff --git a/frontend/src/components/dialogs.tsx b/frontend/src/components/dialogs.tsx
index d89511f..e967dd9 100644
--- a/frontend/src/components/dialogs.tsx
+++ b/frontend/src/components/dialogs.tsx
@@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react";
-import { Globe, FileText, ImagePlus, Link2, Mail, Palette, Pencil, ScanText, Settings2, Sparkles, Tag, Unplug, UserPlus } from "lucide-react";
+import { Globe, FileText, ImagePlus, Link2, Mail, Palette, Pencil, ScanText, Search, Settings2, Sparkles, Tag, Unplug, User as UserIcon, UserPlus, X } from "lucide-react";
import { api } from "../lib/api.ts";
import { cn } from "../lib/cn.ts";
import { ACCENT_PRESETS, applyAccent, currentAccent, previewAccent, type AccentState } from "../lib/accent.ts";
@@ -354,8 +354,17 @@ export function SettingsModal({
const [uploading, setUploading] = useState(false);
const [uploadError, setUploadError] = useState("");
const [dragOver, setDragOver] = useState(false);
+ const [search, setSearch] = useState("");
const fileRef = useRef(null);
+ // Section search: each section lists keywords; a section shows when the
+ // query is empty or matches its title/keywords.
+ function show(...keywords: string[]): boolean {
+ const q = search.trim().toLowerCase();
+ if (!q) return true;
+ return keywords.some((k) => k.toLowerCase().includes(q));
+ }
+
useEffect(() => {
if (user) {
setDisplayName(user.displayName);
@@ -364,6 +373,7 @@ export function SettingsModal({
setTheme(user.theme);
setError("");
setUploadError("");
+ setSearch("");
}
}, [user]);
@@ -409,83 +419,122 @@ export function SettingsModal({
}
return (
-
+