Skip to content

Commit 184d1ca

Browse files
author
RooCode
committed
feat: upgrade tailwindcss to v4
Update tailwindcss from v3 to v4 and related documentation. - Update package.json dependencies - Update tailwind config with v4 features - Update documentation in README and memory bank - Update tech stack display in homepage Signed-off-by: RooCode
1 parent ad7da2b commit 184d1ca

20 files changed

+666
-1055
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Rapid development with Next.js 15, TypeScript, and Shadcn UI, Swagger. Built for
77
### Frontend
88
- Next.js 15 (App Router)
99
- TypeScript 5
10-
- TailwindCSS 3
10+
- TailwindCSS 4 (Latest)
1111
- Shadcn UI
1212
- Swagger UI
1313

app/[locale]/not-found.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default function NotFound() {
99

1010
return (
1111
<BaseLayout locale='en'>
12-
<div className='flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
12+
<div className='flex flex-col items-center justify-center min-h-screen bg-linear-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
1313
<AlertTriangleIcon className='mx-auto h-12 w-12 text-red-500 mb-4' />
1414
<p className='text-2xl md:text-3xl font-semibold text-gray-600 dark:text-gray-300 mb-6'>{t("title")}</p>
1515
<p className='text-lg md:text-xl text-gray-500 dark:text-gray-400 mb-8 max-w-md'>{t("description")}</p>

app/[locale]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export async function generateMetadata(): Promise<Metadata> {
1818
};
1919
}
2020

21-
const techs: string[] = ["NextJS 15", "TailwindCSS 3", "Shadcn", "Prisma 6", "Supabase", "Swagger"];
21+
const techs: string[] = ["NextJS 15", "TailwindCSS 4", "Shadcn", "Prisma 6", "Supabase", "Swagger"];
2222

2323
export default async function Page({ params }: PageType) {
2424
const { locale } = await params;

app/api-docs/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function ApiDoc() {
88
<Link href='/' className='text-2xl font-bold mb-4'>
99
NextJS Faster
1010
</Link>
11-
<div className='swagger-ui-wrapper bg-white rounded-lg shadow'>
11+
<div className='swagger-ui-wrapper bg-white rounded-lg shadow-sm'>
1212
<SwaggerUI url='/api/docs' />
1313
</div>
1414
</div>

app/globals.css

Lines changed: 103 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,106 @@
1-
@tailwind base;
2-
@tailwind components;
3-
@tailwind utilities;
1+
@import "tailwindcss";
2+
3+
@custom-variant dark (&:is(.dark *));
4+
5+
@theme {
6+
--color-border: hsl(var(--border));
7+
--color-input: hsl(var(--input));
8+
--color-ring: hsl(var(--ring));
9+
--color-background: hsl(var(--background));
10+
--color-foreground: hsl(var(--foreground));
11+
12+
--color-primary: hsl(var(--primary));
13+
--color-primary-foreground: hsl(var(--primary-foreground));
14+
15+
--color-secondary: hsl(var(--secondary));
16+
--color-secondary-foreground: hsl(var(--secondary-foreground));
17+
18+
--color-destructive: hsl(var(--destructive));
19+
--color-destructive-foreground: hsl(var(--destructive-foreground));
20+
21+
--color-muted: hsl(var(--muted));
22+
--color-muted-foreground: hsl(var(--muted-foreground));
23+
24+
--color-accent: hsl(var(--accent));
25+
--color-accent-foreground: hsl(var(--accent-foreground));
26+
27+
--color-popover: hsl(var(--popover));
28+
--color-popover-foreground: hsl(var(--popover-foreground));
29+
30+
--color-card: hsl(var(--card));
31+
--color-card-foreground: hsl(var(--card-foreground));
32+
33+
--color-chart-1: hsl(var(--chart-1));
34+
--color-chart-2: hsl(var(--chart-2));
35+
--color-chart-3: hsl(var(--chart-3));
36+
--color-chart-4: hsl(var(--chart-4));
37+
--color-chart-5: hsl(var(--chart-5));
38+
39+
--color-sidebar: hsl(var(--sidebar-background));
40+
--color-sidebar-foreground: hsl(var(--sidebar-foreground));
41+
--color-sidebar-primary: hsl(var(--sidebar-primary));
42+
--color-sidebar-primary-foreground: hsl(var(--sidebar-primary-foreground));
43+
--color-sidebar-accent: hsl(var(--sidebar-accent));
44+
--color-sidebar-accent-foreground: hsl(var(--sidebar-accent-foreground));
45+
--color-sidebar-border: hsl(var(--sidebar-border));
46+
--color-sidebar-ring: hsl(var(--sidebar-ring));
47+
48+
--radius-lg: var(--radius);
49+
--radius-md: calc(var(--radius) - 2px);
50+
--radius-sm: calc(var(--radius) - 4px);
51+
52+
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
53+
"Segoe UI Symbol", "Noto Color Emoji";
54+
55+
--animate-accordion-down: accordion-down 0.2s ease-out;
56+
--animate-accordion-up: accordion-up 0.2s ease-out;
57+
58+
@keyframes accordion-down {
59+
from {
60+
height: 0;
61+
}
62+
to {
63+
height: var(--radix-accordion-content-height);
64+
}
65+
}
66+
@keyframes accordion-up {
67+
from {
68+
height: var(--radix-accordion-content-height);
69+
}
70+
to {
71+
height: 0;
72+
}
73+
}
74+
}
75+
76+
@utility container {
77+
margin-inline: auto;
78+
padding-inline: 2rem;
79+
@media (width >= --theme(--breakpoint-sm)) {
80+
max-width: none;
81+
}
82+
@media (width >= 1400px) {
83+
max-width: 1400px;
84+
}
85+
}
86+
87+
/*
88+
The default border color has changed to `currentcolor` in Tailwind CSS v4,
89+
so we've added these compatibility styles to make sure everything still
90+
looks the same as it did with Tailwind CSS v3.
91+
92+
If we ever want to remove these styles, we need to add an explicit border
93+
color utility to any element that depends on these defaults.
94+
*/
95+
@layer base {
96+
*,
97+
::after,
98+
::before,
99+
::backdrop,
100+
::file-selector-button {
101+
border-color: var(--color-gray-200, currentcolor);
102+
}
103+
}
4104

5105
@layer base {
6106
:root {

app/not-found.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default function NotFound() {
99

1010
return (
1111
<BaseLayout locale='en'>
12-
<div className='flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
12+
<div className='flex flex-col items-center justify-center min-h-screen bg-linear-to-b from-gray-50 to-gray-100 dark:from-gray-900 dark:to-gray-800 px-4 text-center'>
1313
<AlertTriangleIcon className='mx-auto h-12 w-12 text-red-500 mb-4' />
1414
<p className='text-2xl md:text-3xl font-semibold text-gray-600 dark:text-gray-300 mb-6'>{t("title")}</p>
1515
<p className='text-lg md:text-xl text-gray-500 dark:text-gray-400 mb-8 max-w-md'>{t("description")}</p>

components/ui/badge.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import type * as React from "react";
44
import { cn } from "@/lib/utils";
55

66
const badgeVariants = cva(
7-
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
7+
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
88
{
99
variants: {
1010
variant: {
11-
default: "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
11+
default: "border-transparent bg-primary text-primary-foreground shadow-sm hover:bg-primary/80",
1212
secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
13-
destructive: "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
13+
destructive: "border-transparent bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/80",
1414
outline: "text-foreground"
1515
}
1616
},

components/ui/button.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import * as React from "react";
55
import { cn } from "@/lib/utils";
66

77
const buttonVariants = cva(
8-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
8+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
99
{
1010
variants: {
1111
variant: {
12-
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
13-
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
14-
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
15-
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
12+
default: "bg-primary text-primary-foreground shadow-sm hover:bg-primary/90",
13+
destructive: "bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
14+
outline: "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
15+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
1616
ghost: "hover:bg-accent hover:text-accent-foreground",
1717
link: "text-primary underline-offset-4 hover:underline"
1818
},

components/ui/card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as React from "react";
33
import { cn } from "@/lib/utils";
44

55
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
6-
<div ref={ref} className={cn("rounded-xl border bg-card text-card-foreground shadow", className)} {...props} />
6+
<div ref={ref} className={cn("rounded-xl border bg-card text-card-foreground shadow-sm", className)} {...props} />
77
));
88
Card.displayName = "Card";
99

components/ui/dropdown-menu.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
2727
<DropdownMenuPrimitive.SubTrigger
2828
ref={ref}
2929
className={cn(
30-
"flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
30+
"flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
3131
inset && "pl-8",
3232
className
3333
)}
@@ -82,7 +82,7 @@ const DropdownMenuItem = React.forwardRef<
8282
<DropdownMenuPrimitive.Item
8383
ref={ref}
8484
className={cn(
85-
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
85+
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
8686
inset && "pl-8",
8787
className
8888
)}
@@ -98,7 +98,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
9898
<DropdownMenuPrimitive.CheckboxItem
9999
ref={ref}
100100
className={cn(
101-
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
101+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
102102
className
103103
)}
104104
checked={checked}
@@ -121,7 +121,7 @@ const DropdownMenuRadioItem = React.forwardRef<
121121
<DropdownMenuPrimitive.RadioItem
122122
ref={ref}
123123
className={cn(
124-
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
124+
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-hidden transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
125125
className
126126
)}
127127
{...props}

components/ui/input.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({ className, type,
1010
<input
1111
type={type}
1212
className={cn(
13-
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
13+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-xs transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
1414
className
1515
)}
1616
ref={ref}

components/ui/select.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
1919
<SelectPrimitive.Trigger
2020
ref={ref}
2121
className={cn(
22-
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
22+
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-xs ring-offset-background placeholder:text-muted-foreground focus:outline-hidden focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
2323
className
2424
)}
2525
{...props}
@@ -107,7 +107,7 @@ const SelectItem = React.forwardRef<
107107
<SelectPrimitive.Item
108108
ref={ref}
109109
className={cn(
110-
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
110+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
111111
className
112112
)}
113113
{...props}

components/ui/toast.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const ToastViewport = React.forwardRef<
1616
<ToastPrimitives.Viewport
1717
ref={ref}
1818
className={cn(
19-
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
19+
"fixed top-0 z-100 flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]",
2020
className
2121
)}
2222
{...props}
@@ -25,7 +25,7 @@ const ToastViewport = React.forwardRef<
2525
ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
2626

2727
const toastVariants = cva(
28-
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full",
28+
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full sm:data-[state=open]:slide-in-from-bottom-full",
2929
{
3030
variants: {
3131
variant: {
@@ -54,7 +54,7 @@ const ToastAction = React.forwardRef<
5454
<ToastPrimitives.Action
5555
ref={ref}
5656
className={cn(
57-
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
57+
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-hidden focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 hover:group-[.destructive]:border-destructive/30 hover:group-[.destructive]:bg-destructive hover:group-[.destructive]:text-destructive-foreground focus:group-[.destructive]:ring-destructive",
5858
className
5959
)}
6060
{...props}
@@ -69,7 +69,7 @@ const ToastClose = React.forwardRef<
6969
<ToastPrimitives.Close
7070
ref={ref}
7171
className={cn(
72-
"absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
72+
"absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-hidden focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 hover:group-[.destructive]:text-red-50 focus:group-[.destructive]:ring-red-400 focus:group-[.destructive]:ring-offset-red-600",
7373
className
7474
)}
7575
toast-close=''

0 commit comments

Comments
 (0)