@rimelight/ui 0.0.20 → 0.0.22

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.
@@ -1,113 +1,113 @@
1
- ---
2
- import DefaultPageTitle from "@astrojs/starlight/components/PageTitle.astro";
3
- import config from "virtual:rimelight-starlight-addons-config";
4
-
5
- const { copy = true, share = true } = config ?? {};
6
- ---
7
-
8
- <DefaultPageTitle />
9
- {(copy || share) && (
10
- <div class="rl-addons">
11
- {copy && (
12
- <button class="rl-addon-btn" id="rl-copy-markdown" title="Copy Markdown">
13
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
14
- </button>
15
- )}
16
- {share && (
17
- <button class="rl-addon-btn" id="rl-share" title="Share">
18
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg>
19
- </button>
20
- )}
21
- </div>
22
- )}
23
-
24
- <style>
25
- .rl-addons {
26
- display: flex;
27
- gap: 0.5rem;
28
- align-items: center;
29
- }
30
-
31
- .rl-addon-btn {
32
- background-color: var(--sl-color-gray-6);
33
- color: var(--sl-color-white);
34
- border: 1px solid var(--sl-color-gray-5);
35
- padding: 0.5rem;
36
- border-radius: 0.25rem;
37
- cursor: pointer;
38
- display: flex;
39
- align-items: center;
40
- justify-content: center;
41
- transition: background-color 0.2s ease;
42
- height: 2rem;
43
- width: 2rem;
44
- }
45
-
46
- .rl-addon-btn:hover {
47
- background-color: var(--sl-color-gray-5);
48
- }
49
-
50
- .rl-addon-btn:disabled {
51
- opacity: 0.7;
52
- cursor: not-allowed;
53
- }
54
- </style>
55
-
56
- <script>
57
- import TurndownService from "turndown";
58
- import { gfm } from "turndown-plugin-gfm";
59
-
60
- const turndown = new TurndownService({
61
- headingStyle: "atx",
62
- codeBlockStyle: "fenced",
63
- bulletListMarker: "-",
64
- });
65
- turndown.use(gfm);
66
-
67
- const copyBtn = document.getElementById("rl-copy-markdown") as HTMLButtonElement | null;
68
- const shareBtn = document.getElementById("rl-share");
69
-
70
- if (copyBtn) {
71
- copyBtn.addEventListener("click", async () => {
72
- try {
73
- copyBtn.disabled = true;
74
- const contentEl = document.querySelector("main .sl-markdown-content");
75
- if (!contentEl) {
76
- throw new Error("Content not found");
77
- }
78
- const clone = contentEl.cloneNode(true) as Element;
79
- clone.querySelectorAll("script, style, noscript, .sl-anchor-link, [data-pagefind-ignore]").forEach((el: Element) => el.remove());
80
- const markdown = turndown.turndown(clone as HTMLElement);
81
- await navigator.clipboard.writeText(markdown);
82
- copyBtn.classList.add("copied");
83
- setTimeout(() => copyBtn.classList.remove("copied"), 2000);
84
- } catch (err) {
85
- console.error("Failed to copy:", err);
86
- } finally {
87
- copyBtn.disabled = false;
88
- }
89
- });
90
- }
91
-
92
- const typedShareBtn = shareBtn as HTMLButtonElement | null;
93
- if (typedShareBtn) {
94
- typedShareBtn.addEventListener("click", async () => {
95
- if (navigator.share) {
96
- try {
97
- await navigator.share({ title: document.title, url: window.location.href });
98
- } catch (err) {
99
- const error = err as { name?: string };
100
- if (error.name !== "AbortError") {
101
- console.error("Share failed:", err);
102
- }
103
- }
104
- } else {
105
- try {
106
- await navigator.clipboard.writeText(window.location.href);
107
- } catch (err) {
108
- console.error("Failed to copy link:", err);
109
- }
110
- }
111
- });
112
- }
1
+ ---
2
+ import DefaultPageTitle from "@astrojs/starlight/components/PageTitle.astro";
3
+ import config from "virtual:rimelight-starlight-addons-config";
4
+
5
+ const { copy = true, share = true } = config ?? {};
6
+ ---
7
+
8
+ <DefaultPageTitle />
9
+ {(copy || share) && (
10
+ <div class="rl-addons">
11
+ {copy && (
12
+ <button class="rl-addon-btn" id="rl-copy-markdown" title="Copy Markdown">
13
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>
14
+ </button>
15
+ )}
16
+ {share && (
17
+ <button class="rl-addon-btn" id="rl-share" title="Share">
18
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" x2="15.42" y1="13.51" y2="17.49"/><line x1="15.41" x2="8.59" y1="6.51" y2="10.49"/></svg>
19
+ </button>
20
+ )}
21
+ </div>
22
+ )}
23
+
24
+ <style>
25
+ .rl-addons {
26
+ display: flex;
27
+ gap: 0.5rem;
28
+ align-items: center;
29
+ }
30
+
31
+ .rl-addon-btn {
32
+ background-color: var(--sl-color-gray-6);
33
+ color: var(--sl-color-white);
34
+ border: 1px solid var(--sl-color-gray-5);
35
+ padding: 0.5rem;
36
+ border-radius: 0.25rem;
37
+ cursor: pointer;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ transition: background-color 0.2s ease;
42
+ height: 2rem;
43
+ width: 2rem;
44
+ }
45
+
46
+ .rl-addon-btn:hover {
47
+ background-color: var(--sl-color-gray-5);
48
+ }
49
+
50
+ .rl-addon-btn:disabled {
51
+ opacity: 0.7;
52
+ cursor: not-allowed;
53
+ }
54
+ </style>
55
+
56
+ <script>
57
+ import TurndownService from "turndown";
58
+ import { gfm } from "turndown-plugin-gfm";
59
+
60
+ const turndown = new TurndownService({
61
+ headingStyle: "atx",
62
+ codeBlockStyle: "fenced",
63
+ bulletListMarker: "-",
64
+ });
65
+ turndown.use(gfm);
66
+
67
+ const copyBtn = document.getElementById("rl-copy-markdown") as HTMLButtonElement | null;
68
+ const shareBtn = document.getElementById("rl-share");
69
+
70
+ if (copyBtn) {
71
+ copyBtn.addEventListener("click", async () => {
72
+ try {
73
+ copyBtn.disabled = true;
74
+ const contentEl = document.querySelector("main .sl-markdown-content");
75
+ if (!contentEl) {
76
+ throw new Error("Content not found");
77
+ }
78
+ const clone = contentEl.cloneNode(true) as Element;
79
+ clone.querySelectorAll("script, style, noscript, .sl-anchor-link, [data-pagefind-ignore]").forEach((el: Element) => el.remove());
80
+ const markdown = turndown.turndown(clone as HTMLElement);
81
+ await navigator.clipboard.writeText(markdown);
82
+ copyBtn.classList.add("copied");
83
+ setTimeout(() => copyBtn.classList.remove("copied"), 2000);
84
+ } catch (err) {
85
+ console.error("Failed to copy:", err);
86
+ } finally {
87
+ copyBtn.disabled = false;
88
+ }
89
+ });
90
+ }
91
+
92
+ const typedShareBtn = shareBtn as HTMLButtonElement | null;
93
+ if (typedShareBtn) {
94
+ typedShareBtn.addEventListener("click", async () => {
95
+ if (navigator.share) {
96
+ try {
97
+ await navigator.share({ title: document.title, url: window.location.href });
98
+ } catch (err) {
99
+ const error = err as { name?: string };
100
+ if (error.name !== "AbortError") {
101
+ console.error("Share failed:", err);
102
+ }
103
+ }
104
+ } else {
105
+ try {
106
+ await navigator.clipboard.writeText(window.location.href);
107
+ } catch (err) {
108
+ console.error("Failed to copy link:", err);
109
+ }
110
+ }
111
+ });
112
+ }
113
113
  </script>
