ltcai 6.7.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -31
- package/docs/CHANGELOG.md +48 -0
- package/frontend/src/App.tsx +80 -0
- package/frontend/src/api/client.ts +11 -0
- package/frontend/src/components/AdminAccessGate.tsx +70 -0
- package/frontend/src/components/BrainConversation.tsx +232 -8
- package/frontend/src/components/FeedbackState.tsx +45 -0
- package/frontend/src/components/WorkspaceProfileSwitcher.tsx +176 -0
- package/frontend/src/components/onboarding/AnalysisScreen.tsx +20 -12
- package/frontend/src/components/onboarding/InstallScreen.tsx +55 -0
- package/frontend/src/components/onboarding/RecommendationScreen.tsx +55 -5
- package/frontend/src/components/onboarding/recommendationModel.ts +59 -2
- package/frontend/src/features/brain/BrainConversation.tsx +382 -7
- package/frontend/src/features/brain/BrainGraphLayer.tsx +258 -25
- package/frontend/src/features/brain/BrainHome.tsx +300 -1
- package/frontend/src/features/brain/brainData.ts +25 -1
- package/frontend/src/features/brain/graphLayout.ts +12 -1
- package/frontend/src/features/brain/types.ts +54 -0
- package/frontend/src/i18n.ts +374 -0
- package/frontend/src/store/appStore.ts +15 -0
- package/frontend/src/styles.css +1383 -41
- package/lattice_brain/__init__.py +1 -1
- package/lattice_brain/runtime/multi_agent.py +1 -1
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/workspace.py +59 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/package.json +1 -1
- package/scripts/brain_quality_eval.py +118 -0
- package/src-tauri/Cargo.lock +1 -1
- package/src-tauri/Cargo.toml +1 -1
- package/src-tauri/tauri.conf.json +1 -1
- package/static/app/asset-manifest.json +28 -28
- package/static/app/assets/Act-BHEb8bAM.js +2 -0
- package/static/app/assets/{Act-DGN37eR4.js.map → Act-BHEb8bAM.js.map} +1 -1
- package/static/app/assets/Brain-yvR7xkrV.js +322 -0
- package/static/app/assets/Brain-yvR7xkrV.js.map +1 -0
- package/static/app/assets/Capture-BrAmsSEH.js +2 -0
- package/static/app/assets/Capture-BrAmsSEH.js.map +1 -0
- package/static/app/assets/Library-BOVzYfxI.js +2 -0
- package/static/app/assets/{Library-BbagRFyd.js.map → Library-BOVzYfxI.js.map} +1 -1
- package/static/app/assets/System-D4WaN4kj.js +2 -0
- package/static/app/assets/System-D4WaN4kj.js.map +1 -0
- package/static/app/assets/index-BOB-W1FZ.js +17 -0
- package/static/app/assets/index-BOB-W1FZ.js.map +1 -0
- package/static/app/assets/index-DvLsGy-z.css +2 -0
- package/static/app/assets/primitives-C3_BfUb8.js +2 -0
- package/static/app/assets/primitives-C3_BfUb8.js.map +1 -0
- package/static/app/assets/textarea-CbvhHvzg.js +2 -0
- package/static/app/assets/{textarea-C2PLu6_O.js.map → textarea-CbvhHvzg.js.map} +1 -1
- package/static/app/index.html +2 -2
- package/static/app/assets/Act-DGN37eR4.js +0 -2
- package/static/app/assets/Brain-HDcIwPHW.js +0 -322
- package/static/app/assets/Brain-HDcIwPHW.js.map +0 -1
- package/static/app/assets/Capture--eZfb_Ex.js +0 -2
- package/static/app/assets/Capture--eZfb_Ex.js.map +0 -1
- package/static/app/assets/Library-BbagRFyd.js +0 -2
- package/static/app/assets/System-C6pd3Mp_.js +0 -2
- package/static/app/assets/System-C6pd3Mp_.js.map +0 -1
- package/static/app/assets/index-C950aES_.js +0 -17
- package/static/app/assets/index-C950aES_.js.map +0 -1
- package/static/app/assets/index-ztppMg0c.css +0 -2
- package/static/app/assets/primitives-Bcm5lZRu.js +0 -2
- package/static/app/assets/primitives-Bcm5lZRu.js.map +0 -1
- package/static/app/assets/textarea-C2PLu6_O.js +0 -2
package/README.md
CHANGED
|
@@ -69,42 +69,42 @@ You need Lattice AI when:
|
|
|
69
69
|
Choose the owner of the Brain. The profile is not a SaaS account by default; it
|
|
70
70
|
is the local identity for the knowledge you keep.
|
|
71
71
|
|
|
72
|
-

