Major rebranding, i18n, dashboard, shared folders, role capabilities

- Rebrand: new app/agent icons, SKALD.md, warm "paper" CSS palette
  (terracotta accent, --radius tokens, WCAG contrast, reduced-motion),
  updated favicon, tray icon, skaldkonur asset
- i18n: backend crate (i18n.rs, locale column, ui_locale config),
  frontend library (web/lib/i18n.js, I18nMixin, t(key)),
  translation files (web/i18n/), every component wired
- Dashboard: <dashboard-page> replaces old home-page content;
  <app-copilot> becomes the landing page (full/dock layout modes)
- Shared folders: API endpoints (shared_folders.rs), frontend page,
  can_write membership, container mount topology, user_fs routing
- Role capabilities: new db table & authorization seam (data not enums),
  roles.attrs JSON for ui_mode / interface select
- Setup: skald-setup prompts for language + password, sets ui_locale
- General: components migrated to CSS variables, Lit conventions cleanup,
  connectors/catalog/marketplace/approval refactoring
This commit is contained in:
2026-07-18 21:38:42 +01:00
parent 2b35312abd
commit 126886e309
109 changed files with 6228 additions and 1390 deletions
+11 -10
View File
@@ -1,7 +1,8 @@
import { html } from 'lit';
import { LightElement } from '../lib/base.js';
import { t, I18nMixin } from '../lib/i18n.js';
export class LoginPage extends LightElement {
export class LoginPage extends I18nMixin(LightElement) {
static get properties() {
return {
@@ -27,7 +28,7 @@ export class LoginPage extends LightElement {
this._error = null;
if (!this._username.trim() || !this._password) {
this._error = 'Enter your username and password.';
this._error = t('login.missing');
return;
}
@@ -46,13 +47,13 @@ export class LoginPage extends LightElement {
}),
});
if (!res.ok) {
this._error = 'Invalid username or password.';
this._error = t('login.error');
return;
}
// Logged in — reload into the app.
window.location.reload();
} catch {
this._error = 'Network error — please try again.';
this._error = t('login.network');
} finally {
this._busy = false;
}
@@ -60,8 +61,8 @@ export class LoginPage extends LightElement {
render() {
const btnLabel = this._busy
? html`<span class="login-spinner"></span>Signing in…`
: 'Sign in';
? html`<span class="login-spinner"></span>${t('login.signing')}`
: t('login.submit');
return html`
<div class="login-page">
@@ -69,13 +70,13 @@ export class LoginPage extends LightElement {
<div class="login-logo">
<img src="/assets/icons/icon-192.png" alt="Skald" />
</div>
<h1 class="login-title">Welcome back</h1>
<p class="login-subtitle">Sign in to your account.</p>
<h1 class="login-title">${t('login.title')}</h1>
<p class="login-subtitle">${t('login.subtitle')}</p>
${this._error ? html`<div class="login-error">${this._error}</div>` : null}
<div class="mb-3">
<label class="form-label">Username</label>
<label class="form-label">${t('login.username')}</label>
<input
type="text"
class="form-control"
@@ -86,7 +87,7 @@ export class LoginPage extends LightElement {
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<label class="form-label">${t('login.password')}</label>
<input
type="password"
class="form-control"