daily-focus 0.1.0 → 0.1.1-dev.11
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/SETUP.md +3 -2
- package/dist/{audit-4AUZVELT.js → audit-TPBQFSL3.js} +1 -1
- package/dist/{chunk-2PLWVW5T.js → chunk-CQ53JYUU.js} +12 -1
- package/dist/cli.js +3 -3
- package/dist/{seed-7DIDKXT7.js → seed-S5ZU6EIO.js} +1 -1
- package/dist/{server-B4FWZHS2.js → server-O5GF3TRI.js} +5 -3
- package/package.json +1 -1
- package/public/app.js +78 -18
- package/public/style.css +47 -16
package/SETUP.md
CHANGED
|
@@ -320,7 +320,8 @@ that runs it, and the calendar helper, so there is nothing else to install, and
|
|
|
320
320
|
calendar permission is asked for once, by an app you recognise. It needs a Mac with
|
|
321
321
|
Apple silicon and macOS 13.5 or newer.
|
|
322
322
|
|
|
323
|
-
|
|
323
|
+
Download `Daily-Focus.dmg` from the [latest release](https://github.com/watson/daily-focus/releases/latest),
|
|
324
|
+
open it and drag the app to Applications, then open it from there.
|
|
324
325
|
It has no window and no Dock icon: look for it in the menu bar.
|
|
325
326
|
|
|
326
327
|
To build it yourself from a checkout:
|
|
@@ -329,7 +330,7 @@ To build it yourself from a checkout:
|
|
|
329
330
|
npm run app
|
|
330
331
|
```
|
|
331
332
|
|
|
332
|
-
That leaves `Daily
|
|
333
|
+
That leaves `Daily-Focus.dmg` and the app itself in `macos/build/`. Its log is
|
|
333
334
|
`~/Library/Logs/Daily Focus.log`. Everything the dashboard starts runs inside the
|
|
334
335
|
app as far as macOS is concerned, so a permission prompt from the morning agent's
|
|
335
336
|
CLI, for Reminders, Messages or your calendars, names Daily Focus, and Full Disk
|
|
@@ -551,7 +551,8 @@ async function readTodaysSessions(config, now) {
|
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
// src/store.ts
|
|
554
|
-
import {
|
|
554
|
+
import { createHash } from "node:crypto";
|
|
555
|
+
import { appendFile as appendFile2, mkdir as mkdir3, readFile as readFile3, stat } from "node:fs/promises";
|
|
555
556
|
import { setTimeout as delay } from "node:timers/promises";
|
|
556
557
|
|
|
557
558
|
// src/agenda.ts
|
|
@@ -710,6 +711,16 @@ var Store = class {
|
|
|
710
711
|
async ensureDataDir() {
|
|
711
712
|
await mkdir3(this.config.dataDir, { recursive: true });
|
|
712
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* Which store this is, as an opaque fingerprint: its path, and the directory's
|
|
716
|
+
* inode and birth time, so a store deleted and made again at the same path
|
|
717
|
+
* counts as another one. A tab compares it across reconnects; see the client's
|
|
718
|
+
* `checkStore`.
|
|
719
|
+
*/
|
|
720
|
+
async fingerprint() {
|
|
721
|
+
const info = await stat(this.config.dataDir);
|
|
722
|
+
return createHash("sha256").update(`${this.config.dataDir}\0${info.ino}\0${info.birthtimeMs}`).digest("hex").slice(0, 16);
|
|
723
|
+
}
|
|
713
724
|
/**
|
|
714
725
|
* Read and parse items.json.
|
|
715
726
|
*
|
package/dist/cli.js
CHANGED
|
@@ -78,7 +78,7 @@ async function demo(open) {
|
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
80
|
async function start(open, onStarted) {
|
|
81
|
-
const { runServer } = await import("./server-
|
|
81
|
+
const { runServer } = await import("./server-O5GF3TRI.js");
|
|
82
82
|
await runServer({
|
|
83
83
|
onStarted: (url) => {
|
|
84
84
|
onStarted?.(url);
|
|
@@ -184,10 +184,10 @@ async function main(argv) {
|
|
|
184
184
|
await import("./init-ZJCI2723.js");
|
|
185
185
|
return;
|
|
186
186
|
case "audit":
|
|
187
|
-
await import("./audit-
|
|
187
|
+
await import("./audit-TPBQFSL3.js");
|
|
188
188
|
return;
|
|
189
189
|
case "seed":
|
|
190
|
-
await import("./seed-
|
|
190
|
+
await import("./seed-S5ZU6EIO.js");
|
|
191
191
|
return;
|
|
192
192
|
case "build-calendar":
|
|
193
193
|
return buildCalendar();
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
stopSession,
|
|
17
17
|
tempPathFor,
|
|
18
18
|
writeJsonAtomic
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CQ53JYUU.js";
|
|
20
20
|
import {
|
|
21
21
|
CLI_NAMES,
|
|
22
22
|
LAUNCH_SETTINGS,
|
|
@@ -3443,7 +3443,7 @@ var SETTINGS = [
|
|
|
3443
3443
|
key: "DAILY_FOCUS_AGENT_MODEL",
|
|
3444
3444
|
group: "agent",
|
|
3445
3445
|
label: "Model",
|
|
3446
|
-
help: "Passed to the CLI as it is, such as opus. Empty uses the CLI's own default.",
|
|
3446
|
+
help: "Passed to the CLI as it is, such as opus for Claude Code. Empty uses the CLI's own default.",
|
|
3447
3447
|
kind: "text",
|
|
3448
3448
|
fallback: always("The CLI's own")
|
|
3449
3449
|
},
|
|
@@ -4132,6 +4132,7 @@ async function startServer(env, options = {}) {
|
|
|
4132
4132
|
for (const warning of configWarnings) console.warn(`[daily-focus] ${warning}`);
|
|
4133
4133
|
const store = new Store(config);
|
|
4134
4134
|
await store.ensureDataDir();
|
|
4135
|
+
const storeId = await store.fingerprint();
|
|
4135
4136
|
for (const outcome of await linkStore(config)) {
|
|
4136
4137
|
if (outcome.result === "linked") console.log(`[daily-focus] linked ${describeLink(config, outcome)}`);
|
|
4137
4138
|
if (outcome.result === "failed") console.warn(`[daily-focus] could not link ${outcome.name}: ${outcome.detail}`);
|
|
@@ -4191,7 +4192,8 @@ async function startServer(env, options = {}) {
|
|
|
4191
4192
|
setupWarnings: [...configWarnings, ...linkWarning ? [linkWarning] : []],
|
|
4192
4193
|
restart,
|
|
4193
4194
|
setup,
|
|
4194
|
-
assetVersion
|
|
4195
|
+
assetVersion,
|
|
4196
|
+
storeId
|
|
4195
4197
|
};
|
|
4196
4198
|
}
|
|
4197
4199
|
async function broadcast(prebuilt) {
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -1495,11 +1495,13 @@ function adoptState(next) {
|
|
|
1495
1495
|
ui.connectionError.value = null;
|
|
1496
1496
|
});
|
|
1497
1497
|
startLocalTick();
|
|
1498
|
+
checkStore(next.storeId);
|
|
1498
1499
|
checkAssetVersion(next.assetVersion);
|
|
1499
1500
|
}
|
|
1500
1501
|
async function refresh() {
|
|
1501
1502
|
try {
|
|
1502
1503
|
const next = await fetchState();
|
|
1504
|
+
checkStore(next.storeId);
|
|
1503
1505
|
checkAssetVersion(next.assetVersion);
|
|
1504
1506
|
n2(() => {
|
|
1505
1507
|
state.value = next;
|
|
@@ -1524,6 +1526,12 @@ function checkAssetVersion(next) {
|
|
|
1524
1526
|
}
|
|
1525
1527
|
location.reload();
|
|
1526
1528
|
}
|
|
1529
|
+
var loadedStore = null;
|
|
1530
|
+
function checkStore(next) {
|
|
1531
|
+
if (!next) return;
|
|
1532
|
+
loadedStore ??= next;
|
|
1533
|
+
if (next !== loadedStore) location.reload();
|
|
1534
|
+
}
|
|
1527
1535
|
var PAST_TENSE = {
|
|
1528
1536
|
done: "Marked done",
|
|
1529
1537
|
dismiss: "Dismissed",
|
|
@@ -1954,9 +1962,9 @@ var handlers = {
|
|
|
1954
1962
|
ui.menuFor.value = null;
|
|
1955
1963
|
}),
|
|
1956
1964
|
moveTicket: (key, status, from) => void moveTicket(key, status, from),
|
|
1957
|
-
openDetail: (id,
|
|
1965
|
+
openDetail: (id, field = null) => n2(() => {
|
|
1958
1966
|
setDetailFor(ui, id);
|
|
1959
|
-
ui.focusField.value =
|
|
1967
|
+
ui.focusField.value = field;
|
|
1960
1968
|
closeMenus();
|
|
1961
1969
|
}),
|
|
1962
1970
|
closeDetail: () => setDetailFor(ui, null),
|
|
@@ -2035,7 +2043,7 @@ var handlers = {
|
|
|
2035
2043
|
ui.settingsDraft.value = /* @__PURE__ */ new Map();
|
|
2036
2044
|
ui.settingsError.value = null;
|
|
2037
2045
|
}),
|
|
2038
|
-
saveSettings: () => void sendSettings(Object.fromEntries(ui.settingsDraft.value), true),
|
|
2046
|
+
saveSettings: (keys) => void sendSettings(Object.fromEntries([...ui.settingsDraft.value].filter(([key]) => !keys || keys.includes(key))), true),
|
|
2039
2047
|
chooseSettings: (values) => void sendSettings(values, false),
|
|
2040
2048
|
loadText: (name) => void loadText(name),
|
|
2041
2049
|
editText: (name, text) => patchText(name, { draft: text }),
|
|
@@ -2645,6 +2653,7 @@ function renderActions(item, state2, ui2, handlers2) {
|
|
|
2645
2653
|
{
|
|
2646
2654
|
type: "button",
|
|
2647
2655
|
class: "button",
|
|
2656
|
+
"aria-haspopup": "menu",
|
|
2648
2657
|
"aria-expanded": String(ui2.menuFor.value === item.id),
|
|
2649
2658
|
onClick: () => handlers2.toggleMenu(item.id)
|
|
2650
2659
|
},
|
|
@@ -2668,9 +2677,9 @@ function renderSnoozeMenu(item, now, handlers2, { indefinite = true, longRange =
|
|
|
2668
2677
|
presets.push(["Next month", addMonths(now, 1), true], ["Next quarter", addMonths(now, 3), true]);
|
|
2669
2678
|
}
|
|
2670
2679
|
let dateInput = null;
|
|
2671
|
-
return
|
|
2672
|
-
|
|
2673
|
-
{ class: "menu"
|
|
2680
|
+
return k(
|
|
2681
|
+
Menu,
|
|
2682
|
+
{ class: "menu" },
|
|
2674
2683
|
presets.map(
|
|
2675
2684
|
([label, until, dated]) => el(
|
|
2676
2685
|
"button",
|
|
@@ -2719,6 +2728,14 @@ function renderSnoozeMenu(item, now, handlers2, { indefinite = true, longRange =
|
|
|
2719
2728
|
)
|
|
2720
2729
|
);
|
|
2721
2730
|
}
|
|
2731
|
+
function Menu({ class: className, children }) {
|
|
2732
|
+
const ref = A2(null);
|
|
2733
|
+
_2(() => {
|
|
2734
|
+
const node = ref.current;
|
|
2735
|
+
if (node?.showPopover && !node.matches(":popover-open")) node.showPopover();
|
|
2736
|
+
});
|
|
2737
|
+
return el("div", { class: className, role: "menu", popover: "manual", ref }, children);
|
|
2738
|
+
}
|
|
2722
2739
|
function addDays(from, days) {
|
|
2723
2740
|
return localDateKey(new Date(from.getFullYear(), from.getMonth(), from.getDate() + days));
|
|
2724
2741
|
}
|
|
@@ -3061,6 +3078,7 @@ function renderPullActions(row, ui2, handlers2) {
|
|
|
3061
3078
|
type: "button",
|
|
3062
3079
|
class: "button",
|
|
3063
3080
|
title: "Park this until a date",
|
|
3081
|
+
"aria-haspopup": "menu",
|
|
3064
3082
|
"aria-expanded": String(ui2.menuFor.value === row.id),
|
|
3065
3083
|
onClick: () => handlers2.toggleMenu(row.id)
|
|
3066
3084
|
},
|
|
@@ -3312,6 +3330,7 @@ function renderTicketStatus(row, state2, ui2, handlers2) {
|
|
|
3312
3330
|
type: "button",
|
|
3313
3331
|
class: "pill pill--status pill--button",
|
|
3314
3332
|
title: `Move ${row.key} to another status`,
|
|
3333
|
+
"aria-haspopup": "menu",
|
|
3315
3334
|
"aria-expanded": String(ui2.statusFor.value === row.id),
|
|
3316
3335
|
onClick: () => handlers2.toggleStatus(row.id)
|
|
3317
3336
|
},
|
|
@@ -3328,9 +3347,9 @@ function ticketStatusOptions(row, state2) {
|
|
|
3328
3347
|
}
|
|
3329
3348
|
function renderStatusMenu(row, offered, ui2, handlers2) {
|
|
3330
3349
|
const busy = ui2.pending.value.has(row.id);
|
|
3331
|
-
return
|
|
3332
|
-
|
|
3333
|
-
{ class: "menu menu--status"
|
|
3350
|
+
return k(
|
|
3351
|
+
Menu,
|
|
3352
|
+
{ class: "menu menu--status" },
|
|
3334
3353
|
offered.map(
|
|
3335
3354
|
(status) => el(
|
|
3336
3355
|
"button",
|
|
@@ -3381,6 +3400,7 @@ function renderTicketActions(row, ui2, handlers2) {
|
|
|
3381
3400
|
type: "button",
|
|
3382
3401
|
class: "button",
|
|
3383
3402
|
title: "Park this until a date",
|
|
3403
|
+
"aria-haspopup": "menu",
|
|
3384
3404
|
"aria-expanded": String(ui2.menuFor.value === row.id),
|
|
3385
3405
|
onClick: () => handlers2.toggleMenu(row.id)
|
|
3386
3406
|
},
|
|
@@ -4203,13 +4223,13 @@ function SettingsView({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4203
4223
|
"section",
|
|
4204
4224
|
{ class: "settings-card", id: `settings-${group.id}`, key: group.id, "aria-labelledby": `settings-${group.id}-title` },
|
|
4205
4225
|
el("h3", { class: "settings-card__title", id: `settings-${group.id}-title` }, group.title),
|
|
4206
|
-
plain.map((setting) =>
|
|
4226
|
+
plain.map((setting) => settingField(setting, draft, handlers2)),
|
|
4207
4227
|
group.id === "calendar" ? calendarPicker(state2, ui2, handlers2, page.settings) : null,
|
|
4208
4228
|
advanced.length > 0 ? el(
|
|
4209
4229
|
"details",
|
|
4210
4230
|
{ class: "settings-card__more" },
|
|
4211
4231
|
el("summary", null, "More"),
|
|
4212
|
-
advanced.map((setting) =>
|
|
4232
|
+
advanced.map((setting) => settingField(setting, draft, handlers2))
|
|
4213
4233
|
) : null
|
|
4214
4234
|
);
|
|
4215
4235
|
}) : el("p", { class: "empty" }, "Loading the settings\u2026"),
|
|
@@ -4348,7 +4368,7 @@ function flagValue(raw) {
|
|
|
4348
4368
|
if (raw === "") return "";
|
|
4349
4369
|
return ["off", "false", "0", "no"].includes(raw.trim().toLowerCase()) ? "off" : "on";
|
|
4350
4370
|
}
|
|
4351
|
-
function
|
|
4371
|
+
function settingField(setting, draft, handlers2) {
|
|
4352
4372
|
const id = `setting-${setting.key}`;
|
|
4353
4373
|
const locked = setting.source === "environment";
|
|
4354
4374
|
const value = shownValue(setting, draft);
|
|
@@ -4475,7 +4495,7 @@ function SetupCard({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4475
4495
|
el(
|
|
4476
4496
|
"p",
|
|
4477
4497
|
{ class: "setup__lede" },
|
|
4478
|
-
"Each morning an agent reads your mail, calendar, pull requests and the rest, and writes a short brief of what needs
|
|
4498
|
+
"Each morning an agent reads your mail, calendar, pull requests and the rest, and writes a short brief of what needs to get done today. The steps below get it ready for its first run. Everything here can be changed later in ",
|
|
4479
4499
|
el("button", { type: "button", class: "link-button", onClick: () => handlers2.openSettings() }, "Settings"),
|
|
4480
4500
|
"."
|
|
4481
4501
|
),
|
|
@@ -4509,11 +4529,14 @@ function SetupCard({ state: state2, ui: ui2, handlers: handlers2 }) {
|
|
|
4509
4529
|
step(
|
|
4510
4530
|
agent.cli !== null,
|
|
4511
4531
|
"Which agent writes the brief?",
|
|
4512
|
-
agent.cli ?
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4532
|
+
agent.cli ? [
|
|
4533
|
+
el(
|
|
4534
|
+
"p",
|
|
4535
|
+
null,
|
|
4536
|
+
`${CLI_LABEL[agent.cli]}. ` + (agent.schedule ? `After the first brief, it runs by itself each scheduled morning at ${agent.schedule.at}. ` : "It runs when you press refresh. ") + "It has to be logged in; the first run says if it is not."
|
|
4537
|
+
),
|
|
4538
|
+
agentAdvanced(agent.cli, ui2, handlers2)
|
|
4539
|
+
] : agentChoice(state2, handlers2)
|
|
4517
4540
|
),
|
|
4518
4541
|
step(setup.sources.exists && setup.sources.placeholders === 0, "Who are you, and where should it look?", sourcesStep(state2, ui2, handlers2)),
|
|
4519
4542
|
step(null, "What else should the dashboard show?", boards(state2, handlers2)),
|
|
@@ -4586,6 +4609,43 @@ function agentChoice(state2, handlers2) {
|
|
|
4586
4609
|
)
|
|
4587
4610
|
];
|
|
4588
4611
|
}
|
|
4612
|
+
var AGENT_ADVANCED = "setup:agent-advanced";
|
|
4613
|
+
function agentAdvanced(cli, ui2, handlers2) {
|
|
4614
|
+
const keys = ["DAILY_FOCUS_AGENT_MODEL", "DAILY_FOCUS_AGENT_EFFORT", ...cli === "claude" ? ["DAILY_FOCUS_AGENT_TOOLS"] : []];
|
|
4615
|
+
const page = ui2.settings.value;
|
|
4616
|
+
const draft = ui2.settingsDraft.value;
|
|
4617
|
+
const changed = keys.some((key) => draft.has(key));
|
|
4618
|
+
const error = changed ? ui2.settingsError.value : null;
|
|
4619
|
+
return el(
|
|
4620
|
+
"details",
|
|
4621
|
+
{
|
|
4622
|
+
class: "setup__advanced",
|
|
4623
|
+
open: ui2.openDrawers.value.has(AGENT_ADVANCED),
|
|
4624
|
+
onToggle: (event) => {
|
|
4625
|
+
const open = event.currentTarget.open;
|
|
4626
|
+
if (open && !ui2.settings.peek()) handlers2.loadSettings();
|
|
4627
|
+
handlers2.toggleDrawer(AGENT_ADVANCED, open);
|
|
4628
|
+
}
|
|
4629
|
+
},
|
|
4630
|
+
el("summary", null, cli === "claude" ? "Advanced: model, effort and tools" : "Advanced: model and effort"),
|
|
4631
|
+
page ? [
|
|
4632
|
+
...keys.flatMap((key) => {
|
|
4633
|
+
const setting = page.settings.find((entry) => entry.key === key);
|
|
4634
|
+
return setting ? [settingField(setting, draft, handlers2)] : [];
|
|
4635
|
+
}),
|
|
4636
|
+
error ? el("p", { class: "setup__note setup__note--todo", role: "alert" }, error) : null,
|
|
4637
|
+
el(
|
|
4638
|
+
"div",
|
|
4639
|
+
{ class: "setup__advanced-actions" },
|
|
4640
|
+
el(
|
|
4641
|
+
"button",
|
|
4642
|
+
{ type: "button", class: "button", disabled: !changed || ui2.settingsSaving.value, onClick: () => handlers2.saveSettings(keys) },
|
|
4643
|
+
ui2.settingsSaving.value ? "Saving\u2026" : "Save"
|
|
4644
|
+
)
|
|
4645
|
+
)
|
|
4646
|
+
] : el("p", null, "Loading the settings\u2026")
|
|
4647
|
+
);
|
|
4648
|
+
}
|
|
4589
4649
|
var SOURCES_EDITOR = "setup:sources";
|
|
4590
4650
|
function sourcesStep(state2, ui2, handlers2) {
|
|
4591
4651
|
const sources = state2.setup.sources;
|
package/public/style.css
CHANGED
|
@@ -1152,14 +1152,29 @@ body[data-session-active='true'] #today .item:not([data-running='true']):focus-w
|
|
|
1152
1152
|
|
|
1153
1153
|
/* snooze menu */
|
|
1154
1154
|
|
|
1155
|
+
/*
|
|
1156
|
+
* A popover in the top layer (`Menu` in client/items.ts says why), hung from the
|
|
1157
|
+
* button that opened it. Only one menu is ever open, so only one button is
|
|
1158
|
+
* expanded and the one anchor name is never ambiguous. `inset` and `margin`
|
|
1159
|
+
* undo the popover's own centring on the viewport.
|
|
1160
|
+
*/
|
|
1161
|
+
[aria-haspopup='menu'][aria-expanded='true'] {
|
|
1162
|
+
anchor-name: --menu;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1155
1165
|
.menu {
|
|
1156
|
-
position:
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1166
|
+
position: fixed;
|
|
1167
|
+
position-anchor: --menu;
|
|
1168
|
+
inset: auto;
|
|
1169
|
+
top: anchor(bottom);
|
|
1170
|
+
right: anchor(right);
|
|
1171
|
+
margin: 4px 0;
|
|
1172
|
+
/* Above the button instead, when the window has no room left below it. */
|
|
1173
|
+
position-try-fallbacks: flip-block;
|
|
1160
1174
|
/* Wide enough that the date field below still shows its own placeholder. */
|
|
1161
1175
|
min-width: 204px;
|
|
1162
1176
|
padding: 5px;
|
|
1177
|
+
color: var(--ink-2);
|
|
1163
1178
|
background: var(--surface);
|
|
1164
1179
|
border: 1px solid var(--border);
|
|
1165
1180
|
border-radius: var(--radius-sm);
|
|
@@ -1636,10 +1651,11 @@ body[data-view='settings'] .layout {
|
|
|
1636
1651
|
* line up with the other tabs' however wide the display is. The 460px floor is
|
|
1637
1652
|
* what drops it to one column on a narrow window rather than squeezing two.
|
|
1638
1653
|
*
|
|
1639
|
-
*
|
|
1640
|
-
*
|
|
1641
|
-
*
|
|
1642
|
-
*
|
|
1654
|
+
* An absolutely positioned child is still fragmented by the columns, and counts
|
|
1655
|
+
* toward balancing them. `.item__actions` stays inside its card, so it travels
|
|
1656
|
+
* with the card into its column and nothing notices. Anything that hangs below a
|
|
1657
|
+
* card must not be in here at all: the row menus once were, and were split
|
|
1658
|
+
* across both columns and pushed the next section down. They are popovers now.
|
|
1643
1659
|
*/
|
|
1644
1660
|
#tickets .list {
|
|
1645
1661
|
display: block;
|
|
@@ -1836,14 +1852,13 @@ body[data-view='settings'] .layout {
|
|
|
1836
1852
|
}
|
|
1837
1853
|
|
|
1838
1854
|
/*
|
|
1839
|
-
*
|
|
1840
|
-
*
|
|
1841
|
-
*
|
|
1855
|
+
* Hung from the pill's left edge, where the park menu hangs from its button's
|
|
1856
|
+
* right: the pill sits in the card's left gutter, so each menu opens toward the
|
|
1857
|
+
* middle of its own card.
|
|
1842
1858
|
*/
|
|
1843
1859
|
.menu--status {
|
|
1844
|
-
top: 26px;
|
|
1845
1860
|
right: auto;
|
|
1846
|
-
left:
|
|
1861
|
+
left: anchor(left);
|
|
1847
1862
|
min-width: 9rem;
|
|
1848
1863
|
}
|
|
1849
1864
|
|
|
@@ -2317,6 +2332,19 @@ body[data-flyout='open'] .layout__side {
|
|
|
2317
2332
|
.setup__editor {
|
|
2318
2333
|
margin-top: 12px;
|
|
2319
2334
|
}
|
|
2335
|
+
/* The settings page's own fold and fields, inside a step. */
|
|
2336
|
+
.setup__body .setup__advanced p {
|
|
2337
|
+
margin: 0;
|
|
2338
|
+
font-size: 12px;
|
|
2339
|
+
line-height: 1.45;
|
|
2340
|
+
}
|
|
2341
|
+
.setup__advanced .field {
|
|
2342
|
+
max-width: 480px;
|
|
2343
|
+
}
|
|
2344
|
+
.setup__advanced-actions {
|
|
2345
|
+
display: flex;
|
|
2346
|
+
justify-content: flex-start;
|
|
2347
|
+
}
|
|
2320
2348
|
|
|
2321
2349
|
/* ---------- settings ---------- */
|
|
2322
2350
|
|
|
@@ -2365,16 +2393,19 @@ body[data-flyout='open'] .layout__side {
|
|
|
2365
2393
|
color: var(--serious);
|
|
2366
2394
|
font-size: 13px;
|
|
2367
2395
|
}
|
|
2368
|
-
.settings-card__more
|
|
2396
|
+
.settings-card__more,
|
|
2397
|
+
.setup__advanced {
|
|
2369
2398
|
margin-top: 6px;
|
|
2370
2399
|
}
|
|
2371
|
-
.settings-card__more > summary
|
|
2400
|
+
.settings-card__more > summary,
|
|
2401
|
+
.setup__advanced > summary {
|
|
2372
2402
|
cursor: pointer;
|
|
2373
2403
|
color: var(--ink-2);
|
|
2374
2404
|
font-size: 13px;
|
|
2375
2405
|
padding: 4px 0;
|
|
2376
2406
|
}
|
|
2377
|
-
.settings-card__more[open] > summary
|
|
2407
|
+
.settings-card__more[open] > summary,
|
|
2408
|
+
.setup__advanced[open] > summary {
|
|
2378
2409
|
margin-bottom: 10px;
|
|
2379
2410
|
}
|
|
2380
2411
|
|