|
|
73
73
|
|
|
74
74
|
### 2. Environment Analysis
|
|
75
75
|
|
|
76
76
|
See what kind of local AI experience this computer can support before choosing a
|
|
77
77
|
model.
|
|
78
78
|
|
|
79
|
-

|
|
80
80
|
|
|
81
81
|
### 3. Recommended Models
|
|
82
82
|
|
|
83
83
|
Start with a short list: safest recommendation, faster model, stronger model.
|
|
84
84
|
Advanced details stay available without overwhelming first-time users.
|
|
85
85
|
|
|
86
|
-

|
|
87
87
|
|
|
88
88
|
### 4. Install And Load
|
|
89
89
|
|
|
90
90
|
Download and load only after consent. Lattice explains model size, local
|
|
91
91
|
execution, and network use before work starts.
|
|
92
92
|
|
|
93
|
-

|
|
94
94
|
|
|
95
95
|
### 5. Brain Chat
|
|
96
96
|
|
|
97
97
|
Talk normally. Useful decisions and context become memory, then appear later as
|
|
98
98
|
topics, relationships, and graph structure.
|
|
99
99
|
|
|
100
|
-

|
|
101
101
|
|
|
102
102
|
### 6. Review Center
|
|
103
103
|
|
|
104
104
|
Automation results are staged for review before they become durable decisions.
|
|
105
105
|
Snooze, unsnooze, run now, approve, and dismiss actions stay explicit.
|
|
106
106
|
|
|
107
|
-

|
|
108
108
|
|
|
109
109
|
## Brain Depths
|
|
110
110
|
|
|
@@ -120,10 +120,10 @@ The user travels inward from everyday memory to deeper structure:
|
|
|
120
120
|
|
|
121
121
|
Walkthrough:
|
|
122
122
|
|
|
123
|
-

