From bd266e440037d197b8006e7b6d4a1785e8873984 Mon Sep 17 00:00:00 2001 From: gabriel miranda Date: Mon, 8 Dec 2025 11:28:09 -0300 Subject: [PATCH 1/7] add tailwind directives parsing to biome --- biome.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/biome.json b/biome.json index 475d432414..63d6dc1725 100644 --- a/biome.json +++ b/biome.json @@ -7,6 +7,11 @@ } } }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, "vcs": { "enabled": true, "clientKind": "git", From d29cee47bbb3bb254bb00b195e19014c86589a0b Mon Sep 17 00:00:00 2001 From: gabriel miranda Date: Mon, 8 Dec 2025 11:29:03 -0300 Subject: [PATCH 2/7] migrate to tailwindcss v4 in the preview server --- packages/preview-server/package.json | 2 +- packages/preview-server/src/app/globals.css | 122 +++++++++++++- packages/preview-server/src/app/layout.tsx | 2 +- .../app/preview/[...slug]/error-overlay.tsx | 10 +- .../preview-server/src/components/button.tsx | 6 +- .../preview-server/src/components/code.tsx | 4 +- .../src/components/icons/icon-button.tsx | 2 +- .../preview-server/src/components/send.tsx | 6 +- .../preview-server/src/components/shell.tsx | 12 +- .../sidebar/file-tree-directory-children.tsx | 2 +- .../src/components/sidebar/file-tree.tsx | 4 +- .../src/components/sidebar/sidebar.tsx | 2 +- .../preview-server/src/components/toolbar.tsx | 16 +- .../components/toolbar/checking-results.tsx | 4 +- .../src/components/toolbar/toolbar-button.tsx | 2 +- .../components/topbar/view-size-controls.tsx | 8 +- packages/preview-server/tailwind.config.ts | 99 ------------ pnpm-lock.yaml | 149 +++++++++++++++--- 18 files changed, 290 insertions(+), 162 deletions(-) delete mode 100644 packages/preview-server/tailwind.config.ts diff --git a/packages/preview-server/package.json b/packages/preview-server/package.json index e708d52b46..f533ee0d91 100644 --- a/packages/preview-server/package.json +++ b/packages/preview-server/package.json @@ -63,7 +63,7 @@ "source-map-js": "1.2.1", "stacktrace-parser": "0.1.11", "tailwind-merge": "3.2.0", - "tailwindcss": "3.4.0", + "tailwindcss": "4.1.17", "typescript": "5.8.3", "use-debounce": "10.0.4", "zod": "4.1.12" diff --git a/packages/preview-server/src/app/globals.css b/packages/preview-server/src/app/globals.css index 10304ba466..43ddd5b488 100644 --- a/packages/preview-server/src/app/globals.css +++ b/packages/preview-server/src/app/globals.css @@ -1,6 +1,122 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; +@import "tailwindcss"; + +@theme { + --background-image-gradient: linear-gradient( + 145.37deg, + rgba(255, 255, 255, 0.09) -8.75%, + rgba(255, 255, 255, 0.027) 83.95% + ); + --background-image-gradient-hover: linear-gradient( + 145.37deg, + rgba(255, 255, 255, 0.1) -8.75%, + rgba(255, 255, 255, 0.057) 83.95% + ); + --background-image-shine: linear-gradient( + 45deg, + rgba(255, 255, 255, 0) 45%, + rgba(255, 255, 255, 1) 50%, + rgba(255, 255, 255, 0) 55%, + rgba(255, 255, 255, 0) 100% + ); + + --color-cyan-1: #0091f70a; + --color-cyan-2: #02a7f211; + --color-cyan-3: #00befd28; + --color-cyan-4: #00baff3b; + --color-cyan-5: #00befd4d; + --color-cyan-6: #00c7fd5e; + --color-cyan-7: #14cdff75; + --color-cyan-8: #11cfff95; + --color-cyan-9: #00cfffc3; + --color-cyan-10: #28d6ffcd; + --color-cyan-11: #52e1fee5; + --color-cyan-12: #bbf3fef7; + + --color-slate-1: #00000000; + --color-slate-2: #d8f4f609; + --color-slate-3: #ddeaf814; + --color-slate-4: #d3edf81d; + --color-slate-5: #d9edfe25; + --color-slate-6: #d6ebfd30; + --color-slate-7: #d9edff40; + --color-slate-8: #d9edff5d; + --color-slate-9: #dfebfd6d; + --color-slate-10: #e5edfd7b; + --color-slate-11: #f1f7feb5; + --color-slate-12: #fcfdffef; + + --font-sans: + var(--font-inter), ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", + "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-mono: + var(--font-sf-mono), ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + "Liberation Mono", "Courier New", monospace; + + --animate-spin-slow: spin 3s linear infinite; + --animate-spin-fast: spin 1.5s linear infinite; + + @keyframes shine { + 0% { + background-position: -100%; + } + + 100% { + background-position: 100%; + } + } + + @keyframes dash { + 0% { + stroke-dashoffset: 1000; + } + + 100% { + stroke-dashoffset: 0; + } + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } +} + +@utility arrow-hide { + appearance: textfield; + + &::-webkit-inner-spin-button { + appearance: none; + margin: 0px; + } + + &::-webkit-outer-spin-button { + appearance: none; + margin: 0px; + } +} + +/* + The default border color has changed to `currentcolor` in Tailwind CSS v4, + so we've added these compatibility styles to make sure everything still + looks the same as it did with Tailwind CSS v3. + + If we ever want to remove these styles, we need to add an explicit border + color utility to any element that depends on these defaults. +*/ +@layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentcolor); + } +} html { color-scheme: dark; diff --git a/packages/preview-server/src/app/layout.tsx b/packages/preview-server/src/app/layout.tsx index 0f4ea0dcc4..4a99619456 100644 --- a/packages/preview-server/src/app/layout.tsx +++ b/packages/preview-server/src/app/layout.tsx @@ -33,7 +33,7 @@ export default async function RootLayout({ lang="en" > -
+
diff --git a/packages/preview-server/src/app/preview/[...slug]/error-overlay.tsx b/packages/preview-server/src/app/preview/[...slug]/error-overlay.tsx index a7dd003cc3..e2304c2723 100644 --- a/packages/preview-server/src/app/preview/[...slug]/error-overlay.tsx +++ b/packages/preview-server/src/app/preview/[...slug]/error-overlay.tsx @@ -36,17 +36,17 @@ export const ErrorOverlay = ({ error }: ErrorOverlayProps) => { min-h-[50vh] w-full max-w-lg sm:rounded-lg md:max-w-[568px] lg:max-w-[920px] absolute left-[50%] top-[50%] z-50 translate-x-[-50%] translate-y-[-50%] rounded-t-sm overflow-hidden bg-white text-black shadow-lg duration-200 - flex flex-col selection:!text-black + flex flex-col selection:text-black! " >
-
-
+
+
{error.name}: {error.message}
{error.stack ? ( -
-
+            
+
                 {error.stack}
               
diff --git a/packages/preview-server/src/components/button.tsx b/packages/preview-server/src/components/button.tsx index 84c7453035..91c7545ee7 100644 --- a/packages/preview-server/src/components/button.tsx +++ b/packages/preview-server/src/components/button.tsx @@ -70,14 +70,14 @@ const getAppearance = (appearance: Appearance | undefined) => { return [ 'border-white bg-white text-black transition-colors duration-200 ease-in-out', 'hover:bg-white/90', - 'focus:bg-white/90 focus:outline-none focus:ring-2 focus:ring-white/20', + 'focus:bg-white/90 focus:outline-hidden focus:ring-2 focus:ring-white/20', 'mt-2 mb-2 aria-disabled:border-transparent aria-disabled:bg-slate-11', ]; case 'gradient': return [ 'bg-gradient border-[#34343A] backdrop-blur-[1.25rem]', - 'hover:bg-gradientHover', - 'focus:bg-gradientHover focus:outline-none focus:ring-2 focus:ring-white/20', + 'hover:bg-gradient-hover', + 'focus:bg-gradient-hover focus:outline-hidden focus:ring-2 focus:ring-white/20', ]; default: unreachable(appearance); diff --git a/packages/preview-server/src/components/code.tsx b/packages/preview-server/src/components/code.tsx index 7f311e22ee..d512a1571e 100644 --- a/packages/preview-server/src/components/code.tsx +++ b/packages/preview-server/src/components/code.tsx @@ -129,8 +129,8 @@ export const Code: React.FC> = ({ scroll={false} aria-selected={isHighlighted} className={cn( - 'text-[#49494f] relative text-[13px] font-light font-[MonoLisa,_Menlo,_monospace] align-middle scroll-mt-[325px] select-none pr-3 cursor-pointer hover:text-slate-12 transition-colors', - 'aria-selected:text-cyan-11 aria-selected:hover:text-cyan-11 aria-selected:bg-cyan-5 [&+*]:aria-selected:bg-cyan-5', + 'text-[#49494f] relative text-[13px] font-light font-[MonoLisa,Menlo,monospace] align-middle scroll-mt-[325px] select-none pr-3 cursor-pointer hover:text-slate-12 transition-colors', + 'aria-selected:text-cyan-11 aria-selected:hover:text-cyan-11 aria-selected:bg-cyan-5 aria-selected:[&+*]:bg-cyan-5', isHighlightStart && 'rounded-tl-sm', isHighlightEnd && 'rounded-bl-sm', )} diff --git a/packages/preview-server/src/components/icons/icon-button.tsx b/packages/preview-server/src/components/icons/icon-button.tsx index 52b7567b94..4ebe38f7a4 100644 --- a/packages/preview-server/src/components/icons/icon-button.tsx +++ b/packages/preview-server/src/components/icons/icon-button.tsx @@ -11,7 +11,7 @@ export const IconButton = React.forwardRef< type="button" {...props} className={cn( - 'focus:ring-gray-8 rounded text-slate-11 transition duration-200 ease-in-out hover:text-slate-12 focus:text-slate-12 focus:outline-none focus:ring-2', + 'focus:ring-gray-8 rounded-sm text-slate-11 transition duration-200 ease-in-out hover:text-slate-12 focus:text-slate-12 focus:outline-hidden focus:ring-2', className, )} ref={forwardedRef} diff --git a/packages/preview-server/src/components/send.tsx b/packages/preview-server/src/components/send.tsx index f4a642c03c..4dcfe98855 100644 --- a/packages/preview-server/src/components/send.tsx +++ b/packages/preview-server/src/components/send.tsx @@ -60,7 +60,7 @@ export const Send = ({ markup }: { markup: string }) => { >
-
+
{ className={cn( 'inline-block relative overflow-hidden will-change-[width]', 'w-full h-full', - '[transition:width_0.2s_ease-in-out,_transform_0.2s_ease-in-out]', + '[transition:width_0.2s_ease-in-out,transform_0.2s_ease-in-out]', { 'lg:w-[calc(100%-16rem)]': sidebarToggled, 'opacity-0 lg:opacity-100': !sidebarToggled, diff --git a/packages/preview-server/src/components/sidebar/file-tree-directory-children.tsx b/packages/preview-server/src/components/sidebar/file-tree-directory-children.tsx index 399f237611..2a42b58cf1 100644 --- a/packages/preview-server/src/components/sidebar/file-tree-directory-children.tsx +++ b/packages/preview-server/src/components/sidebar/file-tree-directory-children.tsx @@ -108,7 +108,7 @@ export const FileTreeDirectoryChildren = (props: { > {props.isRoot ? null : ( { return ( -
-