Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05b7dac713 | ||
|
|
cfd382e3df | ||
|
|
bbcff40401 | ||
|
|
01001d0980 | ||
|
|
4ac7180cda | ||
|
|
e1683ef09d | ||
|
|
f89fb21502 | ||
|
|
ec147cd1ba | ||
|
|
1f9f14099b | ||
|
|
6cf63113df | ||
|
|
e24a0fa849 | ||
|
|
1c223a2c26 | ||
|
|
a9c90ee6f1 | ||
|
|
dc4a584d5f |
|
Before Width: | Height: | Size: 246 KiB After Width: | Height: | Size: 248 KiB |
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 308 KiB |
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 228 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 331 KiB After Width: | Height: | Size: 333 KiB |
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 245 KiB |
|
Before Width: | Height: | Size: 263 KiB After Width: | Height: | Size: 282 KiB |
|
Before Width: | Height: | Size: 350 KiB After Width: | Height: | Size: 370 KiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 356 KiB |
|
Before Width: | Height: | Size: 227 KiB After Width: | Height: | Size: 229 KiB |
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 253 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 238 KiB |
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 227 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
@@ -371,9 +371,9 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
|
|||||||
await sidebar.getByLabel('Gruppens navn').fill('Arbejde');
|
await sidebar.getByLabel('Gruppens navn').fill('Arbejde');
|
||||||
await sidebar.getByLabel('Gruppens navn').press('Enter');
|
await sidebar.getByLabel('Gruppens navn').press('Enter');
|
||||||
|
|
||||||
// The name is a link to the group's own page; the chevron beside it is a
|
// The name is a link to the group's own page; the folder icon beside it is a
|
||||||
// separate button that folds. Two intentions, two targets — the single one they
|
// separate button that folds. Two intentions, two targets — the single one they
|
||||||
// used to share could only ever serve the smaller.
|
// used to share could only ever serve the smaller, and neither wears an arrow.
|
||||||
//
|
//
|
||||||
// `exact` on the link, because a group's name is a user-chosen word that can
|
// `exact` on the link, because a group's name is a user-chosen word that can
|
||||||
// turn up inside another control's name, and Playwright matches an accessible
|
// turn up inside another control's name, and Playwright matches an accessible
|
||||||
@@ -383,19 +383,20 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
|
|||||||
await expect(heading).toBeVisible();
|
await expect(heading).toBeVisible();
|
||||||
await expect(sidebar.getByText('Træk et projekt herop')).toBeVisible();
|
await expect(sidebar.getByText('Træk et projekt herop')).toBeVisible();
|
||||||
|
|
||||||
// A group's name must be readable in full, and must start where a project's
|
// A group's name must be readable in full, and must line up with the other
|
||||||
// name starts.
|
// headings — not with the projects filed under it.
|
||||||
//
|
//
|
||||||
// Both halves are here because both were once broken at the same time and for
|
// The clipping half is here because it was once broken: "Omdøb" and "Slet" sat
|
||||||
// different reasons. "Omdøb" and "Slet" sat in the flow reserving their width
|
// in the flow reserving their width even while invisible, so ARBEJDE was drawn
|
||||||
// even while invisible, so ARBEJDE was drawn as "ARBE"; and the fold chevron
|
// as "ARBE". The alignment half changed meaning with the redesign: a group now
|
||||||
// sat before the name, pushing a group 22px further in than the projects it
|
// carries a section icon just like "Projekter" above it, and belongs to that
|
||||||
// contains — so a group read as if it were filed under them. Every assertion
|
// heading tier rather than to the project rows below.
|
||||||
// in this file passed through both, because both buttons still worked.
|
|
||||||
const shape = await sidebar.locator('.folder-head').evaluate((el) => {
|
const shape = await sidebar.locator('.folder-head').evaluate((el) => {
|
||||||
const link = el.querySelector('h2 a');
|
const link = el.querySelector('h2 a');
|
||||||
const name = { ...link.querySelector('.dot').getBoundingClientRect().toJSON() };
|
// The leading mark is the section icon in its own fold button, the same
|
||||||
// The last child of the link is the name itself; the dot is a span before it.
|
// folder/funnel/tag glyph the system headings carry — a group and a section
|
||||||
|
// read identically, and the icon sits before the name, not inside the link.
|
||||||
|
const name = { ...el.querySelector('.head-icon').getBoundingClientRect().toJSON() };
|
||||||
return {
|
return {
|
||||||
clipped: link.scrollWidth > link.clientWidth + 1,
|
clipped: link.scrollWidth > link.clientWidth + 1,
|
||||||
left: name.left,
|
left: name.left,
|
||||||
@@ -407,17 +408,17 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
|
|||||||
expect(shape.clipped, 'gruppens navn bliver klippet').toBe(false);
|
expect(shape.clipped, 'gruppens navn bliver klippet').toBe(false);
|
||||||
expect(shape.count, 'navnet og tallet overlapper').toBeGreaterThanOrEqual(shape.right);
|
expect(shape.count, 'navnet og tallet overlapper').toBeGreaterThanOrEqual(shape.right);
|
||||||
|
|
||||||
// Measured dot to dot, not box to box: both rows begin with the same coloured
|
// A group is a heading, not a project row: it belongs to the same tier as
|
||||||
// mark, and it is the only thing in them that means the same on both sides.
|
// "Projekter" and the other system sections — icon, bold name, no arrow — and
|
||||||
// Comparing the group's inner link with the project's outer box reported the
|
// starts where they start, not where the projects filed under it do. Measured
|
||||||
// row's own padding as a misalignment.
|
// icon to icon, the one mark both headings share.
|
||||||
const projectLeft = await sidebar
|
const sectionLeft = await sidebar
|
||||||
.getByRole('link', { name: 'Regnskab' })
|
.getByRole('heading', { name: 'Projekter' })
|
||||||
.evaluate((el) => el.querySelector('.dot').getBoundingClientRect().left);
|
.evaluate((el) => el.querySelector('.head-icon').getBoundingClientRect().left);
|
||||||
expect(
|
expect(
|
||||||
Math.abs(shape.left - projectLeft),
|
Math.abs(shape.left - sectionLeft),
|
||||||
`gruppen starter ${Math.round(shape.left - projectLeft)}px fra projekterne`
|
`gruppen starter ${Math.round(shape.left - sectionLeft)}px fra sektionsoverskrifterne`
|
||||||
).toBeLessThanOrEqual(2);
|
).toBeLessThanOrEqual(4);
|
||||||
|
|
||||||
// Dragged in, then dragged back out onto "Projekter" — which is the reason
|
// Dragged in, then dragged back out onto "Projekter" — which is the reason
|
||||||
// that heading is a drop target at all: with every project filed away there
|
// that heading is a drop target at all: with every project filed away there
|
||||||
@@ -440,18 +441,13 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
|
|||||||
'false'
|
'false'
|
||||||
);
|
);
|
||||||
|
|
||||||
// En foldet gruppe står med sin chevron fremme permanent, og den lå oven i
|
// The fold control is the bare folder icon now — no chevron, and no --surface
|
||||||
// prikken med et felt i --surface bag sig — en lys firkant ud for navnet på
|
// field behind it, so a folded group leaves no pale square beside its name on
|
||||||
// den sænkede bjælke, hele tiden. Nu tones prikken ud i stedet, så der er
|
// the sunken bar.
|
||||||
// ingenting at male henover den med.
|
const foldBg = await sidebar
|
||||||
const chevron = await sidebar
|
.locator('.folder-head .fold-icon')
|
||||||
.locator('.folder-head .chevron-button')
|
.evaluate((el) => getComputedStyle(el).backgroundColor);
|
||||||
.evaluate((el) => ({
|
expect(foldBg, 'foldeknappen har en firkant bag sig').toBe('rgba(0, 0, 0, 0)');
|
||||||
background: getComputedStyle(el).backgroundColor,
|
|
||||||
dot: getComputedStyle(el.closest('.folder-head').querySelector('.group-dot')).opacity
|
|
||||||
}));
|
|
||||||
expect(chevron.background, 'chevronen har en firkant bag sig').toBe('rgba(0, 0, 0, 0)');
|
|
||||||
expect(chevron.dot, 'prikken ligger stadig under chevronen').toBe('0');
|
|
||||||
|
|
||||||
await sidebar.getByRole('button', { name: /^Fold Arbejde/ }).click();
|
await sidebar.getByRole('button', { name: /^Fold Arbejde/ }).click();
|
||||||
|
|
||||||
@@ -467,11 +463,7 @@ test('en projektgruppe kan foldes, fyldes og slettes uden at tage projekterne me
|
|||||||
// button on click.
|
// button on click.
|
||||||
await expect(sidebar.getByLabel('Gruppens navn')).toBeVisible();
|
await expect(sidebar.getByLabel('Gruppens navn')).toBeVisible();
|
||||||
await sidebar.getByLabel('Gruppens navn').press('Enter');
|
await sidebar.getByLabel('Gruppens navn').press('Enter');
|
||||||
|
await expect(sidebar.getByRole('link', { name: 'Arbejde', exact: true })).toBeVisible();
|
||||||
const painted = await sidebar
|
|
||||||
.locator('.folder-head .group-dot')
|
|
||||||
.evaluate((el) => getComputedStyle(el).backgroundColor);
|
|
||||||
expect(painted, 'gruppens prik fik ikke sin farve').not.toBe('rgba(0, 0, 0, 0)');
|
|
||||||
|
|
||||||
// The heading itself is *not* indented — only what is filed under it. A heading
|
// The heading itself is *not* indented — only what is filed under it. A heading
|
||||||
// that starts further in than the rows above it says the heading is inside
|
// that starts further in than the rows above it says the heading is inside
|
||||||
|
|||||||
@@ -651,6 +651,7 @@
|
|||||||
<div
|
<div
|
||||||
class="allday"
|
class="allday"
|
||||||
data-allday={iso(date)}
|
data-allday={iso(date)}
|
||||||
|
class:today={iso(date) === todayISO}
|
||||||
class:over={over === iso(date)}
|
class:over={over === iso(date)}
|
||||||
ondragover={(e) => onDragOver(e, date)}
|
ondragover={(e) => onDragOver(e, date)}
|
||||||
ondragleave={() => (over = null)}
|
ondragleave={() => (over = null)}
|
||||||
@@ -876,12 +877,16 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* White, not the sidebar's sunken ground: a calendar reads lightest when the
|
||||||
|
day itself is the brightest thing on the screen and the events are the soft
|
||||||
|
colour laid on it — the opposite of the grey grid it was, where the events
|
||||||
|
had to shout to be seen at all. */
|
||||||
.corner,
|
.corner,
|
||||||
.head,
|
.head,
|
||||||
.gutter,
|
.gutter,
|
||||||
.allday,
|
.allday,
|
||||||
.daycol {
|
.daycol {
|
||||||
background: var(--ground);
|
background: var(--surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
.head {
|
.head {
|
||||||
@@ -889,6 +894,16 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Today's whole column, faintly, so the eye finds it before it reads a number —
|
||||||
|
the marker on the date above is the label, this is the glow it sits in. Kept
|
||||||
|
under the events, so a pastel block still reads as its own calendar's colour
|
||||||
|
rather than as this wash tinted. */
|
||||||
|
.head.today,
|
||||||
|
.allday.today,
|
||||||
|
.daycol.today {
|
||||||
|
background: color-mix(in oklab, var(--accent) 6%, var(--surface));
|
||||||
|
}
|
||||||
|
|
||||||
.head .wd {
|
.head .wd {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: var(--text-xs);
|
font-size: var(--text-xs);
|
||||||
@@ -901,9 +916,19 @@
|
|||||||
font-size: var(--text-sm);
|
font-size: var(--text-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The marker at the top the day is named by: today's number in a filled disc,
|
||||||
|
the same one the month grid gives today, so "this is today" is one glance in
|
||||||
|
either view rather than a colour you have to already know to read. */
|
||||||
.head.today .num {
|
.head.today .num {
|
||||||
color: var(--accent);
|
color: var(--accent-ink);
|
||||||
|
background: var(--accent);
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: inline-grid;
|
||||||
|
place-items: center;
|
||||||
font-weight: 560;
|
font-weight: 560;
|
||||||
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gutter {
|
.gutter {
|
||||||
@@ -977,6 +1002,10 @@
|
|||||||
/* Placeringen kommer fra `place()` som en inline `style`; alt andet står her.
|
/* Placeringen kommer fra `place()` som en inline `style`; alt andet står her.
|
||||||
To ting på samme tid deler bredden, så `margin-right` er den ene hårstrå
|
To ting på samme tid deler bredden, så `margin-right` er den ene hårstrå
|
||||||
luft, der gør to kasser til to kasser. */
|
luft, der gør to kasser til to kasser. */
|
||||||
|
/* A soft wash of the calendar's own colour rather than a grey block edged in it:
|
||||||
|
each calendar keeps a dusty, unmistakable nuance, and a screen of them reads
|
||||||
|
as colour laid on white instead of a grid of grey bars. The left edge stays,
|
||||||
|
a shade stronger than the fill, so the block still has a spine. */
|
||||||
.tevent {
|
.tevent {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
@@ -984,16 +1013,20 @@
|
|||||||
padding: 1px var(--s1);
|
padding: 1px var(--s1);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
border-left: 3px solid var(--event-colour, var(--line-strong));
|
border-left: 3px solid var(--event-colour, var(--line-strong));
|
||||||
background: var(--surface-sunken);
|
background: color-mix(in oklab, var(--event-colour, var(--line-strong)) 16%, var(--surface));
|
||||||
color: var(--ink-muted);
|
color: var(--ink);
|
||||||
font-size: var(--text-xs);
|
font-size: var(--text-xs);
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A task is a card you can pick up, not an event you cannot — so on the white
|
||||||
|
column it is an outlined card, where an event is a solid wash. The priority
|
||||||
|
colour rides the left edge, as it does everywhere else. */
|
||||||
.tevent.task {
|
.tevent.task {
|
||||||
background: var(--surface-raised);
|
background: var(--surface);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--line);
|
||||||
border-left-color: var(--line-strong);
|
border-left-color: var(--line-strong);
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
@@ -1101,7 +1134,8 @@
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 1px var(--s1);
|
padding: 1px var(--s1);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
background: var(--surface-raised);
|
background: var(--surface);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--line);
|
||||||
border-left: 2px solid var(--line-strong);
|
border-left: 2px solid var(--line-strong);
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -1120,7 +1154,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chip:hover {
|
.chip:hover {
|
||||||
background: var(--surface);
|
background: var(--surface-sunken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* An event reads as a different kind of thing at a glance, before any of the
|
/* An event reads as a different kind of thing at a glance, before any of the
|
||||||
@@ -1140,8 +1174,8 @@
|
|||||||
padding: 1px var(--s1);
|
padding: 1px var(--s1);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
border-left: 3px solid var(--event-colour);
|
border-left: 3px solid var(--event-colour);
|
||||||
background: var(--surface-sunken);
|
background: color-mix(in oklab, var(--event-colour) 16%, var(--surface));
|
||||||
color: var(--ink-muted);
|
color: var(--ink);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -1156,7 +1190,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.event:hover {
|
.event:hover {
|
||||||
background: var(--surface);
|
background: color-mix(in oklab, var(--event-colour) 26%, var(--surface));
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1165,7 +1199,7 @@
|
|||||||
every calendar anybody has used. */
|
every calendar anybody has used. */
|
||||||
.event.allday {
|
.event.allday {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
background: color-mix(in oklab, var(--event-colour) 22%, var(--ground));
|
background: color-mix(in oklab, var(--event-colour) 22%, var(--surface));
|
||||||
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--event-colour) 45%, transparent);
|
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--event-colour) 45%, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1267,20 +1301,18 @@
|
|||||||
padding: 1px var(--s1);
|
padding: 1px var(--s1);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
border-left: 2px solid var(--line-strong);
|
border-left: 2px solid var(--line-strong);
|
||||||
background: var(--surface-raised);
|
background: var(--surface);
|
||||||
|
box-shadow: inset 0 0 0 1px var(--line);
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar.week .chip[data-priority='1'] {
|
.calendar.week .chip[data-priority='1'] {
|
||||||
border-left-color: var(--p1);
|
border-left-color: var(--p1);
|
||||||
background: var(--surface-raised);
|
|
||||||
}
|
}
|
||||||
.calendar.week .chip[data-priority='2'] {
|
.calendar.week .chip[data-priority='2'] {
|
||||||
border-left-color: var(--p2);
|
border-left-color: var(--p2);
|
||||||
background: var(--surface-raised);
|
|
||||||
}
|
}
|
||||||
.calendar.week .chip[data-priority='3'] {
|
.calendar.week .chip[data-priority='3'] {
|
||||||
border-left-color: var(--p3);
|
border-left-color: var(--p3);
|
||||||
background: var(--surface-raised);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Readable again in the week, for the reason the task chips are: a
|
/* Readable again in the week, for the reason the task chips are: a
|
||||||
@@ -1292,12 +1324,12 @@
|
|||||||
padding: 1px var(--s1);
|
padding: 1px var(--s1);
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
border-left: 3px solid var(--event-colour);
|
border-left: 3px solid var(--event-colour);
|
||||||
background: var(--surface-sunken);
|
background: color-mix(in oklab, var(--event-colour) 16%, var(--surface));
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar.week .event.allday {
|
.calendar.week .event.allday {
|
||||||
border-left: none;
|
border-left: none;
|
||||||
background: color-mix(in oklab, var(--event-colour) 22%, var(--ground));
|
background: color-mix(in oklab, var(--event-colour) 22%, var(--surface));
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar.week .at {
|
.calendar.week .at {
|
||||||
|
|||||||
@@ -682,28 +682,84 @@
|
|||||||
<!--
|
<!--
|
||||||
A fixed heading that folds, the same way a project group's does.
|
A fixed heading that folds, the same way a project group's does.
|
||||||
|
|
||||||
One snippet for all four rather than four copies of a chevron and an aria
|
One snippet for all four rather than four copies of an icon and an aria
|
||||||
attribute: they have to behave identically, and the group heading is already
|
attribute: they have to behave identically, and the group heading is already
|
||||||
the proof that they drift otherwise — it grew a fold, a colour and two
|
the proof that they drift otherwise — it grew a fold, a colour and two
|
||||||
actions while these stayed plain text.
|
actions while these stayed plain text.
|
||||||
|
|
||||||
The whole heading is the target, not the chevron. At this size a lone chevron
|
The whole heading is the target, and the icon is the mark: no arrow beside it.
|
||||||
is something you miss, and the name is where the eye already is.
|
At this size an extra glyph is clutter, and the name is where the eye already
|
||||||
|
is.
|
||||||
-->
|
-->
|
||||||
|
<!-- One monochrome mark per kind of heading, so a section and a group read as the
|
||||||
|
same kind of thing — a folder of projects, a funnel of filters, a tag of
|
||||||
|
labels — instead of one being a faint label and the other a coloured dot. -->
|
||||||
|
{#snippet sectionIcon(key)}
|
||||||
|
{#if key === 'filters'}
|
||||||
|
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
|
<path
|
||||||
|
d="M2.2 3.4h11.6L9.3 8.8v3.4L6.7 10.9V8.8z"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.4"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{:else if key === 'labels'}
|
||||||
|
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
|
<path
|
||||||
|
d="M7.7 2.3H13v5.3l-5.3 5.3-5.3-5.3z"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.4"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
<circle cx="10.2" cy="4.9" r="0.95" fill="currentColor" />
|
||||||
|
</svg>
|
||||||
|
{:else if key === 'shared'}
|
||||||
|
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
|
<circle cx="6.2" cy="5.6" r="2.1" fill="none" stroke="currentColor" stroke-width="1.4" />
|
||||||
|
<path
|
||||||
|
d="M2.6 12.8c0-2.1 1.7-3.3 3.6-3.3s3.6 1.2 3.6 3.3"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.4"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M11 9.6c1.5.2 2.6 1.3 2.6 3.2"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.4"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
<circle cx="11.2" cy="5.6" r="1.7" fill="none" stroke="currentColor" stroke-width="1.4" />
|
||||||
|
</svg>
|
||||||
|
{:else}
|
||||||
|
<!-- Projekter and every group: a folder of projects. -->
|
||||||
|
<svg class="head-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
|
<path
|
||||||
|
d="M2 4.6a1 1 0 011-1h3.1l1.4 1.5H13a1 1 0 011 1v6.3a1 1 0 01-1 1H3a1 1 0 01-1-1z"
|
||||||
|
fill="none"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="1.4"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
|
||||||
{#snippet foldHeading(key, label)}
|
{#snippet foldHeading(key, label)}
|
||||||
|
<!-- No chevron: a system section has no page and nothing to rename, so the
|
||||||
|
whole heading is one button that folds it. The icon and the bold name are
|
||||||
|
the whole control — an arrow beside them was only ever saying "clickable"
|
||||||
|
twice. -->
|
||||||
<h2 class="fold">
|
<h2 class="fold">
|
||||||
<button
|
<button
|
||||||
onclick={() => app.toggleSection(key)}
|
onclick={() => app.toggleSection(key)}
|
||||||
aria-expanded={!app.sectionCollapsed(key)}
|
aria-expanded={!app.sectionCollapsed(key)}
|
||||||
>
|
>
|
||||||
<svg
|
{@render sectionIcon(key)}
|
||||||
class="chevron"
|
|
||||||
class:collapsed={app.sectionCollapsed(key)}
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M6 9l6 6 6-6" />
|
|
||||||
</svg>
|
|
||||||
{label}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
</h2>
|
</h2>
|
||||||
@@ -871,31 +927,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- The button sits inside the heading, not around it, the same way a
|
<!-- No chevron: the folder icon itself folds the group, and the name
|
||||||
project's title does: a group *is* a heading in the sidebar, and
|
beside it opens the group's own page. Two intentions, two targets,
|
||||||
wrapping an h2 in a button both invalidates the markup and takes
|
but no arrow to clutter the rail — the icon a section carries is
|
||||||
the heading away from a screen reader. The whole heading folds —
|
the same one that folds it here. The button sits inside the
|
||||||
at this size a lone chevron is a target you miss, and the name is
|
heading, not around it: a group *is* a heading, and wrapping an h2
|
||||||
where the eye already is. -->
|
in a button both invalidates the markup and takes the heading from
|
||||||
<!-- The chevron folds; the name opens the group's own page. Two
|
a screen reader. -->
|
||||||
targets in one heading, because they are two different intentions
|
|
||||||
and the old single one could only ever serve the smaller. -->
|
|
||||||
<button
|
<button
|
||||||
class="chevron-button"
|
class="fold-icon"
|
||||||
onclick={() => app.toggleGroup(group.id)}
|
onclick={() => app.toggleGroup(group.id)}
|
||||||
aria-expanded={!group.collapsed}
|
aria-expanded={!group.collapsed}
|
||||||
aria-label={group.collapsed
|
aria-label={group.collapsed
|
||||||
? t('sidebar.unfold', { name: group.name })
|
? t('sidebar.unfold', { name: group.name })
|
||||||
: t('sidebar.fold', { name: group.name })}
|
: t('sidebar.fold', { name: group.name })}
|
||||||
>
|
>
|
||||||
<svg
|
{@render sectionIcon('group')}
|
||||||
class="chevron"
|
|
||||||
class:collapsed={group.collapsed}
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
aria-hidden="true"
|
|
||||||
>
|
|
||||||
<path d="M6 9l6 6 6-6" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
<h2 class="fold">
|
<h2 class="fold">
|
||||||
<!-- Navigation waits two tenths of a second for a second click. A
|
<!-- Navigation waits two tenths of a second for a second click. A
|
||||||
@@ -916,11 +963,6 @@
|
|||||||
}, 200);
|
}, 200);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
|
||||||
class="dot group-dot"
|
|
||||||
style="background: {colorVar(group.color)}"
|
|
||||||
aria-hidden="true"
|
|
||||||
></span>
|
|
||||||
{group.name}
|
{group.name}
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
@@ -1087,14 +1129,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.scroller::-webkit-scrollbar {
|
.scroller::-webkit-scrollbar {
|
||||||
width: 10px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* No transparent border and no padding-box clip: those centred a 4px bar in a
|
||||||
|
10px track, so the thumb floated three pixels shy of the divider. The bar is
|
||||||
|
the track now — a thin rounded thumb sitting flush against the line on the
|
||||||
|
right, which is where a scrollbar belongs. */
|
||||||
.scroller::-webkit-scrollbar-thumb {
|
.scroller::-webkit-scrollbar-thumb {
|
||||||
background: var(--line-strong);
|
background: var(--line-strong);
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
border: 3px solid transparent;
|
|
||||||
background-clip: padding-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.scroller::-webkit-scrollbar-track {
|
.scroller::-webkit-scrollbar-track {
|
||||||
@@ -1267,12 +1311,22 @@
|
|||||||
background: var(--surface-sunken);
|
background: var(--surface-sunken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Every heading — the system sections and the user's groups — reads the same:
|
||||||
|
a mark, then a bold plainly-cased name. What used to set them apart (one a
|
||||||
|
faint uppercase label, the other a bold name with a coloured dot) is gone. */
|
||||||
h2 {
|
h2 {
|
||||||
font-size: var(--text-xs);
|
font-size: var(--menu-size);
|
||||||
font-weight: 560;
|
font-weight: 600;
|
||||||
text-transform: uppercase;
|
color: var(--ink);
|
||||||
letter-spacing: 0.06em;
|
}
|
||||||
color: var(--ink-faint);
|
|
||||||
|
/* The heading's mark, in the muted ink so the bold name still leads. Sized and
|
||||||
|
nudged like a row's own mark, so the icons line up down the sidebar. */
|
||||||
|
.head-icon {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
flex: none;
|
||||||
|
color: var(--ink-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only the square icon buttons — "+" and the folder — and asked for by class
|
/* Only the square icon buttons — "+" and the folder — and asked for by class
|
||||||
@@ -1358,57 +1412,17 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The chevron on its own, so the name beside it can be a link to the group's
|
/* The folder icon is the fold toggle now — no chevron beside it. A bare icon
|
||||||
page. Sized as a target rather than as a glyph: 11px of arrow is something
|
button the size of the icon it holds: the name next to it opens the group's
|
||||||
you miss. */
|
page, this folds it, and neither wears an arrow to say so. */
|
||||||
/* The chevron sits on top of the group's dot rather than before it. In the flow
|
.fold-icon {
|
||||||
it pushed the name 22px further in than a project's, so groups read as if
|
flex: none;
|
||||||
they were filed under the projects above them — the opposite of what they
|
|
||||||
are. Out of the flow, a group's name starts exactly where a project's does.
|
|
||||||
The dot is the resting state; the chevron takes over on hover or focus, and
|
|
||||||
stays put while the group is folded, so a folded group still shows the way
|
|
||||||
back open. */
|
|
||||||
/* Uden baggrund. Knappen dækkede prikken med et felt i --surface, og på den
|
|
||||||
sænkede bjælke er det en lys firkant: en foldet gruppe stod med en hvid
|
|
||||||
klods ud for navnet permanent, fordi chevronen bliver stående, når gruppen
|
|
||||||
er lukket. Prikken tones ud i stedet for at blive dækket — det er samme
|
|
||||||
skifte, uden noget at male henover den med. */
|
|
||||||
.chevron-button {
|
|
||||||
position: absolute;
|
|
||||||
left: calc(var(--s2) - 5px);
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
border-radius: var(--radius-sm);
|
|
||||||
color: inherit;
|
color: inherit;
|
||||||
opacity: 0;
|
|
||||||
/* Fordi prikken herunder tones ud frem for at blive dækket. En `opacity`
|
|
||||||
under 1 laver en stakkontekst og maler elementet, som var det placeret
|
|
||||||
med `z-index: 0` — så prikken, der står senere i DOM'en, lagde sig oven
|
|
||||||
på knappen i det øjeblik den forsvandt. Den var usynlig og tog stadig
|
|
||||||
klikket: prøven brugte tredive sekunder på at folde en gruppe, der ikke
|
|
||||||
ville foldes. Ét lag op, og rækkefølgen er den samme som før. */
|
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.folder-head:hover .chevron-button,
|
.fold-icon:hover {
|
||||||
.chevron-button:focus-visible,
|
|
||||||
.chevron-button[aria-expanded='false'] {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Præcis de tre tilfælde ovenfor, læst nedad i stedet for opad: står chevronen
|
|
||||||
der, er prikken væk. `opacity` og ikke `display`, for de to ligger oven i
|
|
||||||
hinanden — forsvandt prikken ud af flowet, ville navnet rykke sig hver gang
|
|
||||||
pilen kom frem. */
|
|
||||||
.folder-head:hover .group-dot,
|
|
||||||
.folder-head:has(.chevron-button:focus-visible) .group-dot,
|
|
||||||
.folder-head:has(.chevron-button[aria-expanded='false']) .group-dot {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chevron-button:hover {
|
|
||||||
color: var(--ink);
|
color: var(--ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1437,22 +1451,6 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chevron {
|
|
||||||
width: 11px;
|
|
||||||
height: 11px;
|
|
||||||
flex: none;
|
|
||||||
fill: none;
|
|
||||||
stroke: currentColor;
|
|
||||||
stroke-width: 2.4;
|
|
||||||
stroke-linecap: round;
|
|
||||||
stroke-linejoin: round;
|
|
||||||
transition: transform var(--fast) var(--ease);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chevron.collapsed {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hidden until the heading is hovered, like the section actions on a project
|
/* Hidden until the heading is hovered, like the section actions on a project
|
||||||
page: two buttons permanently beside a label stop it reading as a label. */
|
page: two buttons permanently beside a label stop it reading as a label. */
|
||||||
.folder-head .count {
|
.folder-head .count {
|
||||||
@@ -1485,14 +1483,6 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The group's own mark, between the chevron and the name — inside the fold
|
|
||||||
button, so it cannot push the heading in. It is a mark now and not a
|
|
||||||
control: the colour is chosen while renaming, which is the other edit to
|
|
||||||
the same thing. */
|
|
||||||
.group-dot {
|
|
||||||
flex: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Projects sit at the same left margin whether or not they are in an area —
|
/* Projects sit at the same left margin whether or not they are in an area —
|
||||||
one straight edge down the whole sidebar reads calmer than a staircase, and
|
one straight edge down the whole sidebar reads calmer than a staircase, and
|
||||||
the bold area heading above already does the grouping the indent used to. */
|
the bold area heading above already does the grouping the indent used to. */
|
||||||
@@ -1508,18 +1498,6 @@
|
|||||||
padding-left: var(--s2);
|
padding-left: var(--s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* An area is the sidebar's own heading — Things treats it as bold and plainly
|
|
||||||
cased, a thing the eye lands on, not another faint uppercase label like the
|
|
||||||
system sections. So an area's name is set apart while "Projekter", "Filtre"
|
|
||||||
and "Etiketter" stay quiet. */
|
|
||||||
.folder-head h2 {
|
|
||||||
font-size: var(--menu-size);
|
|
||||||
font-weight: 600;
|
|
||||||
text-transform: none;
|
|
||||||
letter-spacing: 0;
|
|
||||||
color: var(--ink);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inside the rename form now, so it needs no padding of its own — the form
|
/* Inside the rename form now, so it needs no padding of its own — the form
|
||||||
already sits where the heading did. */
|
already sits where the heading did. */
|
||||||
.renaming {
|
.renaming {
|
||||||
|
|||||||
@@ -285,7 +285,7 @@
|
|||||||
<p class="hint">{t('data.doneHint')}</p>
|
<p class="hint">{t('data.doneHint')}</p>
|
||||||
</header>
|
</header>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<a class="ghost" href="/faerdige">{t('data.openDone')}</a>
|
<a class="link" href="/faerdige">{t('data.openDone')}</a>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,10 @@
|
|||||||
if (days === 1) return { key: 'i-gaar', label: t('notes.groupYesterday') };
|
if (days === 1) return { key: 'i-gaar', label: t('notes.groupYesterday') };
|
||||||
if (days < 7) return { key: 'ugen', label: t('notes.groupWeek') };
|
if (days < 7) return { key: 'ugen', label: t('notes.groupWeek') };
|
||||||
|
|
||||||
const label = at.toLocaleDateString(tag(), { month: 'long', year: 'numeric' });
|
// Stort forbogstav på måneden: Intl giver "august 2026" på dansk, og en
|
||||||
|
// overskrift begynder med stort.
|
||||||
|
const month = at.toLocaleDateString(tag(), { month: 'long', year: 'numeric' });
|
||||||
|
const label = month.charAt(0).toUpperCase() + month.slice(1);
|
||||||
return { key: `m-${at.getFullYear()}-${at.getMonth()}`, label };
|
return { key: `m-${at.getFullYear()}-${at.getMonth()}`, label };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,7 +813,11 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
{:else}
|
{:else}
|
||||||
<span class="mark" class:closed={folded.has(group.key)} aria-hidden="true">▾</span>
|
<!-- No arrow, to match the sidebar: the box folds on a click,
|
||||||
|
the star and the people icon are the marks that mean
|
||||||
|
something, and a date group has none — an empty spacer, so
|
||||||
|
every label still starts at the same place. -->
|
||||||
|
<span class="mark" aria-hidden="true"></span>
|
||||||
{/if}
|
{/if}
|
||||||
{group.label}
|
{group.label}
|
||||||
<span class="count">{group.notes.length}</span>
|
<span class="count">{group.notes.length}</span>
|
||||||
@@ -831,41 +838,38 @@
|
|||||||
ondragstart={(e) => onDragStart(e, note)}
|
ondragstart={(e) => onDragStart(e, note)}
|
||||||
ondragend={() => (dragging = null)}
|
ondragend={() => (dragging = null)}
|
||||||
>
|
>
|
||||||
<!-- Titel og projekt på linje ét, uddrag på linje to. Datoen står
|
<!-- Tre linjer, som Apple Noter: titlen, så datoen og uddraget, og
|
||||||
i gruppens overskrift og ikke her — undtagen når der er sorteret
|
nederst hvor noten er lagt. Datoen står forrest på linje to og
|
||||||
på navn, for så er der ingen overskrift, der siger den, og så er
|
venstrestillet, ikke ude til højre. -->
|
||||||
den det eneste tilbage, der gør. -->
|
|
||||||
<span class="head">
|
<span class="head">
|
||||||
<strong>{note.title || t('notes.untitled')}</strong>
|
<strong>{note.title || t('notes.untitled')}</strong>
|
||||||
{#if order === 'title'}
|
</span>
|
||||||
|
<span class="preview">
|
||||||
<span class="when" title={stamp(note)}>{when(shownDate(note))}</span>
|
<span class="when" title={stamp(note)}>{when(shownDate(note))}</span>
|
||||||
{/if}
|
<span class="snippet">{preview(note)}</span>
|
||||||
{#if note.project_id}
|
|
||||||
<!-- Projektets egen farve, den samme som prikken i sidebjælken.
|
|
||||||
Mærkaten sagde det samme som alle de andre i en grå, der var
|
|
||||||
lysere end uddraget — og projektet er dét, man skanner efter,
|
|
||||||
når man leder i tolv hundrede noter. Nu kan Hjem kendes fra
|
|
||||||
Claude uden at læse ordet. -->
|
|
||||||
<span class="filed" style="--project: {projectColour(note.project_id)}">
|
|
||||||
<span class="dot" aria-hidden="true"></span>
|
|
||||||
{projectName(note.project_id)}
|
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
<!-- Linje tre: hvor noten er lagt, med den samme mappe som grupperne i
|
||||||
|
menuen — projektets navn, ejerens hvis den er en andens, ellers bare
|
||||||
|
"Noter", når den ikke hører til et projekt. -->
|
||||||
|
<span class="filed">
|
||||||
{#if note.shared_with_me && note.owner}
|
{#if note.shared_with_me && note.owner}
|
||||||
<!-- Hvis note delt med mig: hvem den kom fra, i personens egen
|
<svg class="filed-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
avatar-farve. Samme form som projekt-mærkaten, så listen har
|
<circle cx="8" cy="6" r="2.3" fill="none" stroke="currentColor" stroke-width="1.4" />
|
||||||
ét sprog for "det her hører til nogen". -->
|
<path d="M3.6 13c0-2.5 2-4 4.4-4s4.4 1.5 4.4 4" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" />
|
||||||
<span
|
</svg>
|
||||||
class="filed person"
|
<span class="filed-name" title={t('notes.sharedBy', { name: note.owner.name })}>{note.owner.name}</span>
|
||||||
style="--project: {note.owner.avatar_color}"
|
{:else if note.project_id}
|
||||||
title={t('notes.sharedBy', { name: note.owner.name })}
|
<svg class="filed-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
>
|
<path d="M2 4.6a1 1 0 011-1h3.1l1.4 1.5H13a1 1 0 011 1v6.3a1 1 0 01-1 1H3a1 1 0 01-1-1z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round" />
|
||||||
<span class="dot" aria-hidden="true"></span>
|
</svg>
|
||||||
{note.owner.name}
|
<span class="filed-name">{projectName(note.project_id)}</span>
|
||||||
</span>
|
{:else}
|
||||||
|
<svg class="filed-icon" viewBox="0 0 16 16" aria-hidden="true">
|
||||||
|
<path d="M2 4.6a1 1 0 011-1h3.1l1.4 1.5H13a1 1 0 011 1v6.3a1 1 0 01-1 1H3a1 1 0 01-1-1z" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linejoin="round" />
|
||||||
|
</svg>
|
||||||
|
<span class="filed-name">{t('notes.title')}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
<span class="preview">{preview(note)}</span>
|
|
||||||
</button>
|
</button>
|
||||||
<!-- De to knapper står oven på hinanden i en smal søjle.
|
<!-- De to knapper står oven på hinanden i en smal søjle.
|
||||||
Ved siden af hinanden tog de toogfyrre pixels af en liste,
|
Ved siden af hinanden tog de toogfyrre pixels af en liste,
|
||||||
@@ -1322,13 +1326,20 @@
|
|||||||
* målt på en rigtig række: titel plus én linje uddrag. */
|
* målt på en rigtig række: titel plus én linje uddrag. */
|
||||||
li {
|
li {
|
||||||
content-visibility: auto;
|
content-visibility: auto;
|
||||||
contain-intrinsic-size: auto 54px;
|
contain-intrinsic-size: auto 74px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A faint hairline between notes, as Apple Notes has — the group boxes give the
|
||||||
|
coarse structure, this separates one note from the next inside a group. */
|
||||||
.rowline {
|
.rowline {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--s1);
|
gap: var(--s1);
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child .rowline {
|
||||||
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* De sjældne handlinger i en søjle, ikke en række. To knapper ved siden af
|
/* De sjældne handlinger i en søjle, ikke en række. To knapper ved siden af
|
||||||
@@ -1367,43 +1378,48 @@
|
|||||||
*
|
*
|
||||||
* Baggrunden er ikke gennemsigtig. En klæbende overskrift uden en er en
|
* Baggrunden er ikke gennemsigtig. En klæbende overskrift uden en er en
|
||||||
* overskrift med rækkerne kørende igennem sig. */
|
* overskrift med rækkerne kørende igennem sig. */
|
||||||
|
/* One design with the sidebar headings: a rounded box, the same corner as an
|
||||||
|
active menu item, filled just enough to separate one group of notes from the
|
||||||
|
next. The hard rule underneath is gone — the box is the separation now. */
|
||||||
h3.group {
|
h3.group {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
margin: 0;
|
margin: 0 0 var(--s1);
|
||||||
background: var(--ground);
|
background: var(--ground);
|
||||||
border-bottom: 1px solid var(--line);
|
border-radius: var(--radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Bold and plainly cased, in the reading ink — the faint uppercase label read as
|
||||||
|
a different app's heading beside the sidebar's. Menu size, so the two tiers of
|
||||||
|
heading in front of the eye at once are the same size. */
|
||||||
h3.group button {
|
h3.group button {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--s2);
|
gap: var(--s2);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: var(--s2) var(--s2);
|
padding: var(--s2) var(--s2);
|
||||||
font-size: var(--text-xs);
|
font-size: var(--menu-size);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
letter-spacing: 0.07em;
|
letter-spacing: normal;
|
||||||
text-transform: uppercase;
|
text-transform: none;
|
||||||
color: var(--ink-faint);
|
color: var(--ink);
|
||||||
|
border-radius: var(--radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
h3.group button:hover {
|
h3.group button:hover {
|
||||||
color: var(--ink-muted);
|
background: var(--surface-sunken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The mark, or an empty box the same width where a date group has none, so every
|
||||||
|
label starts at the same place. The star and the people icon fill it; the
|
||||||
|
arrow that used to is gone — the box folds on a click. */
|
||||||
h3.group .mark {
|
h3.group .mark {
|
||||||
flex: none;
|
flex: none;
|
||||||
width: 0.75em;
|
width: 0.75em;
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
color: var(--ink-faint);
|
color: var(--ink-faint);
|
||||||
transition: transform var(--fast) var(--ease);
|
|
||||||
}
|
|
||||||
|
|
||||||
h3.group .mark.closed {
|
|
||||||
transform: rotate(-90deg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sit eget navn og ikke `.star`. Rækkens favoritknap hedder også det og er
|
/* Sit eget navn og ikke `.star`. Rækkens favoritknap hedder også det og er
|
||||||
@@ -1419,6 +1435,7 @@
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
letter-spacing: 0;
|
letter-spacing: 0;
|
||||||
|
color: var(--ink-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stregen mellem rækkerne er væk.
|
/* Stregen mellem rækkerne er væk.
|
||||||
@@ -1480,19 +1497,25 @@
|
|||||||
/* Dato og begyndelse på samme linje, som Apple Noter gør det. To linjer pr.
|
/* Dato og begyndelse på samme linje, som Apple Noter gør det. To linjer pr.
|
||||||
note frem for tre, og datoen først, fordi det er den, man skanner efter. */
|
note frem for tre, og datoen først, fordi det er den, man skanner efter. */
|
||||||
|
|
||||||
|
/* Datoen forrest på linje to og venstrestillet, som Apple Noter — ikke skubbet
|
||||||
|
ud til højre. Tabular-tal, så en søjle af datoer står på lige linjer. */
|
||||||
.when {
|
.when {
|
||||||
flex: none;
|
flex: none;
|
||||||
color: var(--ink-muted);
|
color: var(--ink-muted);
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `display: block`, og det er ikke pynt.
|
/* Linje to er en flex-række: datoen, der ikke krymper, og uddraget, der klippes.
|
||||||
*
|
Afkortningen skal stå på uddraget selv — et inline-element klippes ikke af
|
||||||
* Uddraget lå før inde i en flex-boks, der ejede afkortningen. Da datoen flyttede
|
`overflow: hidden`. */
|
||||||
* op i gruppens overskrift, forsvandt den boks — og et inline-element klippes
|
|
||||||
* ikke af `overflow: hidden`, så den sidste sætning løb videre ind under
|
|
||||||
* favoritstjernen. Reglerne skal stå på det element, der faktisk skal klippes. */
|
|
||||||
.preview {
|
.preview {
|
||||||
display: block;
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 0.45em;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.snippet {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -1509,31 +1532,30 @@
|
|||||||
* Prikken bærer farven, ikke teksten. Fem projekters farver som skriftfarve på
|
* Prikken bærer farven, ikke teksten. Fem projekters farver som skriftfarve på
|
||||||
* en lys flade er fem forskellige grader af læsbarhed, og den lyseste af dem er
|
* en lys flade er fem forskellige grader af læsbarhed, og den lyseste af dem er
|
||||||
* ikke læsbar. */
|
* ikke læsbar. */
|
||||||
|
/* Linje tre: hvor noten er lagt. En mappe som grupperne i menuen og et navn,
|
||||||
|
venstrestillet under uddraget — ikke en mærkat skubbet ud til højre. */
|
||||||
.filed {
|
.filed {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.375em;
|
gap: 0.4em;
|
||||||
flex: none;
|
min-width: 0;
|
||||||
margin-left: auto;
|
margin-top: 1px;
|
||||||
max-width: 45%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
font-size: var(--text-xs);
|
font-size: var(--text-xs);
|
||||||
color: var(--ink-muted);
|
color: var(--ink-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.filed .dot {
|
.filed-icon {
|
||||||
width: 6px;
|
width: 13px;
|
||||||
height: 6px;
|
height: 13px;
|
||||||
flex: none;
|
flex: none;
|
||||||
border-radius: var(--radius-full);
|
color: var(--ink-faint);
|
||||||
background: var(--project, var(--line-strong));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.filed::before {
|
.filed-name {
|
||||||
content: '▸ ';
|
min-width: 0;
|
||||||
opacity: 0.7;
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Noten er et ark, ikke en flade i appen.
|
/* Noten er et ark, ikke en flade i appen.
|
||||||
@@ -1753,17 +1775,6 @@
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The person chip: the project mark's shape in a person's own colour. No ▸
|
|
||||||
before it — the coloured dot already says "belongs to", and two markers on
|
|
||||||
one short chip is noise. It sits next to the title rather than pushed to the
|
|
||||||
right, so in the Delt med mig group it reads as "Ferieplan — Sofie". */
|
|
||||||
.filed.person {
|
|
||||||
margin-left: 0.5em;
|
|
||||||
max-width: 40%;
|
|
||||||
}
|
|
||||||
.filed.person::before {
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sharepanel .none {
|
.sharepanel .none {
|
||||||
font-size: var(--text-xs);
|
font-size: var(--text-xs);
|
||||||
|
|||||||