@intility/bifrost-experimental 0.1.0 → 0.2.0
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/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
# @intility/bifrost-experimental
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.2.0
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- d272c33: `TwinkleBackground` has a new `fill` prop for using it inside a `Box` or a card. The dots then cover the whole container, evenly, with no fade. The dot grid is now also centered with a margin to the edges, so the edge of the container no longer cuts a dot in half.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- 75f2bf7: `Backdrop` no longer uses `filter: blur()` for its soft edges. Safari on some Macs drew a dark or light halo around the shade when switching between light and dark mode. The edges now fade with a gradient mask instead.
|
|
12
|
+
|
|
13
|
+
## 0.1.0 - 2026-10-27
|
|
14
|
+
|
|
15
|
+
### First release
|
|
16
|
+
|
|
17
|
+
- 2b88573: New package for experimental, AI-generated components. Adds `TwinkleBackground`, an animated dot-grid background in the Bifrost theme color, `Backdrop`, a soft shaded area that keeps text readable on a busy background, and `FrontpageHeader`, a logo, title and subtitle for the front page of a Platform Manager module. #998
|
|
@@ -17,14 +17,48 @@ span.bfx-backdrop {
|
|
|
17
17
|
z-index: -1;
|
|
18
18
|
pointer-events: none;
|
|
19
19
|
|
|
20
|
-
/*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
/* How far the shade reaches past the content, which is also the width of its
|
|
21
|
+
fade. The horizontal reach is no wider than the page padding, so the shade
|
|
22
|
+
can't reach past the screen edge on small screens. */
|
|
23
|
+
--bfx-backdrop-x: min(var(--bfs32), var(--bfl-page-padding));
|
|
24
|
+
--bfx-backdrop-y: var(--bfs24);
|
|
25
25
|
|
|
26
|
-
/*
|
|
27
|
-
|
|
26
|
+
/* Larger than the content without changing the layout */
|
|
27
|
+
inset: calc(-1 * var(--bfx-backdrop-y)) calc(-1 * var(--bfx-backdrop-x));
|
|
28
|
+
opacity: 0.7;
|
|
29
|
+
|
|
30
|
+
/* Soft edges, so it doesn't look like a box. Each edge eases out over the
|
|
31
|
+
reach, like the tail of a blur, and the two masks are multiplied so the
|
|
32
|
+
corners fade too. A mask rather than filter: blur(), which Safari renders
|
|
33
|
+
with a dark or light halo on some Macs. */
|
|
34
|
+
mask-image:
|
|
35
|
+
linear-gradient(
|
|
36
|
+
to bottom,
|
|
37
|
+
transparent,
|
|
38
|
+
rgba(0, 0, 0, 0.1) calc(var(--bfx-backdrop-y) * 0.25),
|
|
39
|
+
rgba(0, 0, 0, 0.5) calc(var(--bfx-backdrop-y) * 0.5),
|
|
40
|
+
rgba(0, 0, 0, 0.9) calc(var(--bfx-backdrop-y) * 0.75),
|
|
41
|
+
#000 var(--bfx-backdrop-y),
|
|
42
|
+
#000 calc(100% - var(--bfx-backdrop-y)),
|
|
43
|
+
rgba(0, 0, 0, 0.9) calc(100% - var(--bfx-backdrop-y) * 0.75),
|
|
44
|
+
rgba(0, 0, 0, 0.5) calc(100% - var(--bfx-backdrop-y) * 0.5),
|
|
45
|
+
rgba(0, 0, 0, 0.1) calc(100% - var(--bfx-backdrop-y) * 0.25),
|
|
46
|
+
transparent
|
|
47
|
+
),
|
|
48
|
+
linear-gradient(
|
|
49
|
+
to right,
|
|
50
|
+
transparent,
|
|
51
|
+
rgba(0, 0, 0, 0.1) calc(var(--bfx-backdrop-x) * 0.25),
|
|
52
|
+
rgba(0, 0, 0, 0.5) calc(var(--bfx-backdrop-x) * 0.5),
|
|
53
|
+
rgba(0, 0, 0, 0.9) calc(var(--bfx-backdrop-x) * 0.75),
|
|
54
|
+
#000 var(--bfx-backdrop-x),
|
|
55
|
+
#000 calc(100% - var(--bfx-backdrop-x)),
|
|
56
|
+
rgba(0, 0, 0, 0.9) calc(100% - var(--bfx-backdrop-x) * 0.75),
|
|
57
|
+
rgba(0, 0, 0, 0.5) calc(100% - var(--bfx-backdrop-x) * 0.5),
|
|
58
|
+
rgba(0, 0, 0, 0.1) calc(100% - var(--bfx-backdrop-x) * 0.25),
|
|
59
|
+
transparent
|
|
60
|
+
);
|
|
61
|
+
mask-composite: intersect;
|
|
28
62
|
}
|
|
29
63
|
|
|
30
64
|
/* A stacking context, so the title's and subtitle's backdrops sit behind both
|
|
@@ -76,6 +110,10 @@ overlap the title. */
|
|
|
76
110
|
);
|
|
77
111
|
}
|
|
78
112
|
|
|
113
|
+
.bfx-twinkle-background-fill {
|
|
114
|
+
height: 100%;
|
|
115
|
+
}
|
|
116
|
+
|
|
79
117
|
/* Red and green aren't themes. The theme colors have a lightness of 46% to
|
|
80
118
|
55% in light mode and 71% to 90% in dark mode, so the lightness is moved
|
|
81
119
|
into that range where alert (55% dark) and success (85% light) are far off. */
|
|
@@ -5,13 +5,21 @@ export type TwinkleBackgroundProps = {
|
|
|
5
5
|
* @default "theme"
|
|
6
6
|
*/
|
|
7
7
|
color?: "theme" | "teal" | "purple" | "pink" | "yellow" | "red" | "green";
|
|
8
|
+
/**
|
|
9
|
+
* Fills the whole container with evenly spread dots, with no fade, for a
|
|
10
|
+
* background inside a card or a `Box`. By default the dots cover the top 40%
|
|
11
|
+
* of the container and fade out down the page.
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
fill?: boolean;
|
|
8
15
|
};
|
|
9
16
|
/**
|
|
10
17
|
* Animated dot grid in the Bifrost theme color, for the front page of a
|
|
11
18
|
* Platform Manager module. It fades out down the page and reacts to hover and
|
|
12
19
|
* clicks. Render it as the first child of a container with
|
|
13
20
|
* `position: relative` and `isolation: isolate`; it fills the top 40% of that
|
|
14
|
-
* container, behind its content
|
|
21
|
+
* container, behind its content, or all of it with `fill`. No dot is cut off
|
|
22
|
+
* by the edge of the container. Experimental: AI-generated, not reviewed line
|
|
15
23
|
* by line.
|
|
16
24
|
*
|
|
17
25
|
* @see https://bifrost.intility.com/react/experimental/twinkle-background
|
|
@@ -24,5 +32,5 @@ export type TwinkleBackgroundProps = {
|
|
|
24
32
|
* </Backdrop>
|
|
25
33
|
* </div>
|
|
26
34
|
*/
|
|
27
|
-
declare const TwinkleBackground: ({ color }: TwinkleBackgroundProps) => import("react").JSX.Element;
|
|
35
|
+
declare const TwinkleBackground: ({ color, fill, }: TwinkleBackgroundProps) => import("react").JSX.Element;
|
|
28
36
|
export default TwinkleBackground;
|
|
@@ -48,7 +48,8 @@ const within = (rect, x, y) => x >= 0 && x <= rect.width && y >= 0 && y <= rect.
|
|
|
48
48
|
* Platform Manager module. It fades out down the page and reacts to hover and
|
|
49
49
|
* clicks. Render it as the first child of a container with
|
|
50
50
|
* `position: relative` and `isolation: isolate`; it fills the top 40% of that
|
|
51
|
-
* container, behind its content
|
|
51
|
+
* container, behind its content, or all of it with `fill`. No dot is cut off
|
|
52
|
+
* by the edge of the container. Experimental: AI-generated, not reviewed line
|
|
52
53
|
* by line.
|
|
53
54
|
*
|
|
54
55
|
* @see https://bifrost.intility.com/react/experimental/twinkle-background
|
|
@@ -62,18 +63,20 @@ const within = (rect, x, y) => x >= 0 && x <= rect.width && y >= 0 && y <= rect.
|
|
|
62
63
|
* </div>
|
|
63
64
|
*/
|
|
64
65
|
const TwinkleBackground = t0 => {
|
|
65
|
-
const $ = _c(
|
|
66
|
+
const $ = _c(6);
|
|
66
67
|
const {
|
|
67
|
-
color: t1
|
|
68
|
+
color: t1,
|
|
69
|
+
fill: t2
|
|
68
70
|
} = t0;
|
|
69
71
|
const color = t1 === undefined ? "theme" : t1;
|
|
72
|
+
const fill = t2 === undefined ? false : t2;
|
|
70
73
|
const canvasRef = useRef(null);
|
|
71
74
|
const still = useReducedMotion();
|
|
72
75
|
const colorClass = color === "red" || color === "green" ? ` bfx-twinkle-background-${color}` : color === "theme" ? "" : ` bf-theme-${color}`;
|
|
73
|
-
let t2;
|
|
74
76
|
let t3;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
let t4;
|
|
78
|
+
if ($[0] !== fill || $[1] !== still) {
|
|
79
|
+
t3 = () => {
|
|
77
80
|
const canvas = canvasRef.current;
|
|
78
81
|
const ctx = canvas?.getContext("2d");
|
|
79
82
|
if (!canvas || !ctx) {
|
|
@@ -93,7 +96,10 @@ const TwinkleBackground = t0 => {
|
|
|
93
96
|
const clicks = [];
|
|
94
97
|
let w = 0;
|
|
95
98
|
let h = 0;
|
|
96
|
-
let cols =
|
|
99
|
+
let cols = 1;
|
|
100
|
+
let offsetX = 0;
|
|
101
|
+
let offsetY = 0;
|
|
102
|
+
let span = 0;
|
|
97
103
|
let rand = new Float32Array(0);
|
|
98
104
|
const seed = Math.random() * 4294967296 | 0;
|
|
99
105
|
const noise = (col, row, k) => {
|
|
@@ -106,12 +112,12 @@ const TwinkleBackground = t0 => {
|
|
|
106
112
|
let last = 0;
|
|
107
113
|
let raf = 0;
|
|
108
114
|
let visible = false;
|
|
109
|
-
let
|
|
115
|
+
let dotColor = "";
|
|
110
116
|
let base = OPACITY.light;
|
|
111
117
|
let styleAt = -Infinity;
|
|
112
118
|
const readStyle = () => {
|
|
113
119
|
const style = getComputedStyle(canvas);
|
|
114
|
-
|
|
120
|
+
dotColor = style.color;
|
|
115
121
|
base = style.colorScheme.includes("dark") ? OPACITY.dark : OPACITY.light;
|
|
116
122
|
};
|
|
117
123
|
const batches = Array.from({
|
|
@@ -122,12 +128,12 @@ const TwinkleBackground = t0 => {
|
|
|
122
128
|
if (forcedColors.matches || h <= 0) {
|
|
123
129
|
return;
|
|
124
130
|
}
|
|
125
|
-
ctx.fillStyle =
|
|
131
|
+
ctx.fillStyle = dotColor;
|
|
126
132
|
for (let i = 0; i < rand.length; i = i + 2, i) {
|
|
127
133
|
const r1 = rand[i];
|
|
128
134
|
const r2 = rand[i + 1];
|
|
129
|
-
const x = i / 2 % cols * SPACING;
|
|
130
|
-
const y = Math.floor(i / 2 / cols) * SPACING;
|
|
135
|
+
const x = offsetX + i / 2 % cols * SPACING;
|
|
136
|
+
const y = offsetY + Math.floor(i / 2 / cols) * SPACING;
|
|
131
137
|
const tw = 0.5 + 0.5 * Math.sin(clock * 0.48 * (1 + r1 * 3) + r2 * TAU);
|
|
132
138
|
let alpha = MIN_ALPHA + (1 - MIN_ALPHA) * tw * tw;
|
|
133
139
|
let size = 1.4 * (1 - 0.3 * r2) * (0.8 + 0.4 * tw);
|
|
@@ -144,7 +150,7 @@ const TwinkleBackground = t0 => {
|
|
|
144
150
|
alpha = alpha + ring * 2.6;
|
|
145
151
|
size = size + ring * 1.4;
|
|
146
152
|
}
|
|
147
|
-
const fade = y /
|
|
153
|
+
const fade = fill || span <= 0 ? 0 : (y - offsetY) / span;
|
|
148
154
|
alpha = alpha * (1 - fade * fade) * base;
|
|
149
155
|
const step = Math.round(Math.min(1, alpha) * ALPHA_STEPS);
|
|
150
156
|
if (step < 1) {
|
|
@@ -221,9 +227,13 @@ const TwinkleBackground = t0 => {
|
|
|
221
227
|
canvas.width = Math.round(w * dpr);
|
|
222
228
|
canvas.height = Math.round(h * dpr);
|
|
223
229
|
ctx.setTransform(w ? canvas.width / w : 1, 0, 0, h ? canvas.height / h : 1, 0, 0);
|
|
224
|
-
cols = Math.
|
|
230
|
+
cols = Math.max(1, Math.floor(w / SPACING));
|
|
231
|
+
const rows = Math.max(1, Math.floor(h / SPACING));
|
|
232
|
+
span = (rows - 1) * SPACING;
|
|
233
|
+
offsetX = (w - (cols - 1) * SPACING) / 2;
|
|
234
|
+
offsetY = (h - span) / 2;
|
|
225
235
|
rand = Float32Array.from({
|
|
226
|
-
length: cols *
|
|
236
|
+
length: cols * rows * 2
|
|
227
237
|
}, (_, i_1) => noise((i_1 >> 1) % cols, Math.floor(i_1 / 2 / cols), i_1 & 1));
|
|
228
238
|
redraw();
|
|
229
239
|
};
|
|
@@ -299,8 +309,8 @@ const TwinkleBackground = t0 => {
|
|
|
299
309
|
});
|
|
300
310
|
}
|
|
301
311
|
}
|
|
302
|
-
const visibility = new IntersectionObserver(
|
|
303
|
-
const [entry] =
|
|
312
|
+
const visibility = new IntersectionObserver(t5 => {
|
|
313
|
+
const [entry] = t5;
|
|
304
314
|
visible = entry.isIntersecting;
|
|
305
315
|
if (visible) {
|
|
306
316
|
play();
|
|
@@ -341,29 +351,30 @@ const TwinkleBackground = t0 => {
|
|
|
341
351
|
window.removeEventListener("blur", onLeave);
|
|
342
352
|
};
|
|
343
353
|
};
|
|
344
|
-
|
|
345
|
-
$[0] =
|
|
346
|
-
$[1] =
|
|
354
|
+
t4 = [still, fill];
|
|
355
|
+
$[0] = fill;
|
|
356
|
+
$[1] = still;
|
|
347
357
|
$[2] = t3;
|
|
358
|
+
$[3] = t4;
|
|
348
359
|
} else {
|
|
349
|
-
t2 = $[1];
|
|
350
360
|
t3 = $[2];
|
|
361
|
+
t4 = $[3];
|
|
351
362
|
}
|
|
352
|
-
useEffect(
|
|
353
|
-
const
|
|
354
|
-
let
|
|
355
|
-
if ($[
|
|
356
|
-
|
|
363
|
+
useEffect(t3, t4);
|
|
364
|
+
const t5 = `bfx-twinkle-background${fill ? " bfx-twinkle-background-fill" : ""}${colorClass}`;
|
|
365
|
+
let t6;
|
|
366
|
+
if ($[4] !== t5) {
|
|
367
|
+
t6 = /*#__PURE__*/_jsx("canvas", {
|
|
357
368
|
ref: canvasRef,
|
|
358
369
|
"aria-hidden": true,
|
|
359
|
-
className:
|
|
370
|
+
className: t5
|
|
360
371
|
});
|
|
361
|
-
$[3] = t4;
|
|
362
372
|
$[4] = t5;
|
|
373
|
+
$[5] = t6;
|
|
363
374
|
} else {
|
|
364
|
-
|
|
375
|
+
t6 = $[5];
|
|
365
376
|
}
|
|
366
|
-
return
|
|
377
|
+
return t6;
|
|
367
378
|
};
|
|
368
379
|
export default TwinkleBackground;
|
|
369
380
|
function _temp() {
|
package/package.json
CHANGED