Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dc9751a33 | ||
|
|
b81f8f67cc |
@@ -2030,7 +2030,12 @@ test('en passkey kan registreres og logges ind med', async ({ browser, browserNa
|
|||||||
// Now sign out and back in with it. No email typed: the device knows which
|
// Now sign out and back in with it. No email typed: the device knows which
|
||||||
// account its key belongs to, which is also why this page cannot be used to
|
// account its key belongs to, which is also why this page cannot be used to
|
||||||
// find out who has an account here.
|
// find out who has an account here.
|
||||||
await page.getByRole('navigation', { name: 'Hovedmenu' }).getByText('Log ud').click();
|
// Signing out asks first now: one click arms it, a second within a few seconds
|
||||||
|
// does it. The whole account row is the button; its label changes to the prompt.
|
||||||
|
const signOut = page.getByRole('navigation', { name: 'Hovedmenu' }).locator('.user');
|
||||||
|
await signOut.click();
|
||||||
|
await expect(signOut).toContainText('Tryk igen for at logge ud');
|
||||||
|
await signOut.click();
|
||||||
// `exact`, because "Log ind" is a substring of "Log ind med en passkey" and
|
// `exact`, because "Log ind" is a substring of "Log ind med en passkey" and
|
||||||
// Playwright matches an accessible name loosely unless told otherwise.
|
// Playwright matches an accessible name loosely unless told otherwise.
|
||||||
await expect(page.getByRole('button', { name: 'Log ind', exact: true })).toBeVisible();
|
await expect(page.getByRole('button', { name: 'Log ind', exact: true })).toBeVisible();
|
||||||
|
|||||||
+40
-2
@@ -210,6 +210,40 @@
|
|||||||
--shadow-lg: 0 8px 32px rgb(0 0 0 / 0.4);
|
--shadow-lg: 0 8px 32px rgb(0 0 0 / 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Kul — a neutral dark grey, the greys of Apple Notes rather than the default's
|
||||||
|
faint green cast. The same green accent, so it still reads as verdande; only the
|
||||||
|
grounds, surfaces and inks turn to plain grey. */
|
||||||
|
[data-theme='charcoal'] {
|
||||||
|
--ground: #1c1c1c;
|
||||||
|
--surface: #232323;
|
||||||
|
--surface-raised: #2b2b2b;
|
||||||
|
--surface-sunken: #171717;
|
||||||
|
--line: #363636;
|
||||||
|
--line-strong: #474747;
|
||||||
|
|
||||||
|
--ink: #ededed;
|
||||||
|
--ink-muted: #a4a4a4;
|
||||||
|
/* Light enough to clear 4.5:1 against the ground — the quiet tier of dates and
|
||||||
|
counts is the first to disappear if it is too dim. */
|
||||||
|
--ink-faint: #8e8e8e;
|
||||||
|
|
||||||
|
--accent: #5fbf8f;
|
||||||
|
--accent-hover: #6fcf9f;
|
||||||
|
--accent-sunken: #23332b80;
|
||||||
|
--accent-ink: #0d1411;
|
||||||
|
|
||||||
|
--p1: #cf6b6b;
|
||||||
|
--p2: #d69f5c;
|
||||||
|
--p3: #6b9ecf;
|
||||||
|
--p4: var(--ink-faint);
|
||||||
|
|
||||||
|
--danger: #cf6b6b;
|
||||||
|
--danger-sunken: #33201f;
|
||||||
|
|
||||||
|
--shadow: 0 1px 2px rgb(0 0 0 / 0.25);
|
||||||
|
--shadow-lg: 0 8px 32px rgb(0 0 0 / 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
/* Papir — warm light, closer to paper than to a screen. */
|
/* Papir — warm light, closer to paper than to a screen. */
|
||||||
[data-theme='paper'] {
|
[data-theme='paper'] {
|
||||||
--ground: #f6f1e7;
|
--ground: #f6f1e7;
|
||||||
@@ -375,9 +409,13 @@ button {
|
|||||||
søgefelt. */
|
søgefelt. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A translucent wash of the accent, not a solid block and not the old near-invisible
|
||||||
|
tint. --accent-sunken sat a hair off the editor's own surface in dark, so a
|
||||||
|
selection could not be seen; a solid accent could, but read as a heavy slab. Mixing
|
||||||
|
the accent part-way into transparent lays a clear green film over the text while it
|
||||||
|
keeps its own colour — visible on white and on the dark surfaces alike. */
|
||||||
::selection {
|
::selection {
|
||||||
background: var(--accent-sunken);
|
background: color-mix(in oklab, var(--accent) 42%, transparent);
|
||||||
color: var(--ink);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scrollbars, made quiet. The default on Windows is a wide grey slab that
|
/* Scrollbars, made quiet. The default on Windows is a wide grey slab that
|
||||||
|
|||||||
@@ -34,6 +34,23 @@
|
|||||||
location.href = '/';
|
location.href = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signing out is one click from a button the pointer passes over on its way to
|
||||||
|
// everything below it, and it drops you at the login screen — so it asks first.
|
||||||
|
// A second click within a few seconds confirms; anything else lets it lapse. Not
|
||||||
|
// a dialog: a two-step button is lighter and stays where the eye already is.
|
||||||
|
let confirmSignOut = $state(false);
|
||||||
|
let signOutTimer;
|
||||||
|
function onSignOutClick() {
|
||||||
|
if (confirmSignOut) {
|
||||||
|
clearTimeout(signOutTimer);
|
||||||
|
signOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
confirmSignOut = true;
|
||||||
|
clearTimeout(signOutTimer);
|
||||||
|
signOutTimer = setTimeout(() => (confirmSignOut = false), 3500);
|
||||||
|
}
|
||||||
|
|
||||||
let filters = $state([]);
|
let filters = $state([]);
|
||||||
let labels = $state([]);
|
let labels = $state([]);
|
||||||
|
|
||||||
@@ -1050,12 +1067,12 @@
|
|||||||
{#if !app.connected}
|
{#if !app.connected}
|
||||||
<span class="offline" title={t('nav.offlineHint')}>{t('nav.offline')}</span>
|
<span class="offline" title={t('nav.offlineHint')}>{t('nav.offline')}</span>
|
||||||
{/if}
|
{/if}
|
||||||
<button class="user" onclick={signOut}>
|
<button class="user" class:confirming={confirmSignOut} onclick={onSignOutClick}>
|
||||||
<span class="avatar" style="background: {app.user?.avatar_color}">
|
<span class="avatar" style="background: {app.user?.avatar_color}">
|
||||||
{app.user?.name?.[0]?.toUpperCase() ?? '?'}
|
{app.user?.name?.[0]?.toUpperCase() ?? '?'}
|
||||||
</span>
|
</span>
|
||||||
<span class="user-name">{app.user?.name}</span>
|
<span class="user-name">{confirmSignOut ? t('nav.signOutConfirm') : app.user?.name}</span>
|
||||||
<span class="signout">{t('nav.signOut')}</span>
|
<span class="signout">{confirmSignOut ? '' : t('nav.signOut')}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1091,14 +1108,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--s5);
|
gap: var(--s5);
|
||||||
padding: var(--s4) var(--s3);
|
/* A few pixels more air down each side than the rows strictly need, so the
|
||||||
|
menu breathes rather than sitting flush against its own edges. */
|
||||||
|
padding: var(--s4) calc(var(--s3) + 3px);
|
||||||
background: var(--surface-sunken);
|
background: var(--surface-sunken);
|
||||||
border-right: 1px solid var(--line);
|
border-right: 1px solid var(--line);
|
||||||
/* Selve bjælken ruller ikke længere — .scroller gør. `hidden` frem for
|
/* Selve bjælken ruller ikke længere — .scroller gør. `hidden` frem for
|
||||||
ingenting, fordi den stadig er den yderste kant: løber en række over,
|
ingenting, fordi den stadig er den yderste kant: løber en række over,
|
||||||
skal den klippes her og ikke skubbe kolonnen bredere. */
|
skal den klippes her og ikke skubbe kolonnen bredere. */
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-left: max(var(--s3), env(safe-area-inset-left));
|
padding-left: max(calc(var(--s3) + 3px), env(safe-area-inset-left));
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1695,6 +1714,16 @@
|
|||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Asking to confirm: the row goes to the danger tint and the name is replaced by
|
||||||
|
"click again", so the second click is plainly the one that signs out. */
|
||||||
|
.user.confirming {
|
||||||
|
background: var(--danger-sunken);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user.confirming .user-name {
|
||||||
|
color: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ export const da = {
|
|||||||
'nav.calendar': 'Kalender',
|
'nav.calendar': 'Kalender',
|
||||||
'nav.settings': 'Indstillinger',
|
'nav.settings': 'Indstillinger',
|
||||||
'nav.signOut': 'Log ud',
|
'nav.signOut': 'Log ud',
|
||||||
|
'nav.signOutConfirm': 'Tryk igen for at logge ud',
|
||||||
'nav.main': 'Hovedmenu',
|
'nav.main': 'Hovedmenu',
|
||||||
'nav.search': 'Søg',
|
'nav.search': 'Søg',
|
||||||
'nav.searchLong': 'Søg i opgaver og projekter',
|
'nav.searchLong': 'Søg i opgaver og projekter',
|
||||||
@@ -843,6 +844,8 @@ export const da = {
|
|||||||
// --- the themes -------------------------------------------------------------------
|
// --- the themes -------------------------------------------------------------------
|
||||||
'theme.dark': 'Nordlys',
|
'theme.dark': 'Nordlys',
|
||||||
'theme.darkNote': 'Mørk med grøn accent.',
|
'theme.darkNote': 'Mørk med grøn accent.',
|
||||||
|
'theme.charcoal': 'Kul',
|
||||||
|
'theme.charcoalNote': 'Neutral mørkegrå.',
|
||||||
'theme.dusk': 'Skumring',
|
'theme.dusk': 'Skumring',
|
||||||
'theme.duskNote': 'Mørk og varm, med rav.',
|
'theme.duskNote': 'Mørk og varm, med rav.',
|
||||||
'theme.light': 'Dagslys',
|
'theme.light': 'Dagslys',
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ export const en = {
|
|||||||
'nav.calendar': 'Calendar',
|
'nav.calendar': 'Calendar',
|
||||||
'nav.settings': 'Settings',
|
'nav.settings': 'Settings',
|
||||||
'nav.signOut': 'Sign out',
|
'nav.signOut': 'Sign out',
|
||||||
|
'nav.signOutConfirm': 'Click again to sign out',
|
||||||
'nav.main': 'Main menu',
|
'nav.main': 'Main menu',
|
||||||
'nav.search': 'Search',
|
'nav.search': 'Search',
|
||||||
'nav.searchLong': 'Search tasks and projects',
|
'nav.searchLong': 'Search tasks and projects',
|
||||||
@@ -836,6 +837,8 @@ export const en = {
|
|||||||
// --- the themes -------------------------------------------------------------------
|
// --- the themes -------------------------------------------------------------------
|
||||||
'theme.dark': 'Northern lights',
|
'theme.dark': 'Northern lights',
|
||||||
'theme.darkNote': 'Dark, with a green accent.',
|
'theme.darkNote': 'Dark, with a green accent.',
|
||||||
|
'theme.charcoal': 'Charcoal',
|
||||||
|
'theme.charcoalNote': 'Neutral dark grey.',
|
||||||
'theme.dusk': 'Dusk',
|
'theme.dusk': 'Dusk',
|
||||||
'theme.duskNote': 'Dark and warm, with amber.',
|
'theme.duskNote': 'Dark and warm, with amber.',
|
||||||
'theme.light': 'Daylight',
|
'theme.light': 'Daylight',
|
||||||
|
|||||||
@@ -1006,6 +1006,7 @@ export const completedView = new CompletedView();
|
|||||||
*/
|
*/
|
||||||
export const THEMES = [
|
export const THEMES = [
|
||||||
{ id: 'dark', name: 'theme.dark', note: 'theme.darkNote', dark: true },
|
{ id: 'dark', name: 'theme.dark', note: 'theme.darkNote', dark: true },
|
||||||
|
{ id: 'charcoal', name: 'theme.charcoal', note: 'theme.charcoalNote', dark: true },
|
||||||
{ id: 'dusk', name: 'theme.dusk', note: 'theme.duskNote', dark: true },
|
{ id: 'dusk', name: 'theme.dusk', note: 'theme.duskNote', dark: true },
|
||||||
{ id: 'light', name: 'theme.light', note: 'theme.lightNote', dark: false },
|
{ id: 'light', name: 'theme.light', note: 'theme.lightNote', dark: false },
|
||||||
{ id: 'paper', name: 'theme.paper', note: 'theme.paperNote', dark: false },
|
{ id: 'paper', name: 'theme.paper', note: 'theme.paperNote', dark: false },
|
||||||
|
|||||||
@@ -1068,8 +1068,9 @@
|
|||||||
against the sidebar's rule, which reads as a rendering fault rather than
|
against the sidebar's rule, which reads as a rendering fault rather than
|
||||||
as a layout. */
|
as a layout. */
|
||||||
/* Luft hele vejen rundt om arket. Højre og bund var nul, dengang editoren
|
/* Luft hele vejen rundt om arket. Højre og bund var nul, dengang editoren
|
||||||
ingen kant havde og ingenting kunne støde imod. */
|
ingen kant havde og ingenting kunne støde imod. Et par pixels mere om
|
||||||
padding: var(--s3) var(--s4) var(--s3) var(--s4);
|
notelisten, så kortet ikke ligger klods op ad menuen. */
|
||||||
|
padding: var(--s3) var(--s4) var(--s3) calc(var(--s4) + 3px);
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(220px, 300px) 1fr;
|
grid-template-columns: minmax(220px, 300px) 1fr;
|
||||||
gap: var(--s4);
|
gap: var(--s4);
|
||||||
@@ -1083,13 +1084,15 @@
|
|||||||
gap: var(--s2);
|
gap: var(--s2);
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border-right: 1px solid var(--line);
|
/* A rounded card, the same corner and border as the editor beside it — the
|
||||||
padding-right: var(--s3);
|
list is its own sheet, not a column ruled off the page. */
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius);
|
||||||
/* White in light, a nuance lighter than the ground in dark — the note list
|
/* White in light, a nuance lighter than the ground in dark — the note list
|
||||||
is a surface you read down, so it lifts off the page like the editor does.
|
is a surface you read down, so it lifts off the page like the editor does.
|
||||||
--surface-raised is #fff in the light themes and one step up in the dark. */
|
--surface-raised is #fff in the light themes and one step up in the dark. */
|
||||||
background: var(--surface-raised);
|
background: var(--surface-raised);
|
||||||
padding-left: var(--s3);
|
padding: var(--s3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.head {
|
.head {
|
||||||
|
|||||||
Reference in New Issue
Block a user