Skip to content

Commit 2d7f692

Browse files
Junyi-99claude
andauthored
chore: update to Tailwind CSS 4.0 (#125)
This pull request focuses on modernizing the UI codebase and updating dependencies for improved stability and consistency. The most significant changes include upgrading various dependencies in `package.json`, standardizing the usage of utility class syntax (notably the placement of `!` for Tailwind overrides), and refactoring shimmer/loading indicator styles to use a shared CSS class. These updates collectively enhance maintainability, visual consistency, and compatibility with newer tooling. **Dependency upgrades and tooling modernization:** * Updated dependencies in `package.json` to newer versions, including major upgrades for `react`, `react-dom`, `axios`, `immer`, `streamdown`, `uuid`, and several dev tools. Added `@tailwindcss/postcss`, `@tailwindcss/vite`, `tailwindcss`, and `tw-shimmer` for improved styling and loading effects. * Changed `postcss.config.js` to use `@tailwindcss/postcss` instead of the generic `tailwindcss` and `autoprefixer` plugins, aligning with the new dependency setup. **UI styling and class syntax standardization:** * Refactored Tailwind utility class syntax throughout component files, moving the `!` modifier to the end of each class for consistency and to match modern conventions. This affects components like `cell-wrapper`, `message-card`, `message-entry-container`, `attachment-popover`, `add-comments-button`, and `comment-item`. [[1]](diffhunk://#diff-157c9a8283c879c70716c7590796e53e556ae6b0e0cbc8038a6afb4f3bd79fb3L13-R13) [[2]](diffhunk://#diff-8975f0fa9a3603405f4f946517a5664a3d9daa76a45686a2731b36ad656af3d6L13-R30) [[3]](diffhunk://#diff-bdc99d7f83bf940e6c4720d6c71d1a152a0f30c450437de80721a4c69ec27056L99-R103) [[4]](diffhunk://#diff-bdc99d7f83bf940e6c4720d6c71d1a152a0f30c450437de80721a4c69ec27056L121-R121) [[5]](diffhunk://#diff-a7ead10fda306e9f40d19c07cb451419827ecfcd58f6af88a9d7e7c1b942a4feL6-R13) [[6]](diffhunk://#diff-169cd97f4ec14d427d7b8708f74adb2c6e75bcf92be343205efc6bb49a9fa1a1L94-R105) [[7]](diffhunk://#diff-169cd97f4ec14d427d7b8708f74adb2c6e75bcf92be343205efc6bb49a9fa1a1L119-R123) [[8]](diffhunk://#diff-4914530d0e63e87a1adc148040ac012bc6b3fdffa22387da0b645a5fb49bce03L24-R69) **Shimmer/loading indicator improvements:** * Removed inline shimmer animation styles and replaced them with a shared `shimmer` CSS class for loading indicators and tool cards, simplifying code and ensuring consistent loading effects. This change impacts `loading-indicator.tsx`, `toolcall-prepare.tsx`, and `tools/general.tsx`. [[1]](diffhunk://#diff-055ce0c61219eb693f487cd58a5c6e449e39db3b40e2a9dde983558c4c23ec40L19-L35) [[2]](diffhunk://#diff-055ce0c61219eb693f487cd58a5c6e449e39db3b40e2a9dde983558c4c23ec40L173-R156) [[3]](diffhunk://#diff-96812e399ce5ec2119eb57438e29fb08489fe8956d59029efdc7ce0510638ee2L18-R18) [[4]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL18-L30) [[5]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL77-R64) [[6]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL124-R111) **Minor UI and accessibility tweaks:** * Updated component class names for improved readability and accessibility, including changes to button states, error messages, and code block rendering. [[1]](diffhunk://#diff-cb1d9a39dd3f77b8f285a7ec7f3a576f1a119742662488d405dc3ce866b95d79L18-R18) [[2]](diffhunk://#diff-f98697c89f34ff3081b7ac6a66e7e9bb2ed6fe82d274042b1d602a897154a89fL18-R18) [[3]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL114-R101) [[4]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL139-R123) [[5]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL114-R101) [[6]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL139-R123) [[7]](diffhunk://#diff-169cd97f4ec14d427d7b8708f74adb2c6e75bcf92be343205efc6bb49a9fa1a1L94-R105) [[8]](diffhunk://#diff-169cd97f4ec14d427d7b8708f74adb2c6e75bcf92be343205efc6bb49a9fa1a1L119-R123) [[9]](diffhunk://#diff-4914530d0e63e87a1adc148040ac012bc6b3fdffa22387da0b645a5fb49bce03L24-R69) **Removal of unused code:** * Deleted unused inline style constants for shimmer/loading effects, further cleaning up the codebase. [[1]](diffhunk://#diff-055ce0c61219eb693f487cd58a5c6e449e39db3b40e2a9dde983558c4c23ec40L19-L35) [[2]](diffhunk://#diff-6bbab187f6b867777c579b60e164e230164a16b8b54121d874020105b1105fbcL18-L30) These changes collectively improve the project's maintainability, visual consistency, and readiness for future updates. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 24438ec commit 2d7f692

122 files changed

Lines changed: 2604 additions & 2805 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

webapp/_webapp/bun.lock

Lines changed: 921 additions & 655 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webapp/_webapp/package-lock.json

Lines changed: 1071 additions & 1378 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webapp/_webapp/package.json

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@
2323
},
2424
"dependencies": {
2525
"@buf/googleapis_googleapis.bufbuild_es": "^2.2.3-20250211200939-546238c53f73.1",
26-
"@bufbuild/protobuf": "^2.5.1",
26+
"@bufbuild/protobuf": "^2.11.0",
2727
"@capacitor-community/apple-sign-in": "^7.0.1",
28-
"@heroui/react": "^2.7.9",
29-
"@iconify/react": "^6.0.0",
28+
"@heroui/react": "2.8.9",
29+
"@iconify/react": "^6.0.2",
3030
"@lukemorales/query-key-factory": "^1.3.4",
3131
"@opentelemetry/exporter-logs-otlp-http": "^0.219.0",
3232
"@opentelemetry/exporter-metrics-otlp-http": "^0.219.0",
@@ -41,58 +41,52 @@
4141
"@opentelemetry/sdk-trace-web": "^2.8.0",
4242
"@opentelemetry/semantic-conventions": "^1.41.1",
4343
"@r2wc/react-to-web-component": "^2.1.0",
44-
"@streamdown/cjk": "^1.0.1",
45-
"@streamdown/code": "^1.0.1",
46-
"@streamdown/math": "^1.0.1",
47-
"@streamdown/mermaid": "^1.0.1",
48-
"@tanstack/react-query": "^5.79.0",
44+
"@streamdown/cjk": "^1.0.2",
45+
"@streamdown/code": "^1.0.2",
46+
"@streamdown/math": "^1.0.2",
47+
"@streamdown/mermaid": "^1.0.2",
48+
"@tailwindcss/postcss": "^4.3.1",
49+
"@tanstack/react-query": "^5.90.21",
4950
"@types/diff": "^8.0.0",
50-
"@uidotdev/usehooks": "^2.4.1",
51-
"axios": "^1.9.0",
52-
"baseline-browser-mapping": "^2.9.12",
53-
"caniuse-lite": "^1.0.30001762",
54-
"diff": "^8.0.2",
51+
"axios": "^1.13.5",
52+
"diff": "^8.0.3",
5553
"events": "^3.3.0",
56-
"framer-motion": "^12.15.0",
54+
"framer-motion": "12.34.2",
5755
"highlight.js": "^11.11.1",
58-
"immer": "^10.1.1",
59-
"jszip": "^3.10.1",
60-
"markdown-to-jsx": "^7.7.6",
61-
"openai": "^5.0.1",
62-
"postcss": "^8.5.4",
63-
"react": "^19.1.0",
64-
"react-dom": "^19.1.0",
56+
"immer": "11.1.4",
57+
"react": "19.2.4",
58+
"react-dom": "19.2.4",
6559
"react-rnd": "^10.5.2",
66-
"semver": "^7.7.2",
67-
"streamdown": "^2.1.0",
68-
"uuid": "^11.1.0",
60+
"semver": "^7.7.4",
61+
"streamdown": "^2.2.0",
62+
"tailwindcss": "^4.3.1",
63+
"tw-shimmer": "^0.4.6",
64+
"uuid": "^13.0.0",
6965
"web-vitals": "^5.3.0",
70-
"zustand": "^5.0.5"
66+
"zustand": "^5.0.11"
7167
},
7268
"devDependencies": {
73-
"@codemirror/state": "^6.5.2",
74-
"@codemirror/view": "^6.37.1",
75-
"@eslint/js": "^9.28.0",
76-
"@types/bun": "^1.3.5",
69+
"@codemirror/state": "^6.5.4",
70+
"@codemirror/view": "^6.39.14",
71+
"@eslint/js": "^9.39.0",
72+
"@types/bun": "^1.3.9",
7773
"@types/chrome": "^0.0.326",
78-
"@types/codemirror": "^5.60.16",
74+
"@types/codemirror": "^5.60.17",
7975
"@types/events": "^3.0.3",
80-
"@types/node": "^22.15.29",
81-
"@types/react": "^19.1.6",
82-
"@types/react-dom": "^19.1.5",
83-
"@types/semver": "^7.7.0",
84-
"@vitejs/plugin-react-swc": "^3.10.0",
85-
"autoprefixer": "^10.4.21",
86-
"eslint": "^9.28.0",
76+
"@types/node": "^25.2.3",
77+
"@types/react": "^19.2.14",
78+
"@types/react-dom": "^19.2.3",
79+
"@types/semver": "^7.7.1",
80+
"@vitejs/plugin-react-swc": "^4.2.3",
81+
"eslint": "^9.39.0",
8782
"eslint-plugin-react-hooks": "^5.2.0",
8883
"eslint-plugin-react-refresh": "^0.4.20",
89-
"globals": "^16.2.0",
90-
"nodemon": "^3.1.10",
84+
"globals": "^17.7.0",
85+
"nodemon": "^3.1.11",
9186
"postcss-prefix-selector": "^2.1.1",
92-
"prettier": "3.5.3",
93-
"tailwindcss": "^3.4.17",
94-
"typescript": "~5.8.3",
95-
"typescript-eslint": "^8.33.0",
96-
"vite": "^6.3.5"
87+
"prettier": "3.8.1",
88+
"typescript": "~5.9.3",
89+
"typescript-eslint": "^8.62.0",
90+
"vite": "^7.3.1"
9791
}
9892
}

