Skip to content

Commit 5a77fe6

Browse files
Fix Firefox code copying (2) (#2126)
Alternative to #2120 that is simpler and (hopefully) without regressions! Replaces `<span>` elements for lines with `<div>` elements, since these seem to copy properly as newlines in Firefox. Though please note [the HTML spec technically disallows this](https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-code-element:concept-element-content-model) 😥. Fixes #1972 Closes #2120 --------- Co-authored-by: Philipp Spiess <hello@philippspiess.com>
1 parent d3cc13b commit 5a77fe6

File tree

5 files changed

+44
-28
lines changed

5 files changed

+44
-28
lines changed

src/components/code-example.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { createHighlighter } from "shiki";
1010
import theme from "./syntax-highlighter/theme.json";
1111

1212
import { highlightClasses } from "./highlight-classes";
13+
import linesToDiv from "./lines-to-div";
1314
import atApplyInjection from "./syntax-highlighter/at-apply.json";
1415
import atRulesInjection from "./syntax-highlighter/at-rules.json";
1516
import themeFnInjection from "./syntax-highlighter/theme-fn.json";
@@ -135,7 +136,7 @@ export function HighlightedCode({
135136
example={example}
136137
className={clsx(
137138
"*:flex *:*:max-w-none *:*:shrink-0 *:*:grow *:overflow-auto *:rounded-lg *:bg-white/10! *:p-5 dark:*:bg-white/5!",
138-
"**:[.line]:isolate **:[.line]:block **:[.line]:not-last:min-h-[1lh]",
139+
"**:[.line]:isolate **:[.line]:not-last:min-h-[1lh]",
139140
"*:inset-ring *:inset-ring-white/10 dark:*:inset-ring-white/5",
140141
className,
141142
)}
@@ -178,6 +179,7 @@ export function RawHighlightedCode({
178179
highlightedClassName:
179180
"highlighted-word relative before:absolute before:-inset-x-0.5 before:-inset-y-0.25 before:-z-10 before:block before:rounded-sm before:bg-[lab(19.93_-1.66_-9.7)] [.highlighted-word_+_&]:before:rounded-l-none",
180181
}),
182+
linesToDiv(),
181183
],
182184
})
183185
.replaceAll("\n", "");

