mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-05-01 06:36:23 +08:00
dreaming: simplify Scene and Diary UI
Scene: remove trace grid, replace with clean phase cards (Light/Deep/REM). Diary: remove arrow nav and heatmap, replace with horizontal scrollable date chips. Left-align content to match rest of app. Net -250 lines.
This commit is contained in:
@@ -282,153 +282,56 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Stats bar ---- */
|
||||
/* ---- Sleep phase cards ---- */
|
||||
|
||||
.dreams__stats {
|
||||
position: relative;
|
||||
.dreams__phases {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 48px;
|
||||
margin-top: 36px;
|
||||
gap: 24px;
|
||||
margin-top: 32px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dreams__stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.dreams__stat-value {
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.dreams__stat-label {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.dreams__stat-divider {
|
||||
width: 1px;
|
||||
height: 32px;
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
.dreams__trace {
|
||||
position: relative;
|
||||
width: min(900px, calc(100% - 40px));
|
||||
margin-top: 28px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
align-items: start;
|
||||
gap: 12px;
|
||||
z-index: 1;
|
||||
user-select: text;
|
||||
max-height: min(500px, calc(100vh - 240px));
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.dreams__trace-section {
|
||||
position: relative;
|
||||
background: color-mix(in oklab, var(--panel) 82%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--border) 78%, transparent);
|
||||
border-radius: 16px;
|
||||
padding: 12px;
|
||||
min-height: 180px;
|
||||
backdrop-filter: blur(14px);
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dreams__trace-header {
|
||||
.dreams__phase {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.dreams__trace-title {
|
||||
font-size: 11px;
|
||||
color: var(--muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.dreams__trace-count {
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 999px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: color-mix(in oklab, var(--accent-subtle) 85%, transparent);
|
||||
color: var(--accent);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.dreams__trace-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.dreams__trace-item {
|
||||
padding: 10px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 12px;
|
||||
background: color-mix(in oklab, var(--panel-raised) 88%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--border) 72%, transparent);
|
||||
overflow: hidden;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
background: color-mix(in oklab, var(--panel) 70%, transparent);
|
||||
border: 1px solid color-mix(in oklab, var(--border) 60%, transparent);
|
||||
}
|
||||
|
||||
.dreams__trace-snippet {
|
||||
font-size: 13px;
|
||||
line-height: 1.35;
|
||||
.dreams__phase--off {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.dreams__phase-dot {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: var(--muted);
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.dreams__phase-dot--on {
|
||||
background: var(--ok);
|
||||
opacity: 1;
|
||||
box-shadow: 0 0 6px rgba(34, 197, 94, 0.3);
|
||||
}
|
||||
|
||||
.dreams__phase-name {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.dreams__trace-source,
|
||||
.dreams__trace-meta,
|
||||
.dreams__trace-empty {
|
||||
margin-top: 6px;
|
||||
.dreams__phase-next {
|
||||
font-size: 11px;
|
||||
line-height: 1.35;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.dreams__trace-source {
|
||||
font-family: var(--mono);
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.dreams__trace-meta,
|
||||
.dreams__trace-empty {
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.dreams__trace {
|
||||
grid-template-columns: 1fr;
|
||||
width: min(680px, calc(100% - 32px));
|
||||
}
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* ---- Dreaming on/off toggle (header bar) ---- */
|
||||
@@ -561,48 +464,13 @@
|
||||
=========================================== */
|
||||
|
||||
.dreams-diary {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 48px 24px 64px;
|
||||
padding: 24px 32px 64px;
|
||||
flex: 1;
|
||||
min-height: 320px;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
var(--bg) 0%,
|
||||
color-mix(in oklab, var(--bg) 94%, #0d0818) 40%,
|
||||
color-mix(in oklab, var(--bg) 88%, #0d0818) 100%
|
||||
);
|
||||
}
|
||||
|
||||
/* Ambient shimmer across the diary surface */
|
||||
.dreams-diary::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: linear-gradient(
|
||||
135deg,
|
||||
transparent 30%,
|
||||
rgba(251, 191, 36, 0.012) 45%,
|
||||
rgba(255, 77, 77, 0.015) 55%,
|
||||
transparent 70%
|
||||
);
|
||||
background-size: 400% 400%;
|
||||
animation: diary-shimmer 20s ease-in-out infinite;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes diary-shimmer {
|
||||
0%,
|
||||
100% {
|
||||
background-position: 0% 0%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- Diary header ---- */
|
||||
@@ -611,11 +479,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 32px;
|
||||
width: 100%;
|
||||
max-width: 520px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -677,18 +541,12 @@
|
||||
|
||||
.dreams-diary__entry {
|
||||
position: relative;
|
||||
max-width: 520px;
|
||||
width: 100%;
|
||||
padding: 0 0 0 20px;
|
||||
z-index: 1;
|
||||
max-width: 680px;
|
||||
padding: 0 0 0 16px;
|
||||
flex-shrink: 0;
|
||||
animation: diary-entry-reveal 1.4s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
.dreams-diary__entry--structured {
|
||||
max-width: 1180px;
|
||||
}
|
||||
|
||||
@keyframes diary-entry-reveal {
|
||||
0% {
|
||||
opacity: 0;
|
||||
@@ -732,13 +590,25 @@
|
||||
|
||||
.dreams-diary__date {
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
color: var(--accent-muted);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
font-weight: 400;
|
||||
font-size: 12px;
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.dreams-diary__daychips {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin: 0 0 24px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.dreams-diary__daychips::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dreams-diary__navigator {
|
||||
@@ -804,9 +674,7 @@
|
||||
}
|
||||
|
||||
.dreams-diary__day-chip {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: 6px 0;
|
||||
padding: 4px 12px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid color-mix(in oklab, var(--border) 70%, transparent);
|
||||
background: color-mix(in oklab, var(--panel) 84%, transparent);
|
||||
@@ -815,6 +683,13 @@
|
||||
font-variant-numeric: tabular-nums;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
transition: border-color 140ms ease, color 140ms ease, background 140ms ease;
|
||||
}
|
||||
|
||||
.dreams-diary__day-chip:hover {
|
||||
color: var(--text);
|
||||
border-color: color-mix(in oklab, var(--accent) 30%, var(--border));
|
||||
}
|
||||
|
||||
.dreams-diary__day-chip--active {
|
||||
@@ -965,10 +840,9 @@
|
||||
|
||||
.dreams-diary__para {
|
||||
margin: 0 0 12px;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
color: color-mix(in oklab, var(--text) 85%, var(--muted));
|
||||
font-style: italic;
|
||||
font-size: 13px;
|
||||
line-height: 1.7;
|
||||
color: var(--text);
|
||||
animation: diary-text-stream 2.4s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-word;
|
||||
@@ -1039,29 +913,13 @@
|
||||
min-height: calc(100vh - 96px);
|
||||
}
|
||||
|
||||
.dreams__stats {
|
||||
gap: 22px;
|
||||
}
|
||||
|
||||
.dreams__phase-bar {
|
||||
.dreams__phases {
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
}
|
||||
|
||||
.dreams__phase-bar-phases {
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.dreams-diary {
|
||||
padding: 32px 16px 48px;
|
||||
}
|
||||
|
||||
.dreams-diary__entry {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.dreams-diary__grid {
|
||||
grid-template-columns: 1fr;
|
||||
padding: 20px 16px 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1936,6 +1936,7 @@ export function renderApp(state: AppViewState) {
|
||||
totalSignalCount: state.dreamingStatus?.totalSignalCount ?? 0,
|
||||
promotedCount: state.dreamingStatus?.promotedToday ?? 0,
|
||||
phaseSignalCount: state.dreamingStatus?.phaseSignalCount ?? 0,
|
||||
phases: state.dreamingStatus?.phases ?? undefined,
|
||||
shortTermEntries: state.dreamingStatus?.shortTermEntries ?? [],
|
||||
signalEntries: state.dreamingStatus?.signalEntries ?? [],
|
||||
promotedEntries: state.dreamingStatus?.promotedEntries ?? [],
|
||||
|
||||
@@ -255,6 +255,12 @@ function renderDiaryNavigator(
|
||||
`;
|
||||
}
|
||||
|
||||
type DreamingPhaseInfo = {
|
||||
enabled: boolean;
|
||||
cron: string;
|
||||
nextRunAtMs?: number;
|
||||
};
|
||||
|
||||
export type DreamingProps = {
|
||||
active: boolean;
|
||||
shortTermCount: number;
|
||||
@@ -262,6 +268,11 @@ export type DreamingProps = {
|
||||
totalSignalCount: number;
|
||||
promotedCount: number;
|
||||
phaseSignalCount: number;
|
||||
phases?: {
|
||||
light: DreamingPhaseInfo;
|
||||
deep: DreamingPhaseInfo;
|
||||
rem: DreamingPhaseInfo;
|
||||
};
|
||||
shortTermEntries: {
|
||||
key: string;
|
||||
path: string;
|
||||
@@ -474,8 +485,40 @@ export function renderDreaming(props: DreamingProps) {
|
||||
|
||||
// ── Scene renderer ────────────────────────────────────────────────────
|
||||
|
||||
// Strip source citations like [memory/2026-04-09.md:9] and section headings,
|
||||
// flatten structured diary entries into plain paragraphs.
|
||||
function flattenDiaryBody(body: string): string[] {
|
||||
return body
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
// Remove section headings that leak implementation
|
||||
.filter(
|
||||
(line) =>
|
||||
line.length > 0 &&
|
||||
line !== "What Happened" &&
|
||||
line !== "Reflections" &&
|
||||
line !== "Candidates" &&
|
||||
line !== "Possible Lasting Updates",
|
||||
)
|
||||
// Strip source citations [memory/...]
|
||||
.map((line) => line.replace(/\s*\[memory\/[^\]]+\]/g, ""))
|
||||
// Strip leading list markers and labels
|
||||
.map((line) =>
|
||||
line
|
||||
.replace(/^(?:\d+\.\s+|-\s+(?:\[[^\]]+\]\s+)?(?:[a-z_]+:\s+)?)/i, "")
|
||||
.replace(/^(?:likely_durable|likely_situational|unclear):\s+/i, "")
|
||||
.trim(),
|
||||
)
|
||||
.filter((line) => line.length > 0);
|
||||
}
|
||||
|
||||
function formatPhaseNextRun(nextRunAtMs?: number): string {
|
||||
if (!nextRunAtMs) {return "—";}
|
||||
const d = new Date(nextRunAtMs);
|
||||
return d.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
||||
}
|
||||
|
||||
function renderScene(props: DreamingProps, idle: boolean, dreamText: string) {
|
||||
const groundedEntries = props.shortTermEntries.filter((entry) => entry.groundedCount > 0);
|
||||
return html`
|
||||
<section class="dreams ${idle ? "dreams--idle" : ""}">
|
||||
${STARS.map(
|
||||
@@ -534,6 +577,24 @@ function renderScene(props: DreamingProps, idle: boolean, dreamText: string) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sleep phases -->
|
||||
<div class="dreams__phases">
|
||||
${["light", "deep", "rem"].map((phaseId) => {
|
||||
const phase = props.phases?.[phaseId as keyof NonNullable<typeof props.phases>];
|
||||
const enabled = phase?.enabled ?? false;
|
||||
const nextRun = formatPhaseNextRun(phase?.nextRunAtMs);
|
||||
const label = phaseId.charAt(0).toUpperCase() + phaseId.slice(1);
|
||||
return html`
|
||||
<div class="dreams__phase ${enabled ? "" : "dreams__phase--off"}">
|
||||
<div class="dreams__phase-dot ${enabled ? "dreams__phase-dot--on" : ""}"></div>
|
||||
<span class="dreams__phase-name">${label}</span>
|
||||
<span class="dreams__phase-next">${enabled ? nextRun : "off"}</span>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="dreams__actions">
|
||||
<button
|
||||
class="btn btn--subtle btn--sm"
|
||||
@@ -551,106 +612,6 @@ function renderScene(props: DreamingProps, idle: boolean, dreamText: string) {
|
||||
>
|
||||
${t("dreaming.scene.reset")}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn--subtle btn--sm"
|
||||
?disabled=${props.modeSaving || props.dreamDiaryActionLoading}
|
||||
@click=${() => props.onResetGroundedShortTerm()}
|
||||
>
|
||||
${t("dreaming.scene.clearGrounded")}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dreams__stats">
|
||||
<div class="dreams__stat">
|
||||
<span class="dreams__stat-value" style="color: var(--text-strong);"
|
||||
>${props.shortTermCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.shortTerm")}</span>
|
||||
</div>
|
||||
<div class="dreams__stat-divider"></div>
|
||||
<div class="dreams__stat">
|
||||
<span class="dreams__stat-value" style="color: var(--accent-muted);"
|
||||
>${props.groundedSignalCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.grounded")}</span>
|
||||
</div>
|
||||
<div class="dreams__stat-divider"></div>
|
||||
<div class="dreams__stat">
|
||||
<span class="dreams__stat-value" style="color: var(--accent);"
|
||||
>${props.totalSignalCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.signals")}</span>
|
||||
</div>
|
||||
<div class="dreams__stat-divider"></div>
|
||||
<div class="dreams__stat">
|
||||
<span class="dreams__stat-value" style="color: var(--accent-2);"
|
||||
>${props.promotedCount}</span
|
||||
>
|
||||
<span class="dreams__stat-label">${t("dreaming.stats.promoted")}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dreams__trace">
|
||||
${renderTraceSection("shortTerm", props.shortTermEntries, {
|
||||
count: props.shortTermCount,
|
||||
emptyKey: "dreaming.trace.emptyShortTerm",
|
||||
meta: (entry) =>
|
||||
[
|
||||
entry.recallCount > 0
|
||||
? `${entry.recallCount} recall${entry.recallCount === 1 ? "" : "s"}`
|
||||
: null,
|
||||
entry.dailyCount > 0 ? `${entry.dailyCount} daily` : null,
|
||||
entry.groundedCount > 0 ? `${entry.groundedCount} grounded` : null,
|
||||
entry.phaseHitCount > 0
|
||||
? `${entry.phaseHitCount} phase hit${entry.phaseHitCount === 1 ? "" : "s"}`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" · "),
|
||||
})}
|
||||
${renderTraceSection("grounded", groundedEntries, {
|
||||
count: groundedEntries.length,
|
||||
emptyKey: "dreaming.trace.emptyGrounded",
|
||||
meta: (entry) =>
|
||||
[
|
||||
`${entry.groundedCount} grounded`,
|
||||
entry.recallCount > 0
|
||||
? `${entry.recallCount} recall${entry.recallCount === 1 ? "" : "s"}`
|
||||
: null,
|
||||
entry.dailyCount > 0 ? `${entry.dailyCount} daily` : null,
|
||||
isGroundedLed(entry) ? t("dreaming.trace.groundedLed") : null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" · "),
|
||||
})}
|
||||
${renderTraceSection("signals", props.signalEntries, {
|
||||
count: props.totalSignalCount,
|
||||
emptyKey: "dreaming.trace.emptySignals",
|
||||
meta: (entry) =>
|
||||
[
|
||||
`${entry.totalSignalCount} signal${entry.totalSignalCount === 1 ? "" : "s"}`,
|
||||
entry.phaseHitCount > 0
|
||||
? `${entry.phaseHitCount} phase hit${entry.phaseHitCount === 1 ? "" : "s"}`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" · "),
|
||||
})}
|
||||
${renderTraceSection("promoted", props.promotedEntries, {
|
||||
count: props.promotedCount,
|
||||
emptyKey: "dreaming.trace.emptyPromoted",
|
||||
meta: (entry) =>
|
||||
[
|
||||
entry.promotedAt ? formatCompactDateTime(entry.promotedAt) : null,
|
||||
entry.groundedCount > 0 ? `${entry.groundedCount} grounded` : null,
|
||||
isGroundedLed(entry) ? t("dreaming.trace.groundedLed") : null,
|
||||
entry.totalSignalCount > 0
|
||||
? `${entry.totalSignalCount} signal${entry.totalSignalCount === 1 ? "" : "s"} before promote`
|
||||
: null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(" · "),
|
||||
})}
|
||||
</div>
|
||||
|
||||
${props.statusError
|
||||
@@ -791,31 +752,6 @@ function renderDiarySection(props: DreamingProps) {
|
||||
<section class="dreams-diary">
|
||||
<div class="dreams-diary__header">
|
||||
<span class="dreams-diary__title">${t("dreaming.diary.title")}</span>
|
||||
<div class="dreams-diary__nav">
|
||||
<button
|
||||
class="dreams-diary__nav-btn"
|
||||
?disabled=${!hasNext}
|
||||
@click=${() => {
|
||||
setDiaryPage(page + 1);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
title=${t("dreaming.diary.older")}
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
<span class="dreams-diary__page">${page + 1} / ${reversed.length}</span>
|
||||
<button
|
||||
class="dreams-diary__nav-btn"
|
||||
?disabled=${!hasPrev}
|
||||
@click=${() => {
|
||||
setDiaryPage(page - 1);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
title=${t("dreaming.diary.newer")}
|
||||
>
|
||||
›
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn--subtle btn--sm"
|
||||
?disabled=${props.modeSaving || props.dreamDiaryLoading}
|
||||
@@ -828,109 +764,39 @@ function renderDiarySection(props: DreamingProps) {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dreams-diary__navigator">
|
||||
<div class="dreams-diary__navigator-content">
|
||||
${renderDiaryNavigator(reversed, page, props.onRequestUpdate)}
|
||||
</div>
|
||||
<!-- Simple day chips -->
|
||||
<div class="dreams-diary__daychips">
|
||||
${reversed.map(
|
||||
(e, i) => html`
|
||||
<button
|
||||
class="dreams-diary__day-chip ${e.page === page
|
||||
? "dreams-diary__day-chip--active"
|
||||
: ""}"
|
||||
@click=${() => {
|
||||
setDiaryPage(e.page);
|
||||
props.onRequestUpdate?.();
|
||||
}}
|
||||
>
|
||||
${formatDiaryChipLabel(e.date)}
|
||||
</button>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
|
||||
<article
|
||||
class="dreams-diary__entry ${structured ? "dreams-diary__entry--structured" : ""}"
|
||||
key="${page}"
|
||||
>
|
||||
<article class="dreams-diary__entry" key="${page}">
|
||||
<div class="dreams-diary__accent"></div>
|
||||
${entry.date ? html`<time class="dreams-diary__date">${entry.date}</time>` : nothing}
|
||||
${structured
|
||||
? html`
|
||||
<div class="dreams-diary__grid">
|
||||
<section class="dreams-diary__panel">
|
||||
<h3 class="dreams-diary__panel-title">What Happened</h3>
|
||||
<div class="dreams-diary__panel-list dreams-diary__panel-list--points">
|
||||
${structured.whatHappened.map(
|
||||
(item, i) => html`
|
||||
<div
|
||||
class="dreams-diary__point"
|
||||
style="animation-delay: ${0.2 + i * 0.06}s;"
|
||||
>
|
||||
<span class="dreams-diary__point-bullet"></span>
|
||||
<p class="dreams-diary__item">${item}</p>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
<section class="dreams-diary__panel">
|
||||
<h3 class="dreams-diary__panel-title">Reflections</h3>
|
||||
<div class="dreams-diary__panel-list dreams-diary__panel-list--points">
|
||||
${structured.reflections.map(
|
||||
(item, i) => html`
|
||||
<div
|
||||
class="dreams-diary__point"
|
||||
style="animation-delay: ${0.26 + i * 0.06}s;"
|
||||
>
|
||||
<span class="dreams-diary__point-bullet"></span>
|
||||
<p class="dreams-diary__item dreams-diary__item--reflection">${item}</p>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
<section class="dreams-diary__panel">
|
||||
<h3 class="dreams-diary__panel-title">Candidates + Possible Lasting Updates</h3>
|
||||
${structured.candidates.length > 0
|
||||
? html`
|
||||
<div class="dreams-diary__panel-subtitle">Candidates</div>
|
||||
<div class="dreams-diary__panel-list dreams-diary__panel-list--points">
|
||||
${structured.candidates.map(
|
||||
(item, i) => html`
|
||||
<div
|
||||
class="dreams-diary__point"
|
||||
style="animation-delay: ${0.32 + i * 0.06}s;"
|
||||
>
|
||||
<span class="dreams-diary__point-bullet"></span>
|
||||
<p class="dreams-diary__item">${item}</p>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
${structured.lastingUpdates.length > 0
|
||||
? html`
|
||||
<div class="dreams-diary__panel-subtitle">Possible Lasting Updates</div>
|
||||
<div class="dreams-diary__panel-list dreams-diary__panel-list--points">
|
||||
${structured.lastingUpdates.map(
|
||||
(item, i) => html`
|
||||
<div
|
||||
class="dreams-diary__point"
|
||||
style="animation-delay: ${0.38 + i * 0.06}s;"
|
||||
>
|
||||
<span class="dreams-diary__point-bullet"></span>
|
||||
<p class="dreams-diary__item dreams-diary__item--update">${item}</p>
|
||||
</div>
|
||||
`,
|
||||
)}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</section>
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="dreams-diary__prose">
|
||||
${entry.body
|
||||
.split("\n")
|
||||
.map(
|
||||
(para, i) =>
|
||||
html`<p
|
||||
class="dreams-diary__para"
|
||||
style="animation-delay: ${0.3 + i * 0.15}s;"
|
||||
>
|
||||
${para}
|
||||
</p>`,
|
||||
)}
|
||||
</div>
|
||||
`}
|
||||
<div class="dreams-diary__prose">
|
||||
${flattenDiaryBody(entry.body).map(
|
||||
(para, i) =>
|
||||
html`<p
|
||||
class="dreams-diary__para"
|
||||
style="animation-delay: ${0.3 + i * 0.15}s;"
|
||||
>
|
||||
${para}
|
||||
</p>`,
|
||||
)}
|
||||
</div>
|
||||
</article>
|
||||
</section>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user