@mdbase-dev/ui 0.1.0-beta.123 → 0.1.0-beta.124
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/README.md +66 -1
- package/css/brand.css +27 -24
- package/css/feedback.css +62 -0
- package/css/motion.css +238 -130
- package/css/screens.css +1 -1
- package/dist/AppSwitcher.d.ts +3 -0
- package/dist/AppSwitcher.js +14 -1
- package/dist/Dialog.js +1 -1
- package/dist/Feedback.d.ts +27 -0
- package/dist/Feedback.js +247 -0
- package/dist/FeedbackMarkup.d.ts +18 -0
- package/dist/FeedbackMarkup.js +136 -0
- package/dist/FeedbackVerification.d.ts +21 -0
- package/dist/FeedbackVerification.js +76 -0
- package/dist/SaveNotice.d.ts +7 -1
- package/dist/SaveNotice.js +32 -0
- package/dist/brand.d.ts +32 -23
- package/dist/brand.js +80 -34
- package/dist/feedback-data.d.ts +75 -0
- package/dist/feedback-data.js +200 -0
- package/dist/mark-activity.d.ts +39 -0
- package/dist/mark-activity.js +121 -0
- package/dist/screens.d.ts +3 -2
- package/dist/screens.js +6 -4
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -22,7 +22,72 @@ applyThemePreference(loadThemePreference());
|
|
|
22
22
|
as `--ink` belong to each app.
|
|
23
23
|
- `theme` stores the System, Light or Dark choice as `mdbase:theme`.
|
|
24
24
|
- `brand` draws the Frontmatter mark, each app's inverted mark, and the
|
|
25
|
-
`mdbase <app>` wordmark. Add `motion.css` to animate the mark
|
|
25
|
+
`mdbase <app>` wordmark. Add `motion.css` to animate the mark: loops
|
|
26
|
+
(`orbit`, `scan`, `bounce`, `stream`, `sort`, `hop`), entrances
|
|
27
|
+
(`keys-first`, `drop`, `assemble`), one-shot `saved`/`error` signals, and a
|
|
28
|
+
`progress` fill.
|
|
29
|
+
- `mark-activity` is the page-wide store behind the app switcher's mark.
|
|
30
|
+
`SaveNotice` already reports saves and problems to it. For other work, call
|
|
31
|
+
`signalMdbaseMark("saved" | "error")` when a write the person made finishes,
|
|
32
|
+
`trackMdbaseMarkProgress()` (or `useMdbaseMarkProgress(fraction)`) when the
|
|
33
|
+
total is known, and `holdMdbaseMarkBusy(loop)` (or `useMdbaseMarkBusy`) while
|
|
34
|
+
it is not.
|
|
26
35
|
- `apps` lists the mdbase apps and builds links that open the current
|
|
27
36
|
collection in another app. Lab and local builds pass their own URLs to
|
|
28
37
|
`withAppUrls`.
|
|
38
|
+
|
|
39
|
+
## Shared feedback
|
|
40
|
+
|
|
41
|
+
Import `@mdbase-dev/ui/feedback` and `@mdbase-dev/ui/feedback.css`, alongside
|
|
42
|
+
`tokens.css` and `controls.css`. Place one `FeedbackProvider` above the app shell
|
|
43
|
+
(and its error boundary); place `FeedbackButton` in a quiet, accessible shell
|
|
44
|
+
location. `useFeedback().open("problem")` opens the same form from an error action.
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { FeedbackButton, FeedbackProvider, feedbackApplication,
|
|
48
|
+
resolveFeedbackEndpoint, useFeedback } from "@mdbase-dev/ui/feedback";
|
|
49
|
+
import "@mdbase-dev/ui/feedback.css";
|
|
50
|
+
|
|
51
|
+
<FeedbackProvider
|
|
52
|
+
endpoint={resolveFeedbackEndpoint(configuredFeedbackUrl, development)}
|
|
53
|
+
application={feedbackApplication("mdbase reader", "library", revision, environment)}
|
|
54
|
+
turnstileSiteKey={configuredPublicSiteKey}
|
|
55
|
+
collectionName={optionalCollectionDisplayName}
|
|
56
|
+
>
|
|
57
|
+
<YourAppShell><FeedbackButton /></YourAppShell>
|
|
58
|
+
</FeedbackProvider>;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Products: `mdbase editor`, `mdbase reader`, `mdbase writer`, `mdbase connect`.
|
|
62
|
+
Views must be fixed identifiers, never URLs or document paths. Application/build
|
|
63
|
+
metadata is always included and previewable; reply email, collection name,
|
|
64
|
+
problem diagnostics, and a screenshot are optional. A single, initially collapsed
|
|
65
|
+
**What gets sent** disclosure holds app details and optional diagnostic/collection
|
|
66
|
+
controls, rather than repeating explanations around the form. Collection-name consent
|
|
67
|
+
resets if the name changes. A missing or invalid endpoint hides entry points.
|
|
68
|
+
|
|
69
|
+
For a **user-visible** failure, call `useFeedback().reportError({ code:
|
|
70
|
+
"save_failed" })`. Use the exported `FeedbackErrorCode` union and optional HTTP
|
|
71
|
+
status, not raw errors. Cancellation does nothing; background retries should not
|
|
72
|
+
call it. The bug wiggles twice, at most once per 30 seconds, and never moves with
|
|
73
|
+
reduced motion. It does not install global exception listeners or telemetry.
|
|
74
|
+
|
|
75
|
+
The form opens focused on its description. Capture starts only on **Attach
|
|
76
|
+
screenshot**, closes the native modal before requesting `getDisplayMedia`, then
|
|
77
|
+
restores the form/draft and stops every track. Unsupported browsers can choose an
|
|
78
|
+
image instead. Draw/highlight/blackout, undo/reset, and keyboard markup export one
|
|
79
|
+
flattened raster; blackouts replace whole pixels and are painted last. Uploads
|
|
80
|
+
are bounded PNG/JPEG, dimension-checked before decoding and re-encoded to discard
|
|
81
|
+
metadata and filenames. Only the explicitly included final image is submitted.
|
|
82
|
+
Opening markup excludes the image until Apply; cancelling or failing to apply
|
|
83
|
+
redactions leaves the original excluded unless the user explicitly includes it.
|
|
84
|
+
|
|
85
|
+
Drafts and the 30-event/five-minute diagnostic buffer are in-memory per provider.
|
|
86
|
+
Cancel preserves the draft; successful dismissal clears it. No collection/auth
|
|
87
|
+
SDK, persistence, public issue tracker, or feedback transport other than the
|
|
88
|
+
configured stateless Worker is required. Turnstile loads when the form opens if a
|
|
89
|
+
public key is configured. Submission omits credentials and referrers, retains the
|
|
90
|
+
request ID for unchanged retries, and resets verification tokens after attempts.
|
|
91
|
+
|
|
92
|
+
See [shared-feedback.md](../../docs/shared-feedback.md) for the Worker contract,
|
|
93
|
+
rollout order, integration status, and regression checks.
|
package/css/brand.css
CHANGED
|
@@ -1,47 +1,50 @@
|
|
|
1
|
-
/* The
|
|
1
|
+
/* The Frontmatter mark. `motion.css` animates the same structure when a motion is set. */
|
|
2
2
|
.mdbase-mark {
|
|
3
|
+
--mark-ink: currentColor;
|
|
4
|
+
--mark-accent: var(--color-accent);
|
|
3
5
|
overflow: visible;
|
|
4
6
|
}
|
|
5
7
|
|
|
8
|
+
/* An app mark is inverted: the bars take the app's colour and the line stays ink. */
|
|
9
|
+
.mdbase-app-mark {
|
|
10
|
+
--mark-ink: var(--app);
|
|
11
|
+
--mark-accent: currentColor;
|
|
12
|
+
color: var(--color-text);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.mdbase-app-mark.is-editor { --app: var(--app-editor); }
|
|
16
|
+
.mdbase-app-mark.is-reader { --app: var(--app-reader); }
|
|
17
|
+
.mdbase-app-mark.is-writer { --app: var(--app-writer); }
|
|
18
|
+
|
|
6
19
|
.mdbase-mark .mdbase-mark-segment,
|
|
7
20
|
.mdbase-mark .mdbase-mark-row,
|
|
8
|
-
.mdbase-mark .mdbase-mark-fence
|
|
9
|
-
.mdbase-mark .mdbase-mark-conveyor-track {
|
|
21
|
+
.mdbase-mark .mdbase-mark-fence {
|
|
10
22
|
transform-box: fill-box;
|
|
11
23
|
transform-origin: center;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
.mdbase-mark .mdbase-mark-ink,
|
|
15
|
-
.mdbase-mark .mdbase-mark-
|
|
16
|
-
fill:
|
|
27
|
+
.mdbase-mark .mdbase-mark-track {
|
|
28
|
+
fill: var(--mark-ink);
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
.mdbase-mark .mdbase-mark-accent {
|
|
20
|
-
fill: var(--
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.mdbase-mark .mdbase-mark-conveyor-track {
|
|
24
|
-
opacity: 0;
|
|
25
|
-
transform-box: view-box;
|
|
26
|
-
transform-origin: 0 0;
|
|
32
|
+
fill: var(--mark-accent);
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
/*
|
|
30
|
-
.mdbase-
|
|
31
|
-
|
|
32
|
-
overflow: visible;
|
|
35
|
+
/* Progress: a faint copy keeps the shape visible while the lines fill. */
|
|
36
|
+
.mdbase-mark .mdbase-mark-progress-ghost {
|
|
37
|
+
opacity: 0.22;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
.mdbase-
|
|
36
|
-
|
|
37
|
-
.mdbase-app-mark.is-writer { --app: var(--app-writer); }
|
|
38
|
-
|
|
39
|
-
.mdbase-app-mark-bars {
|
|
40
|
-
fill: var(--app);
|
|
40
|
+
.mdbase-mark .mdbase-mark-progress-fill {
|
|
41
|
+
transition: width 240ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
fill
|
|
44
|
+
@media (prefers-reduced-motion: reduce) {
|
|
45
|
+
.mdbase-mark .mdbase-mark-progress-fill {
|
|
46
|
+
transition: none;
|
|
47
|
+
}
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
.wordmark {
|
package/css/feedback.css
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
.mdbase-feedback-app { display: contents; }
|
|
2
|
+
.mdbase-feedback-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
|
|
3
|
+
.mdbase-feedback-trigger { display: inline-flex; align-items: center; gap: 8px; padding: 8px 10px; border: 0; border-radius: 4px; background: transparent; color: var(--color-text-soft); font: 12px/1.4 var(--sans); cursor: pointer; }
|
|
4
|
+
.mdbase-feedback-trigger:hover { background: var(--color-selected); color: var(--color-text); }
|
|
5
|
+
.mdbase-feedback-bug { width: 22px; height: 22px; flex-shrink: 0; }
|
|
6
|
+
@keyframes mdbase-feedback-wiggle { 0%,100% { transform: rotate(0); } 25% { transform: rotate(-14deg); } 75% { transform: rotate(14deg); } }
|
|
7
|
+
@media (prefers-reduced-motion: no-preference) { .mdbase-feedback-bug.is-wiggling { animation: mdbase-feedback-wiggle 280ms ease-in-out 2; } }
|
|
8
|
+
.mdbase-feedback-dialog { position: fixed; inset: 0 0 0 auto; margin: 0; padding: 0; width: 440px; max-width: 100vw; height: 100dvh; max-height: 100dvh; border: 0; border-left: 1px solid var(--color-border-strong); background: var(--color-canvas); color: var(--color-text); font: 13px/1.5 var(--sans); overflow: hidden; }
|
|
9
|
+
.mdbase-feedback-dialog[open] { display: flex; flex-direction: column; }
|
|
10
|
+
.mdbase-feedback-dialog:not([open]) { display: none; }
|
|
11
|
+
.mdbase-feedback-dialog::backdrop { background: var(--color-scrim); }
|
|
12
|
+
.mdbase-feedback-dialog *, .mdbase-feedback-markup * { box-sizing: border-box; }
|
|
13
|
+
.mdbase-feedback-dialog :is(button,input,textarea), .mdbase-feedback-markup button { font: inherit; }
|
|
14
|
+
.mdbase-feedback-dialog :focus-visible, .mdbase-feedback-markup :focus-visible, .mdbase-feedback-trigger:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }
|
|
15
|
+
.mdbase-feedback-dialog button, .mdbase-feedback-markup .mdbase-feedback-actions button, .mdbase-feedback-tools button { border: 1px solid var(--color-border-strong); border-radius: 4px; padding: 7px 11px; background: var(--color-canvas); color: var(--color-text); cursor: pointer; }
|
|
16
|
+
.mdbase-feedback-dialog button:hover, .mdbase-feedback-markup button:hover { background: var(--color-selected); }
|
|
17
|
+
.mdbase-feedback-dialog button:disabled, .mdbase-feedback-markup button:disabled { opacity: .5; cursor: default; }
|
|
18
|
+
.mdbase-feedback-header { display: flex; justify-content: space-between; align-items: center; gap: 15px; padding: 27px; border-bottom: 1px solid var(--color-border); flex-shrink: 0; }
|
|
19
|
+
.mdbase-feedback-header h2 { font-size: 23px; line-height: 1.25; letter-spacing: -.5px; margin: 0; color: var(--color-text); }
|
|
20
|
+
.mdbase-feedback-header button { border: 0; width: 34px; height: 34px; padding: 0; font-size: 23px; color: var(--color-text-muted); }
|
|
21
|
+
.mdbase-feedback-dialog form { display: flex; flex-direction: column; flex: 1; overflow: hidden; margin: 0; }
|
|
22
|
+
.mdbase-feedback-body { flex: 1; overflow-y: auto; padding: 23px 27px; }
|
|
23
|
+
.mdbase-feedback-topics { display: grid; gap: 6px; border: 0; padding: 0; margin: 0 0 23px; }
|
|
24
|
+
.mdbase-feedback-topics legend { margin-bottom: 10px; font-size: 12px; font-weight: 700; }
|
|
25
|
+
.mdbase-feedback-topics label { display: flex; align-items: center; gap: 9px; padding: 9px 11px; border: 1px solid var(--color-border); border-radius: 4px; font-size: 12px; cursor: pointer; }
|
|
26
|
+
.mdbase-feedback-topics label:has(:checked) { border-color: var(--color-accent); background: var(--color-accent-soft); }
|
|
27
|
+
.mdbase-feedback-dialog input:is([type=radio],[type=checkbox]) { accent-color: var(--color-accent); margin: 0; width: 14px; height: 14px; flex-shrink: 0; }
|
|
28
|
+
.mdbase-feedback-field { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px; font-weight: 700; }
|
|
29
|
+
.mdbase-feedback-field small { margin-left: 6px; font-weight: 400; font-size: 11px; color: var(--color-text-muted); }
|
|
30
|
+
.mdbase-feedback-field :is(input,textarea) { width: 100%; background: var(--color-canvas); border: 1px solid var(--color-border-strong); border-radius: 4px; color: var(--color-text); padding: 10px 11px; font-weight: 400; }
|
|
31
|
+
.mdbase-feedback-field textarea { min-height: 125px; resize: vertical; }
|
|
32
|
+
.mdbase-feedback-field :is(input,textarea)::placeholder { color: var(--color-text-muted); }
|
|
33
|
+
.mdbase-feedback-screenshot { margin: 0 0 20px; }
|
|
34
|
+
.mdbase-feedback-dialog .mdbase-feedback-preview { display: block; position: relative; padding: 0; width: 100%; overflow: hidden; }
|
|
35
|
+
.mdbase-feedback-preview img { display: block; width: 100%; height: 165px; object-fit: contain; }
|
|
36
|
+
.mdbase-feedback-preview span { position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%); background: var(--color-canvas); border: 1px solid var(--color-border-strong); border-radius: 4px; padding: 4px 8px; font-size: 11px; white-space: nowrap; }
|
|
37
|
+
.mdbase-feedback-screenshot-actions { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 10px; font-size: 11px; }
|
|
38
|
+
.mdbase-feedback-screenshot-actions label { display: flex; align-items: center; gap: 7px; }
|
|
39
|
+
.mdbase-feedback-upload { position: relative; color: var(--color-accent); cursor: pointer; padding: 6px 0; }
|
|
40
|
+
.mdbase-feedback-upload input { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }
|
|
41
|
+
.mdbase-feedback-upload:focus-within { outline: 2px solid var(--color-accent); outline-offset: 3px; }
|
|
42
|
+
.mdbase-feedback-check { display: flex; gap: 8px; align-items: center; font-size: 12px; }
|
|
43
|
+
.mdbase-feedback-details > .mdbase-feedback-check { margin: 14px 0 8px; }
|
|
44
|
+
.mdbase-feedback-help { font-size: 11px; line-height: 1.6; color: var(--color-text-muted); margin: 9px 0; }
|
|
45
|
+
.mdbase-feedback-dialog details { font-size: 11px; color: var(--color-text-soft); margin: 12px 0; }
|
|
46
|
+
.mdbase-feedback-dialog summary { cursor: pointer; }
|
|
47
|
+
.mdbase-feedback-dialog pre { font: 11px/1.6 var(--mono); white-space: pre-wrap; overflow-wrap: anywhere; background: var(--color-surface-subtle); padding: 12px; border: 1px solid var(--color-border); border-radius: 4px; }
|
|
48
|
+
.mdbase-feedback-error { color: var(--color-danger); font-size: 12px; }
|
|
49
|
+
.mdbase-feedback-actions { display: flex; justify-content: space-between; align-items: center; gap: 12px; border-top: 1px solid var(--color-border); padding: 18px 27px; flex-shrink: 0; }
|
|
50
|
+
.mdbase-feedback-dialog .mdbase-feedback-primary, .mdbase-feedback-markup .mdbase-feedback-actions .mdbase-feedback-primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-on-accent); }
|
|
51
|
+
.mdbase-feedback-dialog .mdbase-feedback-primary:hover, .mdbase-feedback-markup .mdbase-feedback-actions .mdbase-feedback-primary:hover { background: var(--color-accent-strong); }
|
|
52
|
+
.mdbase-feedback-success { padding: 40px 27px; }
|
|
53
|
+
.mdbase-feedback-success h3 { font-size: 25px; line-height: 1.3; margin: 0 0 17px; }
|
|
54
|
+
.mdbase-feedback-success .mdbase-feedback-primary { margin-top: 20px; }
|
|
55
|
+
.mdbase-feedback-markup { width: min(1100px,calc(100vw - 32px)); max-width: none; max-height: calc(100dvh - 32px); padding: 0; }
|
|
56
|
+
.mdbase-feedback-markup .mdbase-dialog-body { max-height: calc(100dvh - 34px); display: flex; flex-direction: column; overflow: hidden; padding: 20px; }
|
|
57
|
+
.mdbase-feedback-tools { display: flex; gap: 7px; flex-wrap: wrap; margin: 10px 0 15px; }
|
|
58
|
+
.mdbase-feedback-tools button[aria-pressed=true] { background: var(--color-selected); border-color: var(--color-accent); }
|
|
59
|
+
.mdbase-feedback-canvas { background: var(--color-surface-subtle); border: 1px solid var(--color-border); padding: 12px; overflow: auto; display: flex; justify-content: center; align-items: center; min-height: 0; }
|
|
60
|
+
.mdbase-feedback-canvas canvas { display: block; max-width: 100%; max-height: calc(100dvh - 345px); width: auto; height: auto; background: white; touch-action: none; cursor: crosshair; }
|
|
61
|
+
.mdbase-feedback-markup .mdbase-feedback-actions { padding: 15px 0 0; }
|
|
62
|
+
@media (max-width: 600px) { .mdbase-feedback-header { padding: 23px; } .mdbase-feedback-body { padding: 20px 23px; } .mdbase-feedback-actions { padding: 16px 23px; } .mdbase-feedback-tools { gap: 4px; } .mdbase-feedback-tools button { font-size: 11px; padding: 6px 8px; } }
|
package/css/motion.css
CHANGED
|
@@ -1,198 +1,306 @@
|
|
|
1
|
-
/*
|
|
1
|
+
/*
|
|
2
|
+
* Animations for the Frontmatter mark. Base mark styling lives in brand.css.
|
|
3
|
+
* Colours go through --mark-ink and --mark-accent so the platform mark and the
|
|
4
|
+
* inverted app marks share every animation.
|
|
5
|
+
*/
|
|
2
6
|
|
|
3
|
-
/*
|
|
4
|
-
.mdbase-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
/* Each segment's place in reading order, and where assemble scatters it from. */
|
|
8
|
+
.mdbase-mark-segment-1 { --step: 0; --scatter: translate(-18px, -22px) rotate(-24deg); }
|
|
9
|
+
.mdbase-mark-segment-2 { --step: 1; --scatter: translate(6px, -30px) rotate(18deg); }
|
|
10
|
+
.mdbase-mark-segment-3 { --step: 2; --scatter: translate(26px, -18px) rotate(-12deg); }
|
|
11
|
+
.mdbase-mark-segment-4 { --step: 3; --scatter: translate(-30px, 4px) rotate(30deg); }
|
|
12
|
+
.mdbase-mark-segment-5 { --step: 4; --scatter: translate(34px, 6px) rotate(-20deg); }
|
|
13
|
+
.mdbase-mark-segment-6 { --step: 5; --scatter: translate(-24px, 26px) rotate(16deg); }
|
|
14
|
+
.mdbase-mark-segment-7 { --step: 6; --scatter: translate(22px, 30px) rotate(-28deg); }
|
|
15
|
+
.mdbase-mark-segment-8 { --step: 7; --scatter: translate(-14px, 34px) rotate(22deg); }
|
|
16
|
+
.mdbase-mark-segment-9 { --step: 8; --scatter: translate(8px, 40px) rotate(-16deg); }
|
|
17
|
+
.mdbase-mark-segment-10 { --step: 9; --scatter: translate(30px, 24px) rotate(26deg); }
|
|
18
|
+
|
|
19
|
+
/* ---------- Loops ---------- */
|
|
20
|
+
|
|
21
|
+
/* Orbit: the fences run in opposite directions, so the mark reads as turning. */
|
|
22
|
+
.mdbase-motion-orbit .mdbase-mark-fence {
|
|
23
|
+
opacity: 0;
|
|
12
24
|
}
|
|
13
25
|
|
|
14
|
-
.mdbase-motion-
|
|
15
|
-
|
|
16
|
-
animation-name: mdbase-trace-accent;
|
|
26
|
+
.mdbase-motion-orbit .mdbase-mark-track-top {
|
|
27
|
+
animation: mdbase-orbit-right 1.3s linear infinite;
|
|
17
28
|
}
|
|
18
29
|
|
|
19
|
-
.mdbase-motion-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.mdbase-motion-bootstrap .mdbase-mark-segment-5 { --mdbase-trace-delay: 165ms; }
|
|
23
|
-
.mdbase-motion-bootstrap .mdbase-mark-segment-6 { --mdbase-trace-delay: 220ms; }
|
|
24
|
-
.mdbase-motion-bootstrap .mdbase-mark-segment-7 { --mdbase-trace-delay: 260ms; }
|
|
25
|
-
.mdbase-motion-bootstrap .mdbase-mark-segment-8 { --mdbase-trace-delay: 315ms; }
|
|
26
|
-
.mdbase-motion-bootstrap .mdbase-mark-segment-9 { --mdbase-trace-delay: 350ms; }
|
|
27
|
-
.mdbase-motion-bootstrap .mdbase-mark-segment-10 { --mdbase-trace-delay: 385ms; }
|
|
30
|
+
.mdbase-motion-orbit .mdbase-mark-track-bottom {
|
|
31
|
+
animation: mdbase-orbit-left 1.3s linear infinite;
|
|
32
|
+
}
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
@keyframes mdbase-orbit-right {
|
|
35
|
+
from { transform: translateX(0); }
|
|
36
|
+
to { transform: translateX(28px); }
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
mdbase-gap-conveyor 900ms linear 1.12s infinite;
|
|
39
|
+
@keyframes mdbase-orbit-left {
|
|
40
|
+
from { transform: translateX(0); }
|
|
41
|
+
to { transform: translateX(-28px); }
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
stroke-dashoffset: 1;
|
|
44
|
-
stroke-opacity: 1;
|
|
45
|
-
}
|
|
46
|
-
10% { opacity: 1; }
|
|
47
|
-
54% {
|
|
48
|
-
fill: transparent;
|
|
49
|
-
opacity: 1;
|
|
50
|
-
stroke-dashoffset: 0;
|
|
51
|
-
stroke-opacity: 1;
|
|
52
|
-
}
|
|
53
|
-
72%,
|
|
54
|
-
100% {
|
|
55
|
-
fill: currentColor;
|
|
56
|
-
opacity: 1;
|
|
57
|
-
stroke-dashoffset: 0;
|
|
58
|
-
stroke-opacity: 0;
|
|
59
|
-
}
|
|
44
|
+
/* Scan: a brightness band reads the record line by line. */
|
|
45
|
+
.mdbase-motion-scan :is(.mdbase-mark-fence, .mdbase-mark-row) {
|
|
46
|
+
opacity: 0.35;
|
|
47
|
+
animation: mdbase-scan 1.6s cubic-bezier(0.4, 0, 0.2, 1) infinite both;
|
|
60
48
|
}
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
50
|
+
.mdbase-motion-scan .mdbase-mark-row-top { animation-delay: 0.14s; }
|
|
51
|
+
.mdbase-motion-scan .mdbase-mark-row-bottom { animation-delay: 0.28s; }
|
|
52
|
+
.mdbase-motion-scan .mdbase-mark-fence-bottom { animation-delay: 0.42s; }
|
|
53
|
+
|
|
54
|
+
@keyframes mdbase-scan {
|
|
55
|
+
0% { opacity: 0.35; }
|
|
56
|
+
14% { opacity: 1; }
|
|
57
|
+
46%, 100% { opacity: 0.35; }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* Bounce: the fence dashes hop like a typing indicator, the bottom fence mirrored. */
|
|
61
|
+
.mdbase-motion-bounce .mdbase-mark-fence .mdbase-mark-segment {
|
|
62
|
+
animation: mdbase-bounce-up 1.2s cubic-bezier(0.45, 0, 0.55, 1) infinite both;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.mdbase-motion-bounce .mdbase-mark-fence-bottom .mdbase-mark-segment {
|
|
66
|
+
animation-name: mdbase-bounce-down;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.mdbase-motion-bounce :is(.mdbase-mark-segment-2, .mdbase-mark-segment-9) { animation-delay: 0.14s; }
|
|
70
|
+
.mdbase-motion-bounce :is(.mdbase-mark-segment-3, .mdbase-mark-segment-10) { animation-delay: 0.28s; }
|
|
71
|
+
|
|
72
|
+
@keyframes mdbase-bounce-up {
|
|
73
|
+
0%, 40%, 100% { transform: translateY(0); }
|
|
74
|
+
20% { transform: translateY(-5px); }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@keyframes mdbase-bounce-down {
|
|
78
|
+
0%, 40%, 100% { transform: translateY(0); }
|
|
79
|
+
20% { transform: translateY(5px); }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Stream: records pass through the fences, as in a sync. The rows are clipped to the frame. */
|
|
83
|
+
.mdbase-motion-stream .mdbase-mark-row {
|
|
84
|
+
animation: mdbase-stream 2.2s infinite;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.mdbase-motion-stream .mdbase-mark-row-bottom {
|
|
88
|
+
animation-delay: 0.1s;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes mdbase-stream {
|
|
92
|
+
0%, 30% {
|
|
72
93
|
opacity: 1;
|
|
73
|
-
|
|
74
|
-
|
|
94
|
+
transform: translateX(0);
|
|
95
|
+
animation-timing-function: cubic-bezier(0.55, 0, 1, 0.45);
|
|
75
96
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
stroke-opacity: 0;
|
|
97
|
+
48% { opacity: 0; transform: translateX(-44px); }
|
|
98
|
+
48.01% {
|
|
99
|
+
opacity: 0;
|
|
100
|
+
transform: translateX(44px);
|
|
101
|
+
animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
|
|
82
102
|
}
|
|
103
|
+
70%, 100% { opacity: 1; transform: translateX(0); }
|
|
83
104
|
}
|
|
84
105
|
|
|
85
|
-
|
|
86
|
-
|
|
106
|
+
/* Sort: the two fields swap places, one passing behind the other. */
|
|
107
|
+
.mdbase-motion-sort .mdbase-mark-row-top {
|
|
108
|
+
animation: mdbase-sort-top 3s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
|
87
109
|
}
|
|
88
110
|
|
|
89
|
-
|
|
90
|
-
|
|
111
|
+
.mdbase-motion-sort .mdbase-mark-row-bottom {
|
|
112
|
+
animation: mdbase-sort-bottom 3s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
|
91
113
|
}
|
|
92
114
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
115
|
+
@keyframes mdbase-sort-top {
|
|
116
|
+
0%, 15% { opacity: 1; transform: translateY(0); }
|
|
117
|
+
27% { opacity: 0.25; }
|
|
118
|
+
40%, 65% { opacity: 1; transform: translateY(22px); }
|
|
119
|
+
77% { opacity: 0.25; }
|
|
120
|
+
90%, 100% { opacity: 1; transform: translateY(0); }
|
|
96
121
|
}
|
|
97
122
|
|
|
98
|
-
|
|
99
|
-
|
|
123
|
+
@keyframes mdbase-sort-bottom {
|
|
124
|
+
0%, 15% { transform: translateY(0); }
|
|
125
|
+
40%, 65% { transform: translateY(-22px); }
|
|
126
|
+
90%, 100% { transform: translateY(0); }
|
|
100
127
|
}
|
|
101
128
|
|
|
102
|
-
|
|
103
|
-
|
|
129
|
+
/* Hop: the highlight moves from one value to the other and back. */
|
|
130
|
+
.mdbase-motion-hop .mdbase-mark-segment-5 {
|
|
131
|
+
animation: mdbase-hop-from 2.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
|
104
132
|
}
|
|
105
133
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
to { transform: translateY(0) scaleX(1); }
|
|
134
|
+
.mdbase-motion-hop .mdbase-mark-segment-7 {
|
|
135
|
+
animation: mdbase-hop-to 2.6s cubic-bezier(0.65, 0, 0.35, 1) infinite;
|
|
109
136
|
}
|
|
110
137
|
|
|
111
|
-
@keyframes mdbase-
|
|
112
|
-
|
|
113
|
-
|
|
138
|
+
@keyframes mdbase-hop-from {
|
|
139
|
+
0%, 38%, 100% { fill: var(--mark-accent); }
|
|
140
|
+
50%, 88% { fill: var(--mark-ink); }
|
|
114
141
|
}
|
|
115
142
|
|
|
116
|
-
@keyframes mdbase-
|
|
117
|
-
|
|
118
|
-
|
|
143
|
+
@keyframes mdbase-hop-to {
|
|
144
|
+
0%, 38%, 100% { fill: var(--mark-ink); }
|
|
145
|
+
50%, 88% { fill: var(--mark-accent); }
|
|
119
146
|
}
|
|
120
147
|
|
|
121
|
-
/*
|
|
122
|
-
|
|
123
|
-
|
|
148
|
+
/* ---------- Entrances ---------- */
|
|
149
|
+
|
|
150
|
+
/* Keys first: the fences open from their middle dash, keys appear, values extend, and the highlight lands last. */
|
|
151
|
+
.mdbase-motion-keys-first .mdbase-mark-row .mdbase-mark-segment {
|
|
124
152
|
transform-origin: left center;
|
|
125
153
|
}
|
|
126
154
|
|
|
127
|
-
.mdbase-motion-
|
|
128
|
-
|
|
129
|
-
transform-origin: right center;
|
|
155
|
+
.mdbase-motion-keys-first .mdbase-mark-fence .mdbase-mark-segment {
|
|
156
|
+
animation: mdbase-fence-in 420ms cubic-bezier(0.16, 1, 0.3, 1) 100ms 1 both;
|
|
130
157
|
}
|
|
131
158
|
|
|
132
|
-
.mdbase-motion-
|
|
133
|
-
animation:
|
|
159
|
+
.mdbase-motion-keys-first :is(.mdbase-mark-segment-2, .mdbase-mark-segment-9) {
|
|
160
|
+
animation-delay: 0ms;
|
|
134
161
|
}
|
|
135
162
|
|
|
136
|
-
.mdbase-motion-
|
|
137
|
-
animation: mdbase-
|
|
163
|
+
.mdbase-motion-keys-first :is(.mdbase-mark-segment-4, .mdbase-mark-segment-6) {
|
|
164
|
+
animation: mdbase-grow 260ms cubic-bezier(0.16, 1, 0.3, 1) 220ms 1 both;
|
|
138
165
|
}
|
|
139
166
|
|
|
140
|
-
.mdbase-motion-
|
|
141
|
-
animation: mdbase-
|
|
167
|
+
.mdbase-motion-keys-first .mdbase-mark-segment-7 {
|
|
168
|
+
animation: mdbase-grow 480ms cubic-bezier(0.16, 1, 0.3, 1) 380ms 1 both;
|
|
142
169
|
}
|
|
143
170
|
|
|
144
|
-
.mdbase-motion-
|
|
145
|
-
animation:
|
|
171
|
+
.mdbase-motion-keys-first .mdbase-mark-segment-5 {
|
|
172
|
+
animation:
|
|
173
|
+
mdbase-grow 520ms cubic-bezier(0.16, 1, 0.3, 1) 440ms 1 both,
|
|
174
|
+
mdbase-land 600ms ease 820ms 1 both;
|
|
146
175
|
}
|
|
147
176
|
|
|
148
|
-
@keyframes mdbase-
|
|
149
|
-
|
|
150
|
-
|
|
177
|
+
@keyframes mdbase-fence-in {
|
|
178
|
+
from { opacity: 0; transform: scaleX(0); }
|
|
179
|
+
to { opacity: 1; transform: none; }
|
|
151
180
|
}
|
|
152
181
|
|
|
153
|
-
@keyframes mdbase-
|
|
154
|
-
|
|
155
|
-
|
|
182
|
+
@keyframes mdbase-grow {
|
|
183
|
+
from { transform: scaleX(0); }
|
|
184
|
+
to { transform: none; }
|
|
156
185
|
}
|
|
157
186
|
|
|
158
|
-
@keyframes mdbase-
|
|
159
|
-
|
|
160
|
-
|
|
187
|
+
@keyframes mdbase-land {
|
|
188
|
+
from { fill: var(--mark-ink); }
|
|
189
|
+
to { fill: var(--mark-accent); }
|
|
161
190
|
}
|
|
162
191
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
192
|
+
/* Drop: segments fall into place in reading order with a little overshoot. */
|
|
193
|
+
.mdbase-motion-drop .mdbase-mark-segment {
|
|
194
|
+
animation: mdbase-drop 560ms cubic-bezier(0.34, 1.56, 0.64, 1) calc(var(--step) * 45ms) 1 both;
|
|
166
195
|
}
|
|
167
196
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
opacity:
|
|
197
|
+
@keyframes mdbase-drop {
|
|
198
|
+
from { opacity: 0; transform: translateY(-12px); }
|
|
199
|
+
to { opacity: 1; transform: none; }
|
|
171
200
|
}
|
|
172
201
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
animation: mdbase-
|
|
202
|
+
/* Assemble: scattered pieces settle into the record. */
|
|
203
|
+
.mdbase-motion-assemble .mdbase-mark-segment {
|
|
204
|
+
animation: mdbase-assemble 900ms cubic-bezier(0.16, 1, 0.3, 1) calc(var(--step) * 28ms + 28ms) 1 both;
|
|
176
205
|
}
|
|
177
206
|
|
|
178
|
-
@keyframes mdbase-
|
|
179
|
-
from { transform:
|
|
180
|
-
|
|
207
|
+
@keyframes mdbase-assemble {
|
|
208
|
+
from { opacity: 0; transform: var(--scatter) scale(0.7); }
|
|
209
|
+
40% { opacity: 1; }
|
|
210
|
+
to { opacity: 1; transform: none; }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/* ---------- Signals ---------- */
|
|
214
|
+
|
|
215
|
+
/* Saved: the fences press in, the highlight flashes success while it stretches, then settles. */
|
|
216
|
+
.mdbase-signal-saved .mdbase-mark-accent {
|
|
217
|
+
transform-origin: left center;
|
|
218
|
+
animation: mdbase-saved-stretch 640ms cubic-bezier(0.34, 1.56, 0.64, 1) 80ms 1 both;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.mdbase-signal-saved .mdbase-mark-fence-top {
|
|
222
|
+
animation: mdbase-press-top 520ms cubic-bezier(0.34, 1.56, 0.64, 1) 1 both;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.mdbase-signal-saved .mdbase-mark-fence-bottom {
|
|
226
|
+
animation: mdbase-press-bottom 520ms cubic-bezier(0.34, 1.56, 0.64, 1) 1 both;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.mdbase-signal-saved .mdbase-mark-row-bottom {
|
|
230
|
+
animation: mdbase-saved-dim 640ms ease 1 both;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
@keyframes mdbase-press-top {
|
|
234
|
+
40% { transform: translateY(4px); }
|
|
235
|
+
to { transform: none; }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@keyframes mdbase-press-bottom {
|
|
239
|
+
40% { transform: translateY(-4px); }
|
|
240
|
+
to { transform: none; }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@keyframes mdbase-saved-stretch {
|
|
244
|
+
35% { fill: var(--color-success); transform: scaleX(0.8); }
|
|
245
|
+
to { transform: none; }
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@keyframes mdbase-saved-dim {
|
|
249
|
+
30% { opacity: 0.35; }
|
|
250
|
+
to { opacity: 1; }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* Error: the fields shake once and the highlight turns to danger before recovering. */
|
|
254
|
+
.mdbase-signal-error .mdbase-mark-row {
|
|
255
|
+
animation: mdbase-shake 520ms cubic-bezier(0.36, 0.07, 0.19, 0.97) 1 both;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.mdbase-signal-error .mdbase-mark-row-bottom {
|
|
259
|
+
animation-delay: 40ms;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.mdbase-signal-error .mdbase-mark-accent {
|
|
263
|
+
animation: mdbase-danger 1.4s ease 1 both;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@keyframes mdbase-shake {
|
|
267
|
+
15% { transform: translateX(-4px); }
|
|
268
|
+
35% { transform: translateX(4px); }
|
|
269
|
+
55% { transform: translateX(-2.5px); }
|
|
270
|
+
75% { transform: translateX(1.5px); }
|
|
271
|
+
to { transform: none; }
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@keyframes mdbase-danger {
|
|
275
|
+
0%, 60% { fill: var(--color-danger); }
|
|
276
|
+
to { fill: var(--mark-accent); }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* ---------- Hover ---------- */
|
|
280
|
+
|
|
281
|
+
/* Wave: one ripple runs through the resting mark in reading order. */
|
|
282
|
+
:is(.mdbase-app-switcher, .mdbase-mark-hover-host):hover .mdbase-mark-at-rest .mdbase-mark-segment {
|
|
283
|
+
animation: mdbase-wave 420ms cubic-bezier(0.45, 0, 0.55, 1) calc(var(--step) * 30ms) 1 both;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
@keyframes mdbase-wave {
|
|
287
|
+
50% { transform: translateY(-3px); }
|
|
181
288
|
}
|
|
182
289
|
|
|
183
290
|
@media (prefers-reduced-motion: reduce) {
|
|
184
|
-
.mdbase-mark .mdbase-mark-segment,
|
|
185
|
-
.mdbase-mark .mdbase-mark-row,
|
|
186
|
-
.mdbase-mark .mdbase-mark-fence,
|
|
187
|
-
.mdbase-mark .mdbase-mark-conveyor-track {
|
|
291
|
+
.mdbase-mark :is(.mdbase-mark-segment, .mdbase-mark-row, .mdbase-mark-fence, .mdbase-mark-track) {
|
|
188
292
|
animation: none !important;
|
|
189
|
-
filter: none !important;
|
|
190
293
|
opacity: 1;
|
|
191
|
-
stroke: none;
|
|
192
294
|
transform: none !important;
|
|
193
295
|
}
|
|
194
296
|
|
|
195
|
-
|
|
196
|
-
|
|
297
|
+
/* Orbit's moving tracks stand in for the fences; with motion off, show the fences. */
|
|
298
|
+
.mdbase-mark .mdbase-mark-track {
|
|
299
|
+
display: none;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Keep a still cue for a failure, since it carries meaning. */
|
|
303
|
+
.mdbase-signal-error .mdbase-mark-accent {
|
|
304
|
+
fill: var(--color-danger);
|
|
197
305
|
}
|
|
198
306
|
}
|
package/css/screens.css
CHANGED