forked from
slices.network/quickslice
Auto-indexing service and GraphQL API for AT Protocol Records
1/// Backfill Animation Component
2///
3/// Animated SVG showing pulsing ellipses to indicate backfill in progress
4import lustre/attribute
5import lustre/element.{type Element}
6import lustre/element/svg
7
8/// Render the backfill animation SVG
9pub fn view(class: String) -> Element(msg) {
10 svg.svg(
11 [
12 attribute.attribute("viewBox", "0 0 128 128"),
13 attribute.attribute("xmlns", "http://www.w3.org/2000/svg"),
14 attribute.attribute("overflow", "visible"),
15 attribute.class(class),
16 ],
17 [
18 // Define gradients
19 svg.defs([], [
20 svg.linear_gradient(
21 [
22 attribute.id("backfill-board1"),
23 attribute.attribute("x1", "0%"),
24 attribute.attribute("y1", "0%"),
25 attribute.attribute("x2", "100%"),
26 attribute.attribute("y2", "100%"),
27 ],
28 [
29 svg.stop([
30 attribute.attribute("offset", "0%"),
31 attribute.attribute("stop-color", "#FF6347"),
32 attribute.attribute("stop-opacity", "1"),
33 ]),
34 svg.stop([
35 attribute.attribute("offset", "100%"),
36 attribute.attribute("stop-color", "#FF4500"),
37 attribute.attribute("stop-opacity", "1"),
38 ]),
39 ],
40 ),
41 svg.linear_gradient(
42 [
43 attribute.id("backfill-board2"),
44 attribute.attribute("x1", "0%"),
45 attribute.attribute("y1", "0%"),
46 attribute.attribute("x2", "100%"),
47 attribute.attribute("y2", "100%"),
48 ],
49 [
50 svg.stop([
51 attribute.attribute("offset", "0%"),
52 attribute.attribute("stop-color", "#00CED1"),
53 attribute.attribute("stop-opacity", "1"),
54 ]),
55 svg.stop([
56 attribute.attribute("offset", "100%"),
57 attribute.attribute("stop-color", "#4682B4"),
58 attribute.attribute("stop-opacity", "1"),
59 ]),
60 ],
61 ),
62 // Inline style for animations
63 element.element("style", [], [
64 element.text(
65 "
66 .backfill-ellipse1 { animation: backfill-pulse 1.5s ease-in-out infinite; }
67 .backfill-ellipse2 { animation: backfill-pulse 1.5s ease-in-out infinite 0.2s; }
68 .backfill-ellipse3 { animation: backfill-pulse 1.5s ease-in-out infinite 0.4s; }
69 @keyframes backfill-pulse {
70 0%, 100% { transform: scale(1); opacity: 1; }
71 50% { transform: scale(1.1); opacity: 0.8; }
72 }
73 ",
74 ),
75 ]),
76 ]),
77 // Pulsing ellipses
78 svg.g([attribute.attribute("transform", "translate(64, 64)")], [
79 // Top ellipse
80 svg.ellipse([
81 attribute.class("backfill-ellipse1"),
82 attribute.attribute("cx", "0"),
83 attribute.attribute("cy", "-28"),
84 attribute.attribute("rx", "50"),
85 attribute.attribute("ry", "20"),
86 attribute.attribute("fill", "url(#backfill-board1)"),
87 attribute.attribute("style", "transform-origin: 0 -28px;"),
88 ]),
89 // Middle ellipse
90 svg.ellipse([
91 attribute.class("backfill-ellipse2"),
92 attribute.attribute("cx", "0"),
93 attribute.attribute("cy", "0"),
94 attribute.attribute("rx", "60"),
95 attribute.attribute("ry", "20"),
96 attribute.attribute("fill", "url(#backfill-board2)"),
97 attribute.attribute("style", "transform-origin: 0 0;"),
98 ]),
99 // Bottom ellipse
100 svg.ellipse([
101 attribute.class("backfill-ellipse3"),
102 attribute.attribute("cx", "0"),
103 attribute.attribute("cy", "28"),
104 attribute.attribute("rx", "40"),
105 attribute.attribute("ry", "20"),
106 attribute.attribute("fill", "#32CD32"),
107 attribute.attribute("style", "transform-origin: 0 28px;"),
108 ]),
109 ]),
110 ],
111 )
112}