Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .server-changes/tailwind-v4-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: improvement
---

Migrated the webapp to Tailwind CSS v4 with a CSS-first `@theme`. Semantic color tokens are now CSS variables overridable per theme (multi-theme support). Tailwind runs through `@tailwindcss/postcss`; plugins replaced or upgraded to v4-compatible versions.
6 changes: 6 additions & 0 deletions .server-changes/theme-color-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
area: webapp
type: improvement
---

Replaced raw charcoal-* Tailwind classes with semantic theme tokens (surfaces, borders, text) across the dashboard. Adds surface/border/text tokens to the themable layer so future themes only override CSS variables.
16 changes: 8 additions & 8 deletions apps/webapp/app/components/AskAI.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ function AskAIDialog({ initialQuery, isOpen, onOpenChange, closeAskAI }: AskAIDi
return (
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
<DialogContent className="animated-gradient-glow flex max-h-[90vh] min-h-fit w-full flex-col justify-between gap-0 px-0 pb-0 pt-0 sm:max-w-prose">
<DialogHeader className="flex h-[2.75rem] items-start justify-center rounded-t-md bg-background-bright pl-3">
<DialogHeader className="flex h-11 items-start justify-center rounded-t-md bg-background-bright pl-3">
<div className="flex items-center gap-1">
<AISparkleIcon className="size-5" />
<DialogTitle className="text-sm font-medium text-text-bright">Ask AI</DialogTitle>
Expand Down Expand Up @@ -226,7 +226,7 @@ function ChatMessages({
];

return (
<div className="flex-1 overflow-y-auto p-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600">
<div className="flex-1 overflow-y-auto p-4 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control">
{conversation.length === 0 ? (
<motion.div
className="flex flex-col gap-2 pb-2"
Expand All @@ -249,7 +249,7 @@ function ChatMessages({
{exampleQuestions.map((question, index) => (
<motion.button
key={index}
className="group flex w-fit items-center gap-2 rounded-full border border-dashed border-charcoal-600 px-4 py-2 transition-colors hover:border-solid hover:border-indigo-500"
className="group flex w-fit items-center gap-2 rounded-full border border-dashed border-border-bright px-4 py-2 transition-colors hover:border-solid hover:border-indigo-500"
onClick={() => onExampleClick(question)}
variants={{
hidden: {
Expand Down Expand Up @@ -468,7 +468,7 @@ function ChatInterface({ initialQuery }: { initialQuery?: string }) {
error={error}
addFeedback={addFeedback}
/>
<form onSubmit={handleSubmit} className="flex-shrink-0 border-t border-grid-bright p-4">
<form onSubmit={handleSubmit} className="shrink-0 border-t border-grid-bright p-4">
<div className="flex gap-3">
<input
type="text"
Expand Down Expand Up @@ -511,7 +511,7 @@ function ChatInterface({ initialQuery }: { initialQuery?: string }) {
disabled={!message.trim()}
LeadingIcon={<ArrowUpIcon className="size-5 text-text-bright" />}
variant="primary/large"
className="size-10 min-w-10 rounded-full group-disabled/button:border-charcoal-550 group-disabled/button:bg-charcoal-600"
className="size-10 min-w-10 rounded-full group-disabled/button:border-border-brighter group-disabled/button:bg-surface-control"
/>
)}
</div>
Expand All @@ -531,11 +531,11 @@ function GradientSpinnerBackground({
}) {
return (
<div
className={`flex rounded-full bg-gradient-to-br from-indigo-500 via-purple-500 to-fuchsia-500 p-px ${className}`}
className={`flex rounded-full bg-linear-to-br from-indigo-500 via-purple-500 to-fuchsia-500 p-px ${className}`}
>
<div
className={`flex h-full w-full items-center justify-center rounded-full bg-charcoal-600 ${
hoverEffect ? "transition group-hover:bg-charcoal-550" : ""
className={`flex h-full w-full items-center justify-center rounded-full bg-surface-control ${
hoverEffect ? "transition group-hover:bg-surface-control-hover" : ""
}`}
>
{children}
Expand Down
6 changes: 3 additions & 3 deletions apps/webapp/app/components/BackgroundWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function BackgroundWrapper({ children }: { children: ReactNode }) {
return (
<div className="relative h-full w-full overflow-hidden bg-background-dimmed lg:bg-transparent">
<div
className="absolute left-0 top-0 hidden w-[260px] bg-contain bg-left-top bg-no-repeat lg:block"
className="absolute left-0 top-0 hidden w-[260px] bg-contain bg-top-left bg-no-repeat lg:block"
style={{
backgroundImage: `url(${blurredDashboardBackgroundMenuTop})`,
aspectRatio: "auto",
Expand All @@ -17,7 +17,7 @@ export function BackgroundWrapper({ children }: { children: ReactNode }) {
/>

<div
className="absolute bottom-0 left-0 hidden w-[260px] bg-contain bg-left-bottom bg-no-repeat lg:block"
className="absolute bottom-0 left-0 hidden w-[260px] bg-contain bg-bottom-left bg-no-repeat lg:block"
style={{
backgroundImage: `url(${blurredDashboardBackgroundMenuBottom})`,
aspectRatio: "auto",
Expand All @@ -27,7 +27,7 @@ export function BackgroundWrapper({ children }: { children: ReactNode }) {
/>

<div
className="absolute top-0 hidden bg-left-top bg-no-repeat lg:block"
className="absolute top-0 hidden bg-top-left bg-no-repeat lg:block"
style={{
left: "260px",
backgroundImage: `url(${blurredDashboardBackgroundTable})`,
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/BlankStatePanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export function DeploymentsNoneDev() {
organization={organization}
project={project}
environment={environment}
className="w-fit border border-charcoal-600 bg-secondary hover:border-charcoal-550 hover:bg-charcoal-600"
className="w-fit border border-border-bright bg-secondary hover:border-border-brighter hover:bg-surface-control"
/>
</StepContentContainer>
</>
Expand Down
4 changes: 2 additions & 2 deletions apps/webapp/app/components/DefinitionTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export function DefinitionTip({
<TooltipProvider>
<Tooltip disableHoverableContent={disableHoverableContent}>
<TooltipTrigger className="text-left">
<span className="cursor-default underline decoration-charcoal-500 decoration-dashed underline-offset-4 transition hover:decoration-charcoal-400">
<span className="cursor-default underline decoration-text-faint decoration-dashed underline-offset-4 transition hover:decoration-text-dimmed">
{children}
</span>
</TooltipTrigger>
<TooltipContent align="end" side="right" className="w-[16rem] min-w-[16rem]">
<TooltipContent align="end" side="right" className="w-64 min-w-64">
<Header3 className="mb-1">{title}</Header3>
{typeof content === "string" ? (
<Paragraph variant="small">{content}</Paragraph>
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function Feedback({ button, defaultValue = "bug", onOpenChange }: Feedbac
<DialogHeader>Contact us</DialogHeader>
<div className="mt-2 flex flex-col gap-4">
<div className="flex items-center gap-4">
<Icon icon={EnvelopeIcon} className="size-10 min-w-[2.5rem] text-blue-500" />
<Icon icon={EnvelopeIcon} className="size-10 min-w-10 text-blue-500" />
<Paragraph variant="base/bright">
How can we help? We read every message and will respond as quickly as we can.
</Paragraph>
Expand Down
6 changes: 3 additions & 3 deletions apps/webapp/app/components/GitMetadata.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function GitMetadataBranch({
leadingIconClassName="group-hover/table-row:text-text-bright"
iconSpacing="gap-x-1"
to={git.branchUrl}
className="pl-1 duration-0 [&_span]:duration-0 [&_span]:group-hover/table-row:text-text-bright"
className="pl-1 duration-0 [&_span]:duration-0 group-hover/table-row:[&_span]:text-text-bright"
>
{git.branchName}
</LinkButton>
Expand All @@ -52,7 +52,7 @@ export function GitMetadataCommit({
LeadingIcon={<GitCommitIcon className="size-4" />}
leadingIconClassName="group-hover/table-row:text-text-bright"
iconSpacing="gap-x-1"
className="pl-1 duration-0 [&_span]:duration-0 [&_span]:group-hover/table-row:text-text-bright"
className="pl-1 duration-0 [&_span]:duration-0 group-hover/table-row:[&_span]:text-text-bright"
>
{`${git.shortSha} / ${git.commitMessage}`}
</LinkButton>
Expand All @@ -78,7 +78,7 @@ export function GitMetadataPullRequest({
LeadingIcon={<GitPullRequestIcon className="size-4" />}
leadingIconClassName="group-hover/table-row:text-text-bright"
iconSpacing="gap-x-1"
className="pl-1 duration-0 [&_span]:duration-0 [&_span]:group-hover/table-row:text-text-bright"
className="pl-1 duration-0 [&_span]:duration-0 group-hover/table-row:[&_span]:text-text-bright"
>
#{git.pullRequestNumber} {git.pullRequestTitle}
</LinkButton>
Expand Down
6 changes: 3 additions & 3 deletions apps/webapp/app/components/ListPagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function ListPagination({ list, className }: { list: List; className?: st
<NextButton cursor={list.pagination.next} />
<div
className={cn(
"order-2 h-6 w-px bg-charcoal-600 transition-colors peer-hover/next:bg-charcoal-550 peer-hover/prev:bg-charcoal-550",
"order-2 h-6 w-px bg-surface-control transition-colors peer-hover/next:bg-surface-control-hover peer-hover/prev:bg-surface-control-hover",
bothDisabled && "opacity-30"
)}
/>
Expand All @@ -41,7 +41,7 @@ function PreviousButton({ cursor }: { cursor?: string }) {
variant={"secondary/small"}
LeadingIcon={ChevronLeftIcon}
className={cn(
"flex items-center rounded-r-none border-r-0 pl-2 pr-[0.5625rem]",
"flex items-center rounded-r-none border-r-0 pl-2 pr-2.25",
!path && "cursor-not-allowed opacity-50"
)}
onClick={(e) => !path && e.preventDefault()}
Expand All @@ -63,7 +63,7 @@ function NextButton({ cursor }: { cursor?: string }) {
variant={"secondary/small"}
TrailingIcon={ChevronRightIcon}
className={cn(
"flex items-center rounded-l-none border-l-0 pl-[0.5625rem] pr-2",
"flex items-center rounded-l-none border-l-0 pl-2.25 pr-2",
!path && "cursor-not-allowed opacity-50"
)}
onClick={(e) => !path && e.preventDefault()}
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/LoginPageLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export function LoginPageLayout({ children }: { children: React.ReactNode }) {
</div>
<div className="flex flex-col items-center gap-4 px-8">
<Paragraph>Trusted by developers at</Paragraph>
<div className="flex w-full flex-wrap items-center justify-center gap-x-6 gap-y-3 text-charcoal-500 xl:justify-between xl:gap-0">
<div className="flex w-full flex-wrap items-center justify-center gap-x-6 gap-y-3 text-text-faint xl:justify-between xl:gap-0">
<LyftLogo className="w-11" />
<UnkeyLogo />
<MiddayLogo />
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/ProductHuntBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function ProductHuntBanner() {
<LinkButton
to="https://www.producthunt.com/posts/trigger-dev"
target="_blank"
className="!text-white underline underline-offset-2 transition hover:decoration-charcoal-100 hover:decoration-2"
className="text-white! underline underline-offset-2 transition hover:decoration-text-bright hover:decoration-2"
variant="tertiary/small"
>
Vote for us today only!
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/UserProfilePhoto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ export function UserAvatar({
/>
</div>
) : (
<UserCircleIcon className={cn("aspect-square text-charcoal-400", className)} />
<UserCircleIcon className={cn("aspect-square text-text-dimmed", className)} />
);
}
6 changes: 3 additions & 3 deletions apps/webapp/app/components/WarmStarts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function WarmStartIconWithTooltip({
}) {
return (
<SimpleTooltip
className="relative z-[9999]"
className="relative z-9999"
button={<WarmStartIcon isWarmStart={isWarmStart} className={className} />}
content={<WarmStartTooltipContent />}
/>
Expand All @@ -42,14 +42,14 @@ function WarmStartTooltipContent() {
<div className="flex max-w-xs flex-col gap-4 p-1">
<div>
<WarmStartCombo isWarmStart={false} className="mb-0.5 text-text-bright" />
<Paragraph variant="small" className="!text-wrap text-text-dimmed">
<Paragraph variant="small" className="text-wrap! text-text-dimmed">
A cold start happens when we need to boot up a new machine for your run to execute. This
takes longer than a warm start.
</Paragraph>
</div>
<div>
<WarmStartCombo isWarmStart={true} className="mb-0.5 text-text-bright" />
<Paragraph variant="small" className="!text-wrap text-text-dimmed">
<Paragraph variant="small" className="text-wrap! text-text-dimmed">
A warm start happens when we can reuse a machine from a run that recently finished. This
takes less time than a cold start.
</Paragraph>
Expand Down
12 changes: 6 additions & 6 deletions apps/webapp/app/components/admin/FeatureFlagsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,14 @@ export function FeatureFlagsDialog({
return (
<div
key={key}
className="flex items-center justify-between rounded-md border border-transparent bg-charcoal-750 px-3 py-2.5"
className="flex items-center justify-between rounded-md border border-transparent bg-background-hover px-3 py-2.5"
title="Global-level setting - not editable per org"
>
<div className="min-w-0 flex-1">
<div className="truncate text-sm text-text-dimmed">{key}</div>
<div className="text-xs text-charcoal-400">global: {globalDisplay}</div>
<div className="text-xs text-text-dimmed">global: {globalDisplay}</div>
</div>
<LockClosedIcon className="size-4 text-charcoal-500" />
<LockClosedIcon className="size-4 text-text-faint" />
</div>
);
}
Expand All @@ -187,7 +187,7 @@ export function FeatureFlagsDialog({
"flex items-center justify-between rounded-md border px-3 py-2.5",
isOverridden
? "border-indigo-500/20 bg-indigo-500/5"
: "border-transparent bg-charcoal-750"
: "border-transparent bg-background-hover"
)}
>
<div className="min-w-0 flex-1">
Expand All @@ -199,7 +199,7 @@ export function FeatureFlagsDialog({
>
{key}
</div>
<div className="text-xs text-charcoal-400">global: {globalDisplay}</div>
<div className="text-xs text-text-dimmed">global: {globalDisplay}</div>
</div>

<div className="flex items-center gap-2">
Expand Down Expand Up @@ -283,7 +283,7 @@ export function FeatureFlagsDialog({
<summary className="cursor-pointer text-xs text-text-dimmed hover:text-text-bright">
Preview JSON
</summary>
<pre className="mt-1 max-h-40 overflow-auto rounded bg-charcoal-800 p-2 text-xs text-text-dimmed">
<pre className="mt-1 max-h-40 overflow-auto rounded bg-background-bright p-2 text-xs text-text-dimmed">
{jsonPreview}
</pre>
</details>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function MaxProjectsSection({
}, [savedJustNow, hasFieldErrors]);

return (
<section className="flex flex-col gap-3 rounded-md border border-charcoal-700 bg-charcoal-800 p-4">
<section className="flex flex-col gap-3 rounded-md border border-grid-bright bg-background-bright p-4">
<div className="flex items-center justify-between">
<Header2>Maximum projects</Header2>
{!isEditing && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export function RateLimitSection({
};

return (
<section className="flex flex-col gap-3 rounded-md border border-charcoal-700 bg-charcoal-800 p-4">
<section className="flex flex-col gap-3 rounded-md border border-grid-bright bg-background-bright p-4">
<div className="flex items-center justify-between">
<Header2>{title}</Header2>
{!isEditing && (
Expand Down
9 changes: 7 additions & 2 deletions apps/webapp/app/components/billing/FreePlanUsage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { ArrowUpCircleIcon } from "@heroicons/react/24/outline";
import { Link } from "@remix-run/react";
import { motion, useMotionValue, useTransform } from "framer-motion";
import { useThemeColor } from "~/hooks/useThemeColor";
import { cn } from "~/utils/cn";

export function FreePlanUsage({ to, percentage }: { to: string; percentage: number }) {
const cappedPercentage = Math.min(percentage, 1);
const widthProgress = useMotionValue(cappedPercentage * 100);
// Resolved to concrete colors - framer-motion can't interpolate var() strings
const successColor = useThemeColor("--color-success", "#28bf5c");
const warningColor = useThemeColor("--color-warning", "#f59e0b");
const errorColor = useThemeColor("--color-error", "#e11d48");
const color = useTransform(
widthProgress,
[0, 74, 75, 95, 100],
["#22C55E", "#22C55E", "#F59E0B", "#F43F5E", "#F43F5E"]
[successColor, successColor, warningColor, errorColor, errorColor]
);

const hasHitLimit = cappedPercentage >= 1;

return (
<div
className={cn(
"rounded border border-charcoal-700 bg-charcoal-750 p-2.5",
"rounded border border-grid-bright bg-background-hover p-2.5",
hasHitLimit && "border-error/40"
)}
>
Expand Down
2 changes: 1 addition & 1 deletion apps/webapp/app/components/billing/UsageBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function Legend({ text, value, position, percentage, tooltipContent }: LegendPro
return (
<div
className={cn(
"absolute left-full z-10 flex border-charcoal-500",
"absolute left-full z-10 flex border-border-brightest",
positions[position],
flipLegendPosition === true ? "-translate-x-full border-r" : "border-l"
)}
Expand Down
Loading
Loading