webapp/_webapp/postcss.config.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
// (VITE_CONFIG=default) so preflight/heroui don't leak into Overleaf. The
33
// .pd-scope class sits on every container we mount into (#paper-debugger-root
44
// and #pd-embed-sidebar). Settings/popup are standalone pages and stay unscoped.
5+
//
6+
// Tailwind v4 via @tailwindcss/postcss (not the Vite plugin) so the prefix step
7+
// runs AFTER Tailwind emits its CSS. v4 handles vendor prefixing internally, so
8+
// autoprefixer is gone.
59
const SCOPE = ".pd-scope";
610
const scoped = process.env.VITE_CONFIG === "default";
711

812
export default {
913
plugins: {
10-
tailwindcss: {},
14+
"@tailwindcss/postcss": {},
1115
...(scoped && {
1216
"postcss-prefix-selector": {
1317
prefix: SCOPE,
@@ -33,6 +37,5 @@ export default {
3337
},
3438
},
3539
}),
36-
autoprefixer: {},
3740
},
3841
};

webapp/_webapp/src/components/cell-wrapper.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const CellWrapper = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDi
1010
<div
1111
ref={ref}
1212
className={cn(
13-
"flex items-center justify-between gap-2 rounded-medium bg-content2 !p-2 !pr-[12px] !pl-[20px]",
13+
"flex items-center justify-between gap-2 rounded-medium bg-content2 p-2! pr-[12px]! pl-[20px]!",
1414
className,
1515
)}
1616
{...props}