|
|
124
124
|
|
|
125
125
|
Screenshot index and capture notes:
|
|
126
|
-
[output/release/
|
|
126
|
+
[output/release/v7.0.0/SCREENSHOT_INDEX.md](output/release/v7.0.0/SCREENSHOT_INDEX.md)
|
|
127
127
|
|
|
128
128
|
## Install
|
|
129
129
|
|
|
@@ -200,29 +200,25 @@ See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for developer workflow details.
|
|
|
200
200
|
|
|
201
201
|
## Current Release
|
|
202
202
|
|
|
203
|
-
The current release is **
|
|
204
|
-
|
|
205
|
-
-
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
- `
|
|
222
|
-
- `dist/ltcai-6.7.0.tar.gz`
|
|
223
|
-
- `ltcai-6.7.0.tgz`
|
|
224
|
-
- `dist/ltcai-6.7.0.vsix`
|
|
225
|
-
- `src-tauri/target/release/bundle/dmg/Lattice AI_6.7.0_aarch64.dmg`
|
|
203
|
+
The current release is **7.1.0 Brain Usability Completion**:
|
|
204
|
+
|
|
205
|
+
- First-run onboarding now explains detected hardware, recommendation timing,
|
|
206
|
+
install progress, and the next action in plain language.
|
|
207
|
+
- Brain Home shows ingestion progress for files, folders, notes, and web pages,
|
|
208
|
+
including memory emergence after content lands.
|
|
209
|
+
- Knowledge Graph exploration adds search suggestions, type filters, time
|
|
210
|
+
exploration, focus movement, and neighbor highlighting.
|
|
211
|
+
- Chat answers surface inline source citations and accessible proof payloads.
|
|
212
|
+
- Workspace/profile/admin entry points, empty/error feedback, consent revoke
|
|
213
|
+
feedback, and VS Code extension sync status are visible in the product shell.
|
|
214
|
+
|
|
215
|
+
Expected artifacts for 7.1.0 release must use exact filenames:
|
|
216
|
+
|
|
217
|
+
- `dist/ltcai-7.1.0-py3-none-any.whl`
|
|
218
|
+
- `dist/ltcai-7.1.0.tar.gz`
|
|
219
|
+
- `ltcai-7.1.0.tgz`
|
|
220
|
+
- `dist/ltcai-7.1.0.vsix`
|
|
221
|
+
- `src-tauri/target/release/bundle/dmg/Lattice AI_7.1.0_aarch64.dmg`
|
|
226
222
|
|
|
227
223
|
Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
228
224
|
|
|
@@ -241,6 +237,8 @@ Do not upload `dist/*`. Package registry publishing remains owner-run.
|
|
|
241
237
|
|
|
242
238
|
| Version | Theme |
|
|
243
239
|
| --- | --- |
|
|
240
|
+
| 7.1.0 | Brain Usability Completion: clearer first-run onboarding, ingestion progress/emergence, richer graph controls, inline answer proof, workspace/profile/admin discovery, empty/error/consent feedback, and VS Code sync status |
|
|
241
|
+
| 7.0.0 | Brain Productization Loop: first-screen ingestion for files/folders/notes/web, answer-level memory proof and source citations, model-continuity demo flow, five-minute first-run loop, and recall/KG quality eval in CI |
|
|
244
242
|
| 6.7.0 | Brain IA Cleanup: reachable rich pages, separated product routes vs compatibility aliases, shared Brain shell navigation, and lazy-loaded rich pages |
|
|
245
243
|
| 6.6.0 | Brain Proof Runtime: backend-owned Brain proof API, model-continuity wiring, first-screen proof that saved context can be recalled across model changes, and direct Brain Home document upload |
|
|
246
244
|
| 6.5.0 | Brain Experience Readiness: Brain readiness signal, depth progress rail, source-aware memory-save feedback, and visual coverage for the first-memory loop |
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,54 @@ The top entry is either the current unreleased main-branch work or the current
|
|
|
4
4
|
release line. Older entries are historical and may describe behavior as it
|
|
5
5
|
existed at that release.
|
|
6
6
|
|
|
7
|
+
## [7.1.0] - 2026-06-20
|
|
8
|
+
|
|
9
|
+
> Brain Usability Completion. Completes the 7.1.0 first-run through editor-sync
|
|
10
|
+
> usability pass: clear onboarding, visible ingestion, graph controls, inline
|
|
11
|
+
> proof, workspace/admin discovery, feedback states, and VS Code sync status.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- Hardware visualization, expected timing, install timeline, and next-action
|
|
15
|
+
copy in first-run onboarding.
|
|
16
|
+
- Brain Home ingestion stage disclosure and memory emergence timeline for file,
|
|
17
|
+
folder, note, and URL sources.
|
|
18
|
+
- Knowledge Graph search suggestions, entity type filters, recent/all-time time
|
|
19
|
+
exploration, focus clearing, and neighbor highlighting.
|
|
20
|
+
- Inline answer citation markers with keyboard-accessible proof cards.
|
|
21
|
+
- Workspace/profile switcher, Admin Console gate, consent revoke feedback, and
|
|
22
|
+
shared empty/error feedback surfaces in the Brain shell.
|
|
23
|
+
- VS Code extension heartbeat/status endpoint plus extension and main-app sync
|
|
24
|
+
indicators for connected/indexing/synced/offline states.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- Package/runtime/static metadata is synchronized to 7.1.0; package publish and
|
|
28
|
+
deployment remain owner-run only.
|
|
29
|
+
|
|
30
|
+
## [7.0.0] - 2026-06-18
|
|
31
|
+
|
|
32
|
+
> Brain Productization Loop. Turns the Brain proof work into a first-five-minute
|
|
33
|
+
> product flow: add sources, ask a question, see proof/citations, and verify the
|
|
34
|
+
> same Brain evidence after switching models.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- Brain Home ingestion panel for files, local folder paths, notes, and web URLs,
|
|
38
|
+
all backed by existing workspace-scoped ingestion routes.
|
|
39
|
+
- Answer-level Memory proof and source citation cards rendered under assistant
|
|
40
|
+
responses after Brain proof refreshes for the user's query.
|
|
41
|
+
- Model-continuity demo strip that lets the user recheck the same Brain
|
|
42
|
+
evidence and jump to model switching from the Brain flow.
|
|
43
|
+
- Deterministic `scripts/brain_quality_eval.py` recall/KG quality gate, wired
|
|
44
|
+
into CI after the unit suite.
|
|
45
|
+
- Visual mock coverage for Brain proof, document upload, note ingest, folder
|
|
46
|
+
indexing, and web URL ingestion endpoints.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
- Brain Home is now ingestion-first instead of chat-first: first screen action
|
|
50
|
+
labels are files/folders/notes/web, with deeper graph/model/settings still
|
|
51
|
+
reachable from the shell.
|
|
52
|
+
- Package/runtime/static metadata is synchronized to 7.0.0; package publish and
|
|
53
|
+
deployment remain owner-run only.
|
|
54
|
+
|
|
7
55
|
## [6.7.0] - 2026-06-18
|
|
8
56
|
|
|
9
57
|
> Brain IA Cleanup. Makes rich product pages reachable from Brain Home,
|
package/frontend/src/App.tsx
CHANGED
|
@@ -5,6 +5,12 @@ import { useAppStore } from "@/store/appStore";
|
|
|
5
5
|
import { parseHash, productShellRoutes } from "@/routes";
|
|
6
6
|
import { BrainHome } from "@/features/brain/BrainHome";
|
|
7
7
|
import { AdminConsole } from "@/features/admin/AdminConsole";
|
|
8
|
+
import { WorkspaceProfileSwitcher } from "@/components/WorkspaceProfileSwitcher";
|
|
9
|
+
import { AdminAccessGate } from "@/components/AdminAccessGate";
|
|
10
|
+
import { t, type Language } from "@/i18n";
|
|
11
|
+
import { latticeApi } from "@/api/client";
|
|
12
|
+
import { useQuery } from "@tanstack/react-query";
|
|
13
|
+
import { FeedbackState } from "@/components/FeedbackState";
|
|
8
14
|
|
|
9
15
|
const ActPage = React.lazy(() => import("@/pages/Act").then((module) => ({ default: module.ActPage })));
|
|
10
16
|
const BrainPage = React.lazy(() => import("@/pages/Brain").then((module) => ({ default: module.BrainPage })));
|
|
@@ -95,6 +101,7 @@ function BrainShell({
|
|
|
95
101
|
active: string;
|
|
96
102
|
children: React.ReactNode;
|
|
97
103
|
}) {
|
|
104
|
+
const language = useAppStore((state) => state.language);
|
|
98
105
|
return (
|
|
99
106
|
<main className="brain-shell-page" aria-label="Lattice workspace">
|
|
100
107
|
<nav className="brain-shell-nav" aria-label="Brain workspace navigation">
|
|
@@ -103,19 +110,92 @@ function BrainShell({
|
|
|
103
110
|
key={item.id}
|
|
104
111
|
type="button"
|
|
105
112
|
className={item.id === active ? "is-active" : ""}
|
|
113
|
+
aria-current={item.id === active ? "page" : undefined}
|
|
106
114
|
onClick={() => navigateHash(`/${item.path}`)}
|
|
107
115
|
>
|
|
108
116
|
{item.label}
|
|
109
117
|
</button>
|
|
110
118
|
))}
|
|
119
|
+
<div className="brain-shell-switchers" aria-label={t(language, "shell.workspace.label")}>
|
|
120
|
+
<VsCodeSyncStatus language={language} />
|
|
121
|
+
<WorkspaceProfileSwitcher language={language} />
|
|
122
|
+
<AdminAccessGate language={language} />
|
|
123
|
+
</div>
|
|
111
124
|
</nav>
|
|
112
125
|
<section className="brain-shell-content">
|
|
126
|
+
<ExternalConsentStatus language={language} />
|
|
113
127
|
{children}
|
|
114
128
|
</section>
|
|
115
129
|
</main>
|
|
116
130
|
);
|
|
117
131
|
}
|
|
118
132
|
|
|
133
|
+
function ExternalConsentStatus({ language }: { language: Language }) {
|
|
134
|
+
const externalConsent = useAppStore((state) => state.externalConsent);
|
|
135
|
+
const setExternalConsent = useAppStore((state) => state.setExternalConsent);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<section className="external-consent-status" aria-label={t(language, "feedback.consent.aria")}>
|
|
139
|
+
<FeedbackState
|
|
140
|
+
tone={externalConsent ? "empty" : "error"}
|
|
141
|
+
language={language}
|
|
142
|
+
title={externalConsent ? t(language, "feedback.consent.activeTitle") : t(language, "feedback.consent.revokedTitle")}
|
|
143
|
+
body={externalConsent ? t(language, "feedback.consent.activeBody") : t(language, "feedback.consent.revokedBody")}
|
|
144
|
+
actionLabel={externalConsent ? t(language, "feedback.consent.revoke") : t(language, "feedback.consent.reenable")}
|
|
145
|
+
onAction={() => setExternalConsent(!externalConsent)}
|
|
146
|
+
/>
|
|
147
|
+
</section>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function VsCodeSyncStatus({ language }: { language: Language }) {
|
|
152
|
+
const bridge = useQuery({
|
|
153
|
+
queryKey: ["workspaceVscodeStatus"],
|
|
154
|
+
queryFn: latticeApi.workspaceVscodeStatus,
|
|
155
|
+
refetchInterval: 15000,
|
|
156
|
+
});
|
|
157
|
+
const index = useQuery({
|
|
158
|
+
queryKey: ["index"],
|
|
159
|
+
queryFn: latticeApi.indexStatus,
|
|
160
|
+
refetchInterval: 15000,
|
|
161
|
+
});
|
|
162
|
+
const data = bridge.data?.data as Record<string, unknown> | undefined;
|
|
163
|
+
const lastSeen = Number(data?.last_seen_ms || 0);
|
|
164
|
+
const connected = Boolean(data?.connected) || (lastSeen > 0 && Date.now() - lastSeen < 60000);
|
|
165
|
+
const indexData = index.data?.data as Record<string, unknown> | undefined;
|
|
166
|
+
const indexStatus = String(indexData?.status || indexData?.state || "");
|
|
167
|
+
const indexing = /index|build|running|pending/i.test(indexStatus);
|
|
168
|
+
const state = bridge.isLoading
|
|
169
|
+
? "checking"
|
|
170
|
+
: !connected
|
|
171
|
+
? "offline"
|
|
172
|
+
: indexing
|
|
173
|
+
? "indexing"
|
|
174
|
+
: "synced";
|
|
175
|
+
const labelKey = `shell.sync.${state}`;
|
|
176
|
+
const detail = connected
|
|
177
|
+
? t(language, "shell.sync.detail")
|
|
178
|
+
: t(language, "shell.sync.detailOffline");
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<button
|
|
182
|
+
type="button"
|
|
183
|
+
className={`vscode-sync-status is-${state}`}
|
|
184
|
+
aria-label={`${t(language, "shell.sync.label")}: ${t(language, labelKey)}`}
|
|
185
|
+
title={`${t(language, "shell.sync.label")}: ${t(language, labelKey)}\n${detail}`}
|
|
186
|
+
onClick={() => {
|
|
187
|
+
window.location.hash = "/settings";
|
|
188
|
+
}}
|
|
189
|
+
>
|
|
190
|
+
<span className="vscode-sync-dot" aria-hidden="true" />
|
|
191
|
+
<span className="vscode-sync-copy">
|
|
192
|
+
<strong>{t(language, "shell.sync.label")}</strong>
|
|
193
|
+
<small>{t(language, labelKey)}</small>
|
|
194
|
+
</span>
|
|
195
|
+
</button>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
119
199
|
function PageLoader() {
|
|
120
200
|
return (
|
|
121
201
|
<div className="brain-shell-loader" role="status">
|
|
@@ -416,6 +416,12 @@ export const latticeApi = {
|
|
|
416
416
|
},
|
|
417
417
|
health: () => get("/health", {}),
|
|
418
418
|
workspaceOs: () => get("/workspace/os", { counts: {}, models: {}, workspace_registry: { workspaces: [] } }),
|
|
419
|
+
workspaceVscodeStatus: () => get("/workspace/vscode/status", {
|
|
420
|
+
connected: false,
|
|
421
|
+
last_seen_ms: 0,
|
|
422
|
+
status: "offline",
|
|
423
|
+
index_status: "unknown",
|
|
424
|
+
}),
|
|
419
425
|
indexStatus: () => get("/api/index/status", {}),
|
|
420
426
|
rebuildIndex: () => post("/api/index/rebuild", { full: false, include_nodes: true, include_chunks: true }, {}),
|
|
421
427
|
graph: () => get("/knowledge-graph/graph", { nodes: [], edges: [] }),
|
|
@@ -444,6 +450,11 @@ export const latticeApi = {
|
|
|
444
450
|
return res;
|
|
445
451
|
},
|
|
446
452
|
browserReadUrl: (url: string) => post("/api/browser/read-url", { url }, {}),
|
|
453
|
+
ingestNote: (content: string, title = "Brain note") => post(
|
|
454
|
+
"/knowledge-graph/ingest",
|
|
455
|
+
{ type: "note", content, title, source: "brain_home" },
|
|
456
|
+
{},
|
|
457
|
+
),
|
|
447
458
|
memoryManager: () => get("/api/memory/manager", { sources: [], tiers: [], usage: {} }),
|
|
448
459
|
memoryBrainQuality: () => get("/api/memory/brain-quality", {}),
|
|
449
460
|
memoryBrainProof: (query = "", limit = 3) => get("/api/memory/brain-proof", { proofs: {}, recall: { items: [] }, model_continuity: {}, claims: {} }, { q: query, limit }),
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { ShieldCheck, Lock } from "lucide-react";
|
|
3
|
+
import { t, type Language } from "@/i18n";
|
|
4
|
+
import { useAppStore, type WorkspaceMode } from "@/store/appStore";
|
|
5
|
+
|
|
6
|
+
const MODES: WorkspaceMode[] = ["basic", "advanced", "admin"];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Role-aware admin entry point for the Brain shell.
|
|
10
|
+
*
|
|
11
|
+
* Mode is the access proxy used across the app (SystemPage gates the admin
|
|
12
|
+
* tab and AdminPanel on `mode`). When the user is in advanced/admin mode we
|
|
13
|
+
* surface a discoverable Admin Console button plus a compact mode switcher.
|
|
14
|
+
* In basic mode the console is hidden behind an explained affordance that
|
|
15
|
+
* promotes the user to admin mode rather than failing silently.
|
|
16
|
+
*/
|
|
17
|
+
export function AdminAccessGate({ language }: { language: Language }) {
|
|
18
|
+
const mode = useAppStore((state) => state.mode);
|
|
19
|
+
const setMode = useAppStore((state) => state.setMode);
|
|
20
|
+
const canSeeAdmin = mode === "advanced" || mode === "admin";
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="admin-access-gate">
|
|
24
|
+
{canSeeAdmin ? (
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
className="admin-access-button"
|
|
28
|
+
title={t(language, "shell.admin.tooltip")}
|
|
29
|
+
aria-label={t(language, "shell.admin.open")}
|
|
30
|
+
onClick={() => {
|
|
31
|
+
window.location.hash = "/admin";
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
<ShieldCheck className="h-3.5 w-3.5" aria-hidden="true" />
|
|
35
|
+
<span>{t(language, "shell.admin.label")}</span>
|
|
36
|
+
</button>
|
|
37
|
+
) : (
|
|
38
|
+
<button
|
|
39
|
+
type="button"
|
|
40
|
+
className="admin-access-button is-locked"
|
|
41
|
+
title={t(language, "shell.admin.needsMode")}
|
|
42
|
+
aria-label={t(language, "shell.admin.needsMode")}
|
|
43
|
+
onClick={() => setMode("admin")}
|
|
44
|
+
>
|
|
45
|
+
<Lock className="h-3.5 w-3.5" aria-hidden="true" />
|
|
46
|
+
<span>{t(language, "shell.admin.enable")}</span>
|
|
47
|
+
</button>
|
|
48
|
+
)}
|
|
49
|
+
|
|
50
|
+
<div
|
|
51
|
+
className="mode-switcher-mini"
|
|
52
|
+
role="group"
|
|
53
|
+
aria-label={t(language, "shell.mode.label")}
|
|
54
|
+
title={t(language, "shell.mode.info")}
|
|
55
|
+
>
|
|
56
|
+
{MODES.map((item) => (
|
|
57
|
+
<button
|
|
58
|
+
key={item}
|
|
59
|
+
type="button"
|
|
60
|
+
className={mode === item ? "is-active" : ""}
|
|
61
|
+
aria-pressed={mode === item}
|
|
62
|
+
onClick={() => setMode(item)}
|
|
63
|
+
>
|
|
64
|
+
{t(language, `shell.mode.${item}`)}
|
|
65
|
+
</button>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|