diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte
index db8e18d..31352f8 100644
--- a/frontend/src/App.svelte
+++ b/frontend/src/App.svelte
@@ -78,6 +78,7 @@
'/invite-codes',
'/did-document',
'/admin',
+ '/about',
])
function getComponent(path: string) {
diff --git a/frontend/src/components/dashboard/AboutContent.svelte b/frontend/src/components/dashboard/AboutContent.svelte
new file mode 100644
index 0000000..9334f3d
--- /dev/null
+++ b/frontend/src/components/dashboard/AboutContent.svelte
@@ -0,0 +1,247 @@
+
+
+
+ {#if loading}
+
{$_('common.loading')}
+ {:else}
+
+ {$_('about.serverSection')}
+
+
+
+
+ {$_('about.contactSection')}
+
+
+
+ {#if session.isAdmin}
+
+ {$_('about.communicationSection')}
+
+
+ {/if}
+
+ {#if session.isAdmin}
+
+ {$_('about.frontendSection')}
+
+
+ {/if}
+
+
+ {$_('about.accountSection')}
+
+
+
+
+ {$_('about.environmentSection')}
+
+
+
+
+
+
+ {/if}
+
+
+
diff --git a/frontend/src/lib/types/api.ts b/frontend/src/lib/types/api.ts
index f91adcb..a20c4c4 100644
--- a/frontend/src/lib/types/api.ts
+++ b/frontend/src/lib/types/api.ts
@@ -189,9 +189,15 @@ export interface ServerLinks {
termsOfService?: string;
}
+export interface ServerContact {
+ email?: string;
+}
+
export interface ServerDescription {
availableUserDomains: string[];
inviteCodeRequired: boolean;
+ did: string;
+ contact?: ServerContact;
links?: ServerLinks;
version?: string;
availableCommsChannels?: VerificationChannel[];
diff --git a/frontend/src/lib/types/routes.ts b/frontend/src/lib/types/routes.ts
index d728875..0828036 100644
--- a/frontend/src/lib/types/routes.ts
+++ b/frontend/src/lib/types/routes.ts
@@ -14,6 +14,7 @@ export const routes = {
didDocument: "/did-document",
migrate: "/migrate",
admin: "/admin",
+ about: "/about",
verify: "/verify",
resetPassword: "/reset-password",
recoverPasskey: "/recover-passkey",
diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json
index d33ff64..97bb2ad 100644
--- a/frontend/src/locales/en.json
+++ b/frontend/src/locales/en.json
@@ -145,7 +145,52 @@
"navDidDocument": "DID Document",
"migrated": "Migrated",
"migratedTitle": "Account Migrated",
- "migratedMessage": "Your account has migrated to {pds}. Your DID document is still hosted here, and you can update it for future migrations."
+ "migratedMessage": "Your account has migrated to {pds}. Your DID document is still hosted here, and you can update it for future migrations.",
+ "navAbout": "About"
+ },
+ "about": {
+ "title": "About",
+ "copyDebugInfo": "Copy Debug Info",
+ "copied": "Debug info copied to clipboard",
+ "copyFailed": "Failed to copy debug info",
+ "serverSection": "Server",
+ "frontendSection": "Frontend",
+ "accountSection": "Account",
+ "environmentSection": "Environment",
+ "serverName": "Server Name",
+ "pdsVersion": "PDS Version",
+ "serverUrl": "Server URL",
+ "availableDomains": "Available Domains",
+ "did": "DID",
+ "handle": "Handle",
+ "accountStatus": "Account Status",
+ "adminStatus": "Admin",
+ "userAgent": "User Agent",
+ "locale": "Locale",
+ "screenSize": "Screen Size",
+ "yes": "Yes",
+ "no": "No",
+ "unknown": "Unknown",
+ "notConfigured": "Not configured",
+ "serverDid": "Server DID",
+ "inviteCodeRequired": "Invite Code Required",
+ "selfHostedDidWeb": "Self-Hosted DID:web",
+ "enabled": "Enabled",
+ "disabled": "Disabled",
+ "contactSection": "Contact & Policies",
+ "contactEmail": "Contact Email",
+ "privacyPolicy": "Privacy Policy",
+ "termsOfService": "Terms of Service",
+ "communicationSection": "Communication",
+ "availableChannels": "Available Channels",
+ "discordBot": "Discord Bot",
+ "discordAppId": "Discord App ID",
+ "telegramBot": "Telegram Bot",
+ "svelteVersion": "Svelte",
+ "svelteI18nVersion": "svelte-i18n",
+ "viteVersion": "Vite",
+ "buildMode": "Build Mode",
+ "userCount": "User Count"
},
"didEditor": {
"preview": "Current DID Document",
diff --git a/frontend/src/routes/Dashboard.svelte b/frontend/src/routes/Dashboard.svelte
index 787b4e0..dd28068 100644
--- a/frontend/src/routes/Dashboard.svelte
+++ b/frontend/src/routes/Dashboard.svelte
@@ -24,8 +24,9 @@
import InviteCodesContent from '../components/dashboard/InviteCodesContent.svelte'
import DidDocumentContent from '../components/dashboard/DidDocumentContent.svelte'
import AdminContent from '../components/dashboard/AdminContent.svelte'
+ import AboutContent from '../components/dashboard/AboutContent.svelte'
- type Section = 'settings' | 'security' | 'sessions' | 'app-passwords' | 'comms' | 'repo' | 'controllers' | 'invite-codes' | 'did-document' | 'admin'
+ type Section = 'settings' | 'security' | 'sessions' | 'app-passwords' | 'comms' | 'repo' | 'controllers' | 'invite-codes' | 'did-document' | 'admin' | 'about'
const auth = $derived(getAuthState())
let dropdownOpen = $state(false)
@@ -75,6 +76,7 @@
'/invite-codes': 'invite-codes',
'/did-document': 'did-document',
'/admin': 'admin',
+ '/about': 'about',
}
return sectionMap[path] ?? null
})
@@ -150,6 +152,7 @@
'invite-codes': '/invite-codes',
'did-document': '/did-document',
'admin': '/admin',
+ 'about': '/about',
}
function selectSection(section: Section) {
@@ -181,9 +184,11 @@
{ id: 'admin', label: $_('dashboard.navAdmin'), show: session?.isAdmin ?? false, highlight: 'admin' },
])
+ const aboutItem = { id: 'about' as Section, label: $_('dashboard.navAbout') }
const visibleNavItems = $derived(navItems.filter(item => item.show))
function getSectionTitle(section: Section): string {
+ if (section === 'about') return aboutItem.label
const item = navItems.find(i => i.id === section)
return item?.label ?? ''
}
@@ -276,6 +281,18 @@
{/each}
+
+