webapp/_webapp/src/components/code-block.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const CodeBlock = ({ code, className }: CodeBlockProps) => {
1515

1616
return (
1717
<pre
18-
className={`p-2 rounded-md bg-gray-200 dark:!bg-default-200 text-sm text-wrap break-words ${className}`}
18+
className={`p-2 rounded-md bg-gray-200 dark:!bg-default-200 text-sm text-wrap wrap-break-word ${className}`}
1919
dangerouslySetInnerHTML={{ __html: highlightedCode }}
2020
/>
2121
);

webapp/_webapp/src/components/loading-indicator.tsx

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,6 @@ interface LoadingIndicatorProps {
1616
// Constants
1717
// ============================================================================
1818

19-
const STYLES = {
20-
loading: {
21-
animation: {
22-
WebkitTextFillColor: "transparent",
23-
animationDelay: "0.5s",
24-
animationDuration: "3s",
25-
animationIterationCount: "infinite",
26-
animationName: "shimmer",
27-
background: "#cdcdcd -webkit-gradient(linear, 100% 0, 0 0, from(#cdcdcd), color-stop(.5, #1a1a1a), to(#cdcdcd))",
28-
WebkitBackgroundClip: "text",
29-
backgroundRepeat: "no-repeat",
30-
backgroundSize: "50% 200%",
31-
backgroundPositionX: "-100%",
32-
},
33-
},
34-
} as const;
35-
3619
const PHASE_STYLES = {
3720
green: {
3821
background: "linear-gradient(90deg, #35aa6b 0%, #7cc89f 100%)",
@@ -170,8 +153,7 @@ export const LoadingIndicator = ({ text = "Thinking", estimatedSeconds = 0, erro
170153
<div className="indicator">
171154
{/* Status Text */}
172155
<div
173-
className={`flex space-x-1 text-xs ${!isTimeout && !errorMessage ? "loading-shimmer" : ""}`}
174-
style={!isTimeout && !errorMessage ? STYLES.loading.animation : undefined}
156+
className={`flex space-x-1 text-xs ${!isTimeout && !errorMessage ? "shimmer" : ""}`}
175157
>
176158
<span className={isTimeout || errorMessage ? "text-rose-400" : ""}>{getStatusMessage()}</span>
177159
</div>

webapp/_webapp/src/components/markdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ interface MarkdownComponentProps {
1515
const MarkdownComponent = memo(({ children, animated }: MarkdownComponentProps) => {
1616
return (
1717
<Streamdown
18-
className="space-y-1 leading-[1.50]"
18+
className="space-y-1 leading-normal"
1919
shikiTheme={["github-light", "ayu-dark"]}
2020
components={{
2121
h1: ({ children }) => (

webapp/_webapp/src/components/message-card.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,24 @@ import { DisplayMessage } from "../stores/types";
1010
// Constants
1111
export const STYLES = {
1212
container: {
13-
base: "!flex !flex-row !gap-2",
13+
base: "flex! flex-row! gap-2!",
1414
assistant: "",
1515
indicator: "",
1616
},
1717
messageWrapper: {
18-
base: "!max-w-full !flex !flex-col !gap-4",
19-
assistant: "!max-w-[100%]",
20-
user: "!max-w-[70%]",
21-
indicator: "!w-full",
18+
base: "max-w-full! flex! flex-col! gap-4!",
19+
assistant: "max-w-full!",
20+
user: "max-w-[70%]!",
21+
indicator: "w-full!",
2222
},
2323
messageBox: {
2424
base: cn(),
25-
assistant: "px-3 pt-3 pb-1 my-2 !border !border-transparent",
25+
assistant: "px-3 pt-3 pb-1 my-2 border! border-transparent!",
2626
user: "px-3 py-2 bg-gray-100 dark:!bg-default-200 self-end my-2",
2727
indicator: "px-3",
2828
},
2929
attachment: {
30-
content: "!max-w-[300px] !bg-default-100 dark:!bg-default-100",
30+
content: "max-w-[300px]! !bg-default-100 dark:!bg-default-100",
3131
text: "!text-tiny !text-default-400",
3232
},
3333
} as const;

webapp/_webapp/src/components/message-entry-container/assistant.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { cn, Tooltip } from "@heroui/react";
22
import { GeneralToolCard } from "./tools/general";
33
import { useCallback, useEffect, useMemo, useState } from "react";
4-
import googleAnalytics from "../../libs/google-analytics";
5-
import { getProjectId } from "../../libs/helpers";
4+
import googleAnalytics from "@/libs/google-analytics";
5+
import { getProjectId } from "@/libs/helpers";
66
import MarkdownComponent from "../markdown";
77
import { TextPatches } from "../text-patches";
8-
import { useAuthStore } from "../../stores/auth-store";
8+
import { useAuthStore } from "@/stores/auth-store";
99
import { Icon } from "@iconify/react/dist/iconify.js";
1010

1111
// Helper functions
@@ -17,10 +17,9 @@ interface ParsedMessage {
1717
const parseMessage = (message: string): ParsedMessage => {
1818
const regex = /<PaperDebugger>([\s\S]*?)<\/PaperDebugger>/g;
1919
const paperDebuggerContents: string[] = [];
20-
let regularContent = message;
2120

2221
// Extract all PaperDebugger blocks
23-
regularContent = message.replace(regex, (_, content) => {
22+
const regularContent = message.replace(regex, (_, content) => {
2423
const processedContent = content.replace(/\n/g, "§NEWLINE§");
2524
paperDebuggerContents.push(processedContent);
2625
return ""; // Remove the tag from regular content
@@ -96,11 +95,11 @@ export const AssistantMessageContainer = ({
9695
<Icon
9796
icon="tabler:pencil"
9897
className={cn(
99-
"!w-4 !h-4 !text-[14px] !text-gray-400 !animate-bounce",
100-
"!transition-all !duration-300 !ease-in-out",
101-
"!inline-block !align-middle !ml-1",
102-
preparing && "!opacity-100",
103-
!preparing && "!opacity-0 !hidden",
98+
"w-4! h-4! text-[14px]! text-gray-400! animate-bounce!",
99+
"transition-all! duration-300! ease-in-out!",
100+
"inline-block! align-middle! ml-1!",
101+
preparing && "opacity-100!",
102+
!preparing && "opacity-0! hidden!",
104103
)}
105104
/>
106105
);
@@ -118,7 +117,7 @@ export const AssistantMessageContainer = ({
118117
return (
119118
showMessage && (
120119
<div className="chat-message-entry noselect">
121-
<div className={cn("message-box-assistant rnd-cancel", messageId.startsWith("error-") && "!text-red-500")}>
120+
<div className={cn("message-box-assistant rnd-cancel", messageId.startsWith("error-") && "text-red-500!")}>
122121
{/* Reasoning content */}
123122
{reasoningComponent}
124123

0 commit comments

Comments
 (0)