diff --git a/src/components/LogTerminal.svelte b/src/components/LogTerminal.svelte
index 0b69054..ef53fce 100644
--- a/src/components/LogTerminal.svelte
+++ b/src/components/LogTerminal.svelte
@@ -86,10 +86,10 @@
{#if activity}
- |
- /
- -
- \
+ •
+ )
+ )
+ )
{activity}
diff --git a/src/components/LogTerminal.test.ts b/src/components/LogTerminal.test.ts
index 52bc175..9cedffb 100644
--- a/src/components/LogTerminal.test.ts
+++ b/src/components/LogTerminal.test.ts
@@ -10,7 +10,12 @@ describe("LogTerminal", () => {
const label = screen.getByText("audit running");
expect(label.closest(".term-line")).toBe(container.querySelector(".term-line:last-child"));
- expect(container.querySelector(".term-spinner")).toHaveAttribute("aria-hidden", "true");
+ const spinner = container.querySelector(".term-spinner");
+ expect(spinner).toHaveAttribute("aria-hidden", "true");
+ expect(spinner?.querySelector(".term-spinner__dot")).toHaveTextContent("•");
+ const arcs = spinner?.querySelectorAll(".term-spinner__arc");
+ expect(arcs).toHaveLength(3);
+ for (const arc of arcs ?? []) expect(arc).toHaveTextContent(")");
await rerender({ activity: null });
diff --git a/src/styles.css b/src/styles.css
index feef49c..72b898f 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -951,34 +951,72 @@ textarea {
color: var(--term-fg);
}
.term-spinner {
- display: inline-grid;
- flex: 0 0 1ch;
+ display: inline-flex;
+ flex: 0 0 4ch;
+ width: 4ch;
+}
+.term-spinner__dot,
+.term-spinner__arc {
+ display: inline-block;
width: 1ch;
+ text-align: center;
+}
+.term-spinner__dot {
color: var(--term-done);
}
-.term-spinner__frame {
- grid-area: 1 / 1;
+.term-spinner__arc {
opacity: 0;
- animation: term-spinner-frame 0.8s linear infinite;
+ animation-duration: 1.2s;
+ animation-timing-function: step-end;
+ animation-iteration-count: infinite;
+}
+.term-spinner__arc--inner {
+ color: var(--term-external);
+ animation-name: term-signal-inner;
}
-.term-spinner__frame--two {
- animation-delay: -0.6s;
+.term-spinner__arc--middle {
+ color: var(--term-user);
+ animation-name: term-signal-middle;
}
-.term-spinner__frame--three {
- animation-delay: -0.4s;
+.term-spinner__arc--outer {
+ color: var(--term-trust);
+ animation-name: term-signal-outer;
}
-.term-spinner__frame--four {
- animation-delay: -0.2s;
+@keyframes term-signal-inner {
+ 0%,
+ 19.999%,
+ 85%,
+ 100% {
+ opacity: 0;
+ }
+ 20%,
+ 84.999% {
+ opacity: 1;
+ }
}
-@keyframes term-spinner-frame {
+@keyframes term-signal-middle {
0%,
- 24.999% {
+ 39.999%,
+ 85%,
+ 100% {
+ opacity: 0;
+ }
+ 40%,
+ 84.999% {
opacity: 1;
}
- 25%,
+}
+@keyframes term-signal-outer {
+ 0%,
+ 59.999%,
+ 85%,
100% {
opacity: 0;
}
+ 60%,
+ 84.999% {
+ opacity: 1;
+ }
}
.report-ready {
@@ -1071,11 +1109,8 @@ textarea {
.toast {
animation: none;
}
- .term-spinner__frame {
+ .term-spinner__arc {
animation: none;
- opacity: 0;
- }
- .term-spinner__frame:first-child {
opacity: 1;
}
}