@@ -0,0 +1,180 @@
1
+ ---
2
+
3
+ interface HighlightGroup {
4
+ label: string
5
+ buttons: string[]
6
+ color: string
7
+ }
8
+
9
+ interface Props {
10
+ highlightedButtons?: string[]
11
+ groups?: HighlightGroup[]
12
+ highlightColor?: string
13
+ backgroundColor?: string
14
+ }
15
+
16
+ const {
17
+ highlightedButtons = [],
18
+ groups = [],
19
+ highlightColor = 'var(--ui-color-primary-500, #00c16a)',
20
+ backgroundColor = 'transparent'
21
+ } = Astro.props
22
+
23
+ function getButtonHighlight(buttonId: string) {
24
+ if (highlightedButtons.includes(buttonId)) {
25
+ return { active: true, color: highlightColor }
26
+ }
27
+ for (const group of groups) {
28
+ if (group.buttons.includes(buttonId)) {
29
+ return { active: true, color: group.color }
30
+ }
31
+ }
32
+ return { active: false, color: undefined }
33
+ }
34
+
35
+ interface Button {
36
+ id: string
37
+ label?: string
38
+ x: number
39
+ y: number
40
+ r?: number
41
+ w?: number
42
+ h?: number
43
+ type?: string
44
+ }
45
+
46
+ const shoulderButtons: Button[] = [
47
+ { id: 'L2', label: 'LT', x: 65, y: 10, w: 80, h: 22 },
48
+ { id: 'L1', label: 'LB', x: 65, y: 42, w: 80, h: 22 },
49
+ { id: 'R2', label: 'RT', x: 255, y: 10, w: 80, h: 22 },
50
+ { id: 'R1', label: 'RB', x: 255, y: 42, w: 80, h: 22 },
51
+ ]
52
+
53
+ const mainButtons: Button[] = [
54
+ // Face Buttons (Smaller, tighter)
55
+ { id: 'Y', label: 'Y', x: 315, y: 125, r: 12 },
56
+ { id: 'X', label: 'X', x: 288, y: 152, r: 12 },
57
+ { id: 'B', label: 'B', x: 342, y: 152, r: 12 },
58
+ { id: 'A', label: 'A', x: 315, y: 179, r: 12 },
59
+
60
+ // D-Pad (Refined)
61
+ { id: 'DPadUp', x: 85, y: 130, w: 20, h: 20, type: 'dpad' },
62
+ { id: 'DPadDown', x: 85, y: 174, w: 20, h: 20, type: 'dpad' },
63
+ { id: 'DPadLeft', x: 63, y: 152, w: 20, h: 20, type: 'dpad' },
64
+ { id: 'DPadRight', x: 107, y: 152, w: 20, h: 20, type: 'dpad' },
65
+
66
+ // Sticks (Smaller, proportional)
67
+ { id: 'LS', x: 155, y: 215, r: 24 },
68
+ { id: 'RS', x: 245, y: 215, r: 24 },
69
+
70
+ // Menu Buttons
71
+ { id: 'View', label: '⧉', x: 145, y: 105, w: 16, h: 10 },
72
+ { id: 'Menu', label: '≡', x: 239, y: 105, w: 16, h: 10 },
73
+ ]
74
+ ---
75
+
76
+ <div class="gamepad-wrapper">
77
+ <div class="gamepad-container">
78
+ <svg viewBox="-20 -20 440 380" class="gamepad-svg">
79
+ <defs>
80
+ <linearGradient id="bodyGrad" x1="0%" y1="0%" x2="0%" y2="100%">
81
+ <stop offset="0%" stop-color="#2a2a40" stop-opacity="1" />
82
+ <stop offset="100%" stop-color="#1a1a2e" stop-opacity="1" />
83
+ </linearGradient>
84
+ </defs>
85
+
86
+ {backgroundColor && backgroundColor !== 'transparent' && (
87
+ <rect x="-20" y="-20" width="440" height="360" fill={backgroundColor} rx="24" />
88
+ )}
89
+
90
+ <!-- Shoulder Buttons -->
91
+ {shoulderButtons.map(btn => {
92
+ const highlight = getButtonHighlight(btn.id);
93
+ const w = btn.w || 0;
94
+ const h = btn.h || 0;
95
+ const color = highlight.active ? (highlight.color || highlightColor) : '#1e1e30';
96
+
97
+ return (
98
+ <g class={`gp-btn shoulder ${highlight.active ? 'active' : ''}`}>
99
+ <rect
100
+ x={btn.x}
101
+ y={btn.y}
102
+ width={w}
103
+ height={h}
104
+ rx="5"
105
+ fill={color}
106
+ stroke={highlight.active ? "#ffffff33" : "#33334d"}
107
+ stroke-width={highlight.active ? "1.5" : "1"}
108
+ />
109
+ <text x={btn.x + w/2} y={btn.y + h/2} text-anchor="middle" dominant-baseline="central" class="btn-label" fill={highlight.active ? "#fff" : "#555570"}>{btn.label}</text>
110
+ </g>
111
+ )
112
+ })}
113
+
114
+ <!-- Controller Body -->
115
+ <path
116
+ d="M120,85 L280,85 C320,85 340,95 350,115 C370,145 390,215 390,245 C390,285 360,315 320,315 C290,315 260,285 240,255 C220,245 180,245 160,255 C140,285 110,315 80,315 C40,315 10,285 10,245 C10,215 30,145 50,115 C60,95 80,85 120,85 Z"
117
+ fill="url(#bodyGrad)"
118
+ stroke="#33334d"
119
+ stroke-width="1"
120
+ />
121
+
122
+ <!-- Touchpad -->
123
+ <path d="M145,90 L255,90 L262,150 L138,150 Z" fill="#151525" stroke="#33334d" stroke-width="0.5" />
124
+
125
+ {mainButtons.map(btn => {
126
+ const highlight = getButtonHighlight(btn.id);
127
+ const color = highlight.active ? (highlight.color || highlightColor) : '#1e1e30';
128
+
129
+ if (btn.r) {
130
+ return (
131
+ <g class={`gp-btn ${highlight.active ? 'active' : ''}`}>
132
+ <circle
133
+ cx={btn.x}
134
+ cy={btn.y}
135
+ r={btn.r}
136
+ fill={color}
137
+ stroke={highlight.active ? "#ffffff33" : "#33334d"}
138
+ stroke-width={highlight.active ? "1.5" : "1"}
139
+ />
140
+ {btn.label && <text x={btn.x} y={btn.y} text-anchor="middle" dominant-baseline="central" class="btn-label" fill={highlight.active ? "#fff" : "#555570"}>{btn.label}</text>}
141
+ </g>
142
+ )
143
+ }
144
+
145
+ const w = btn.w || 0;
146
+ const h = btn.h || 0;
147
+ return (
148
+ <g class={`gp-btn ${highlight.active ? 'active' : ''}`}>
149
+ <rect
150
+ x={btn.x}
151
+ y={btn.y}
152
+ width={w}
153
+ height={h}
154
+ rx="3"
155
+ fill={color}
156
+ stroke={highlight.active ? "#ffffff33" : "#33334d"}
157
+ stroke-width={highlight.active ? "1.5" : "1"}
158
+ />
159
+ {btn.label && <text x={btn.x + w/2} y={btn.y + h/2} text-anchor="middle" dominant-baseline="central" class="btn-label" fill={highlight.active ? "#fff" : "#555570"}>{btn.label}</text>}
160
+ </g>
161
+ )
162
+ })}
163
+
164
+ </svg>
165
+ </div>
166
+
167
+ {groups.some(g => g.label) && (
168
+ <div class="flex flex-wrap justify-center gap-x-6 gap-y-3 mt-10 w-full">
169
+ {groups.filter(g => g.label).map(group => (
170
+ <div class="flex items-center gap-2 m-0 p-0 h-[10px] text-[10px] text-[#777790] uppercase tracking-[0.1em] font-bold leading-[10px]">
171
+ <svg width="8" height="8" class="flex-shrink-0 block">
172
+ <rect width="8" height="8" rx="2" fill={group.color} />
173
+ </svg>
174
+ <span class="inline-block h-[10px] leading-[10px] m-0 p-0">{group.label}</span>
175
+ </div>
176
+ ))}
177
+ </div>
178
+ )}
179
+ </div>
180
+