src/components/highlight-classes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export function highlightClasses(opts: HighlightClassesOptions): ShikiTransforme
4343
for (let i = 0; i < line.children.length; ++i) {
4444
let el = line.children[i];
4545
if (el.type !== "element") continue;
46-
if (el.tagName !== "span") continue;
46+
if (el.tagName !== "div" && el.tagName !== "span") continue;
4747

4848
// Tiny state machine to make sure we're inside a class attribute
4949
let text = getTextContent(el).trim();
@@ -216,7 +216,7 @@ export function getTextContent(element: ElementContent): string {
216216
return element.value;
217217
}
218218

219-
if (element.type === "element" && element.tagName === "span") {
219+
if (element.type === "element" && (element.tagName === "div" || element.tagName === "span")) {
220220
return element.children.map(getTextContent).join("");
221221
}
222222

src/components/home/tailwind-ui-section.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ export default function TailwindUiSection() {
5757

5858
<GridContainer className="mt-10">
5959
<div className="px-2 max-sm:px-4">
60-
<a href="https://tailwindcss.com/plus?ref=home" className="inline-block rounded-4xl bg-black px-4 py-2 text-sm/6 font-semibold text-white hover:bg-gray-800 dark:bg-gray-700 dark:hover:bg-gray-600">Explore Tailwind Plus</a>
60+
<a
61+
href="https://tailwindcss.com/plus?ref=home"
62+
className="inline-block rounded-4xl bg-black px-4 py-2 text-sm/6 font-semibold text-white hover:bg-gray-800 dark:bg-gray-700 dark:hover:bg-gray-600"
63+
>
64+
Explore Tailwind Plus
65+
</a>
6166
</div>
6267
</GridContainer>
6368
<TabGroup>

src/components/lines-to-div.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { ShikiTransformer } from "shiki";
2+
3+
export default function linesToDiv(): ShikiTransformer {
4+
return {
5+
name: "tailwindcss/lines-to-div",
6+
line(node) {
7+
node.tagName = "div";
8+
},
9+
};
10+
}

src/components/search.tsx

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,37 +13,36 @@ const APP_ID = "KNPXZI5B0M";
1313

1414
function isTailwindPlusURL(url: string) {
1515
return (
16-
url.startsWith('https://tailwindui.com') ||
17-
url.startsWith('https://tailwindcss.com/plus') ||
18-
url.startsWith('/plus')
19-
)
16+
url.startsWith("https://tailwindui.com") ||
17+
url.startsWith("https://tailwindcss.com/plus") ||
18+
url.startsWith("/plus")
19+
);
2020
}
2121

2222
function isExternalURL(url: string) {
23-
if (url.startsWith('https://tailwindui.com')) {
24-
return false
23+
if (url.startsWith("https://tailwindui.com")) {
24+
return false;
2525
}
2626

2727
return /^https?:\/\//.test(url) && !url.startsWith(window.location.origin);
2828
}
2929

3030
function rewriteURL(url: string) {
31-
if (!url.startsWith('https://tailwindui.com')) {
32-
return url
31+
if (!url.startsWith("https://tailwindui.com")) {
32+
return url;
3333
}
3434

35-
url = url.replace('https://tailwindui.com/', 'https://tailwindcss.com/plus/')
35+
url = url.replace("https://tailwindui.com/", "https://tailwindcss.com/plus/");
3636
// Temporary thing while `https://tailwindui.com/` is rewritten to /plus
37-
url = url.replace('/plus/plus/', '/plus/')
38-
url = url.replace('/plus/components', '/plus/ui-blocks')
39-
url = url.replace('/plus/templates/catalyst', '/plus/ui-kit')
40-
url = url.replace('/plus/all-access', '/plus/#pricing')
41-
url = url.replace('/plus/documentation', '/plus/ui-blocks/documentation')
37+
url = url.replace("/plus/plus/", "/plus/");
38+
url = url.replace("/plus/components", "/plus/ui-blocks");
39+
url = url.replace("/plus/templates/catalyst", "/plus/ui-kit");
40+
url = url.replace("/plus/all-access", "/plus/#pricing");
41+
url = url.replace("/plus/documentation", "/plus/ui-blocks/documentation");
4242

43-
return url
43+
return url;
4444
}
4545

46-
4746
const SearchContext = createContext<any>({});
4847

4948
export function SearchProvider({ children }: React.PropsWithChildren) {
@@ -157,20 +156,20 @@ export function SearchProvider({ children }: React.PropsWithChildren) {
157156
hitComponent={Hit}
158157
transformItems={(items) => {
159158
items = items.map((item) => {
160-
item.url = rewriteURL(item.url)
161-
return item
162-
})
159+
item.url = rewriteURL(item.url);
160+
return item;
161+
});
163162

164163
// TODO: Remove this once only new stuff is indexed
165164
items = items.filter((item) => {
166165
// Remove old prev-Tailwind plus search results
167166
// @ts-ignore
168167
if (item.hierarchy?.lvl0 === "Components") {
169-
return false
168+
return false;
170169
}
171170

172-
return true
173-
})
171+
return true;
172+
});
174173

175174
return items.map((item, index) => {
176175
// We transform the absolute URL into a relative URL to
@@ -195,11 +194,11 @@ export function SearchProvider({ children }: React.PropsWithChildren) {
195194

196195
if (isTailwindUI && item.hierarchy.lvl0 === "UI Blocks") {
197196
if (item.hierarchy?.lvl0) {
198-
item.hierarchy.lvl0 = "Components"
197+
item.hierarchy.lvl0 = "Components";
199198
}
200199

201200
if (item._highlightResult?.hierarchy?.lvl0?.value) {
202-
item._highlightResult.hierarchy.lvl0.value = "Components"
201+
item._highlightResult.hierarchy.lvl0.value = "Components";
203202
}
204203
}
205204

0 commit comments

Comments
 (0)