radiant-docs 0.1.20 → 0.1.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.
package/package.json
CHANGED
|
@@ -56,170 +56,175 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
56
56
|
<div data-rd-code-group-content class="min-w-0">
|
|
57
57
|
<slot />
|
|
58
58
|
</div>
|
|
59
|
-
|
|
59
|
+
<script is:inline>
|
|
60
|
+
(() => {
|
|
61
|
+
const script = document.currentScript;
|
|
62
|
+
if (!(script instanceof HTMLScriptElement)) return;
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const script = document.currentScript;
|
|
64
|
-
if (!(script instanceof HTMLScriptElement)) return;
|
|
64
|
+
const root = script.closest("[data-rd-code-group-root='true']");
|
|
65
|
+
if (!(root instanceof HTMLElement)) return;
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
const contentElement = root.querySelector("[data-rd-code-group-content]");
|
|
68
|
+
const tabsElement = root.querySelector("[data-rd-code-group-tabs]");
|
|
69
|
+
const pillElement = root.querySelector("[data-rd-code-group-pill]");
|
|
70
|
+
const copyButton = root.querySelector("[data-rd-copy-trigger='true']");
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
const tabsElement = root.querySelector("[data-rd-code-group-tabs]");
|
|
71
|
-
const pillElement = root.querySelector("[data-rd-code-group-pill]");
|
|
72
|
-
const copyButton = root.querySelector("[data-rd-copy-trigger='true']");
|
|
72
|
+
if (!contentElement || !tabsElement || !pillElement) return;
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
const codeItems = Array.from(
|
|
75
|
+
contentElement.querySelectorAll("[data-rd-code-group-item='true']"),
|
|
76
|
+
);
|
|
77
|
+
if (codeItems.length === 0) return;
|
|
75
78
|
|
|
76
|
-
|
|
77
|
-
contentElement.querySelectorAll("[data-rd-code-group-item='true']"),
|
|
78
|
-
);
|
|
79
|
-
if (codeItems.length === 0) return;
|
|
79
|
+
let activeIndex = 0;
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
const setCopiedState = (button, copied) => {
|
|
82
|
+
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
83
|
+
const checkIcon = button.querySelector("[data-rd-copy-check]");
|
|
84
|
+
if (!copyIcon || !checkIcon) return;
|
|
82
85
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (!copyIcon || !checkIcon) return;
|
|
86
|
+
if (copied) {
|
|
87
|
+
copyIcon.classList.add("scale-50", "opacity-0", "-rotate-6");
|
|
88
|
+
copyIcon.classList.remove("scale-100", "opacity-100", "rotate-0");
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
checkIcon.classList.remove("scale-50", "opacity-0", "rotate-6");
|
|
91
|
+
checkIcon.classList.add("scale-110", "opacity-100", "rotate-0");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
95
|
+
copyIcon.classList.remove("scale-50", "opacity-0", "-rotate-6");
|
|
96
|
+
copyIcon.classList.add("scale-100", "opacity-100", "rotate-0");
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
checkIcon.classList.remove("scale-110", "opacity-100", "rotate-0");
|
|
99
|
+
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
100
|
+
};
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
const tabs = codeItems.map((itemElement, index) => {
|
|
103
|
+
const filename =
|
|
104
|
+
itemElement.getAttribute("data-rd-tab-filename") ??
|
|
105
|
+
`file-name-${index + 1}.txt`;
|
|
106
|
+
const hideTabIcon =
|
|
107
|
+
itemElement.getAttribute("data-rd-tab-hide-icon") === "true";
|
|
108
|
+
const tabIconTemplate = itemElement.querySelector(
|
|
109
|
+
"template[data-rd-code-group-tab-icon]",
|
|
110
|
+
);
|
|
111
|
+
const hasTabIcon =
|
|
112
|
+
!hideTabIcon &&
|
|
113
|
+
!!tabIconTemplate &&
|
|
114
|
+
tabIconTemplate.innerHTML.trim().length > 0;
|
|
115
|
+
|
|
116
|
+
const tabWrapper = document.createElement("div");
|
|
117
|
+
tabWrapper.className = "relative z-10 text-xs font-medium";
|
|
118
|
+
|
|
119
|
+
const tabButton = document.createElement("button");
|
|
120
|
+
tabButton.type = "button";
|
|
121
|
+
tabButton.className =
|
|
122
|
+
`relative inline-flex h-9 items-center border-0 bg-transparent px-3 py-1.5 text-xs font-medium text-neutral-600 transition-colors duration-150 focus:outline-none focus-visible:outline-none cursor-pointer ${hasTabIcon ? "gap-2" : ""}`;
|
|
123
|
+
tabButton.setAttribute("aria-label", filename);
|
|
124
|
+
tabButton.setAttribute("data-rd-code-group-tab", String(index));
|
|
125
|
+
|
|
126
|
+
let iconContainer = null;
|
|
127
|
+
if (hasTabIcon) {
|
|
128
|
+
iconContainer = document.createElement("span");
|
|
129
|
+
iconContainer.className =
|
|
130
|
+
"pointer-events-none inline-flex shrink-0 items-center rounded-[4px] transition-opacity duration-150";
|
|
131
|
+
iconContainer.innerHTML = tabIconTemplate.innerHTML;
|
|
132
|
+
}
|
|
103
133
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
`file-name-${index + 1}.txt`;
|
|
108
|
-
const tabIconTemplate = itemElement.querySelector(
|
|
109
|
-
"template[data-rd-code-group-tab-icon]",
|
|
110
|
-
);
|
|
134
|
+
const labelElement = document.createElement("span");
|
|
135
|
+
labelElement.className = "whitespace-pre leading-none";
|
|
136
|
+
labelElement.textContent = filename;
|
|
111
137
|
|
|
112
|
-
|
|
113
|
-
|
|
138
|
+
if (iconContainer) {
|
|
139
|
+
tabButton.appendChild(iconContainer);
|
|
140
|
+
}
|
|
141
|
+
tabButton.appendChild(labelElement);
|
|
142
|
+
tabWrapper.appendChild(tabButton);
|
|
143
|
+
tabsElement.appendChild(tabWrapper);
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
itemElement,
|
|
147
|
+
tabWrapper,
|
|
148
|
+
tabButton,
|
|
149
|
+
iconContainer,
|
|
150
|
+
};
|
|
151
|
+
});
|
|
114
152
|
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
153
|
+
const syncPill = () => {
|
|
154
|
+
const activeTab = tabs[activeIndex]?.tabWrapper;
|
|
155
|
+
if (!activeTab) {
|
|
156
|
+
pillElement.classList.add("opacity-0");
|
|
157
|
+
pillElement.classList.remove("opacity-100");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
121
160
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
161
|
+
const activeRect = activeTab.getBoundingClientRect();
|
|
162
|
+
const tabsRect = tabsElement.getBoundingClientRect();
|
|
163
|
+
const left = activeRect.left - tabsRect.left + tabsElement.scrollLeft;
|
|
164
|
+
const width = activeRect.width;
|
|
165
|
+
pillElement.style.left = `${left}px`;
|
|
166
|
+
pillElement.style.width = `${width}px`;
|
|
167
|
+
pillElement.classList.remove("opacity-0");
|
|
168
|
+
pillElement.classList.add("opacity-100");
|
|
169
|
+
};
|
|
125
170
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
171
|
+
const syncActiveTab = () => {
|
|
172
|
+
tabs.forEach(({ itemElement, tabButton, iconContainer }, index) => {
|
|
173
|
+
const isActive = index === activeIndex;
|
|
174
|
+
itemElement.style.display = isActive ? "" : "none";
|
|
175
|
+
tabButton.classList.toggle("text-neutral-900", isActive);
|
|
176
|
+
tabButton.classList.toggle("text-neutral-600", !isActive);
|
|
177
|
+
|
|
178
|
+
if (!iconContainer) return;
|
|
179
|
+
iconContainer.classList.toggle("opacity-100", isActive);
|
|
180
|
+
iconContainer.classList.toggle("opacity-80", !isActive);
|
|
181
|
+
});
|
|
182
|
+
syncPill();
|
|
183
|
+
};
|
|
131
184
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
185
|
+
tabs.forEach(({ tabButton }, index) => {
|
|
186
|
+
tabButton.addEventListener("click", () => {
|
|
187
|
+
if (activeIndex === index) return;
|
|
188
|
+
activeIndex = index;
|
|
189
|
+
syncActiveTab();
|
|
190
|
+
});
|
|
191
|
+
});
|
|
135
192
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
193
|
+
if (copyButton) {
|
|
194
|
+
let timeoutId = null;
|
|
195
|
+
copyButton.addEventListener("click", async () => {
|
|
196
|
+
const activeItem = tabs[activeIndex]?.itemElement;
|
|
197
|
+
const encodedCopyValue =
|
|
198
|
+
activeItem?.getAttribute("data-rd-copy-content") ?? "";
|
|
199
|
+
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
await navigator.clipboard.writeText(copyValue);
|
|
203
|
+
setCopiedState(copyButton, true);
|
|
204
|
+
|
|
205
|
+
if (timeoutId) window.clearTimeout(timeoutId);
|
|
206
|
+
timeoutId = window.setTimeout(() => {
|
|
207
|
+
setCopiedState(copyButton, false);
|
|
208
|
+
timeoutId = null;
|
|
209
|
+
}, 1200);
|
|
210
|
+
} catch {
|
|
211
|
+
setCopiedState(copyButton, false);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
140
215
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const syncPill = () => {
|
|
150
|
-
const activeTab = tabs[activeIndex]?.tabWrapper;
|
|
151
|
-
if (!activeTab) {
|
|
152
|
-
pillElement.classList.add("opacity-0");
|
|
153
|
-
pillElement.classList.remove("opacity-100");
|
|
154
|
-
return;
|
|
216
|
+
const resizeObserver =
|
|
217
|
+
typeof ResizeObserver !== "undefined"
|
|
218
|
+
? new ResizeObserver(() => syncPill())
|
|
219
|
+
: null;
|
|
220
|
+
if (resizeObserver) {
|
|
221
|
+
resizeObserver.observe(tabsElement);
|
|
155
222
|
}
|
|
156
223
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
pillElement.classList.add("opacity-100");
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const syncActiveTab = () => {
|
|
168
|
-
tabs.forEach(({ itemElement, tabButton, iconContainer }, index) => {
|
|
169
|
-
const isActive = index === activeIndex;
|
|
170
|
-
itemElement.style.display = isActive ? "" : "none";
|
|
171
|
-
tabButton.classList.toggle("text-neutral-900", isActive);
|
|
172
|
-
tabButton.classList.toggle("text-neutral-600", !isActive);
|
|
173
|
-
|
|
174
|
-
if (iconContainer.classList.contains("hidden")) return;
|
|
175
|
-
iconContainer.classList.toggle("opacity-100", isActive);
|
|
176
|
-
iconContainer.classList.toggle("opacity-80", !isActive);
|
|
177
|
-
});
|
|
178
|
-
syncPill();
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
tabs.forEach(({ tabButton }, index) => {
|
|
182
|
-
tabButton.addEventListener("click", () => {
|
|
183
|
-
if (activeIndex === index) return;
|
|
184
|
-
activeIndex = index;
|
|
185
|
-
syncActiveTab();
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
if (copyButton) {
|
|
190
|
-
let timeoutId = null;
|
|
191
|
-
copyButton.addEventListener("click", async () => {
|
|
192
|
-
const activeItem = tabs[activeIndex]?.itemElement;
|
|
193
|
-
const encodedCopyValue =
|
|
194
|
-
activeItem?.getAttribute("data-rd-copy-content") ?? "";
|
|
195
|
-
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
await navigator.clipboard.writeText(copyValue);
|
|
199
|
-
setCopiedState(copyButton, true);
|
|
200
|
-
|
|
201
|
-
if (timeoutId) window.clearTimeout(timeoutId);
|
|
202
|
-
timeoutId = window.setTimeout(() => {
|
|
203
|
-
setCopiedState(copyButton, false);
|
|
204
|
-
timeoutId = null;
|
|
205
|
-
}, 1200);
|
|
206
|
-
} catch {
|
|
207
|
-
setCopiedState(copyButton, false);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const resizeObserver =
|
|
213
|
-
typeof ResizeObserver !== "undefined"
|
|
214
|
-
? new ResizeObserver(() => syncPill())
|
|
215
|
-
: null;
|
|
216
|
-
if (resizeObserver) {
|
|
217
|
-
resizeObserver.observe(tabsElement);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
tabsElement.addEventListener("scroll", syncPill, { passive: true });
|
|
221
|
-
window.addEventListener("resize", syncPill);
|
|
222
|
-
syncActiveTab();
|
|
223
|
-
requestAnimationFrame(syncPill);
|
|
224
|
-
})();
|
|
225
|
-
</script>
|
|
224
|
+
tabsElement.addEventListener("scroll", syncPill, { passive: true });
|
|
225
|
+
window.addEventListener("resize", syncPill);
|
|
226
|
+
syncActiveTab();
|
|
227
|
+
requestAnimationFrame(syncPill);
|
|
228
|
+
})();
|
|
229
|
+
</script>
|
|
230
|
+
</div>
|