fix(deps): migrate Tailwind CSS from v3 to v4 (#711)

This commit is contained in:
Will Pfleger
2026-05-22 20:45:47 -04:00
committed by GitHub
parent 4269fd2720
commit 839097112c
95 changed files with 384 additions and 620 deletions

View File

@@ -77,11 +77,11 @@
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^6.0.0",
"autoprefixer": "^10.4.27",
"@tailwindcss/postcss": "^4.3.0",
"nostr-tools": "^2.23.3",
"postcss": "^8.5.8",
"tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7",
"tailwindcss": "^4.3.0",
"tw-animate-css": "^1.4.0",
"typescript": "~5.9.0",
"vite": "^8.0.0"
}

View File

@@ -1,6 +1,5 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
"@tailwindcss/postcss": {},
},
};

View File

@@ -22,7 +22,7 @@ import { listenForDeepLinks } from "@/shared/deep-link";
function AppLoadingGate() {
return (
<div className="flex min-h-dvh items-center justify-center bg-[radial-gradient(circle_at_top,hsl(var(--primary)/0.14),transparent_48%),linear-gradient(180deg,hsl(var(--background)),hsl(var(--muted)/0.55))] px-4 py-8">
<div className="w-full max-w-sm rounded-[28px] border border-border/70 bg-background/92 p-8 shadow-2xl backdrop-blur">
<div className="w-full max-w-sm rounded-[28px] border border-border/70 bg-background/92 p-8 shadow-2xl backdrop-blur-sm">
<p className="text-xs font-medium uppercase tracking-[0.2em] text-muted-foreground">
Sprout
</p>

View File

@@ -128,7 +128,7 @@ export function AddAgentToChannelDialog({
Channel
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={
channels.length === 0 || attachAgentMutation.isPending
}
@@ -166,7 +166,7 @@ export function AddAgentToChannelDialog({
Role
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={attachAgentMutation.isPending}
id="agent-channel-role"
onChange={(event) =>

View File

@@ -195,7 +195,7 @@ export function AddTeamToChannelDialog({
Channel
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={channels.length === 0 || deployMutation.isPending}
id="team-channel-id"
onChange={(event) => setChannelId(event.target.value)}
@@ -220,7 +220,7 @@ export function AddTeamToChannelDialog({
Role
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={deployMutation.isPending}
id="team-channel-role"
onChange={(event) =>

View File

@@ -113,7 +113,7 @@ function ToolDetailBlocks({
result: string;
}) {
return (
<div className="space-y-4 py-2 pl-5 text-popover-foreground outline-none">
<div className="space-y-4 py-2 pl-5 text-popover-foreground outline-hidden">
{description ? (
<p className="max-w-2xl text-xs leading-5 text-muted-foreground">
{description}

View File

@@ -395,7 +395,7 @@ export function CreateAgentDialog({
Run on
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
id="agent-run-on"
onChange={(e) => handleRunOnChange(e.target.value)}
value={runOn}

View File

@@ -56,7 +56,7 @@ export function CreateAgentRuntimeProviderField({
Agent runtime
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
id="agent-provider"
onChange={(event) => onProviderChange(event.target.value)}
value={selectedProviderId}

View File

@@ -28,7 +28,7 @@ export function ManagedAgentLogPanel({
return (
<section
className={cn(
"border border-border/70 shadow-sm",
"border border-border/70 shadow-xs",
isInline
? "rounded-2xl bg-background/80 p-4"
: "rounded-[28px] bg-card/90 p-5",

View File

@@ -92,7 +92,7 @@ export function ManagedAgentRow({
className={cn(
"overflow-hidden rounded-xl border bg-card/70 transition-colors",
isLogSelected
? "border-primary/40 bg-primary/5 shadow-sm"
? "border-primary/40 bg-primary/5 shadow-xs"
: "border-border/70 hover:bg-muted/20",
)}
data-testid={`managed-agent-${agent.pubkey}`}

View File

@@ -76,7 +76,7 @@ export function ManagedAgentSessionPanel({
return (
<section
className={cn(
"rounded-lg border border-border/70 bg-background/80 p-4 shadow-sm",
"rounded-lg border border-border/70 bg-background/80 p-4 shadow-xs",
className,
)}
>

View File

@@ -76,7 +76,7 @@ export function PersonaCatalogDetailsSheet({
)}
aria-pressed={isSelected}
className={cn(
"w-full rounded-xl border p-4 text-left transition-[background-color,border-color,box-shadow] focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2",
"w-full rounded-xl border p-4 text-left transition-[background-color,border-color,box-shadow] focus:outline-hidden focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2",
isSelected
? "border-primary bg-primary/10 text-foreground"
: "border-border/80 bg-background/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground",

View File

@@ -74,7 +74,7 @@ export function PersonaCatalogSection({
return (
<div
className={cn(
"group relative flex flex-col gap-4 rounded-xl border p-3 shadow-sm transition-[background-color,border-color,box-shadow]",
"group relative flex flex-col gap-4 rounded-xl border p-3 shadow-xs transition-[background-color,border-color,box-shadow]",
isPending
? "cursor-not-allowed opacity-70"
: "cursor-pointer",
@@ -92,7 +92,7 @@ export function PersonaCatalogSection({
isSelected,
)}
aria-pressed={isSelected}
className="absolute inset-0 z-0 rounded-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2"
className="absolute inset-0 z-0 rounded-xl focus:outline-hidden focus-visible:ring-2 focus-visible:ring-primary/40 focus-visible:ring-offset-2"
data-testid={`persona-catalog-card-target-${persona.id}`}
disabled={isPending}
onClick={() => {

View File

@@ -16,7 +16,7 @@ export function PersonaCatalogSelectionBadge({
className={cn(
"inline-flex items-center gap-1 whitespace-nowrap rounded-full px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.14em]",
isActive
? "bg-primary text-primary-foreground shadow-sm"
? "bg-primary text-primary-foreground shadow-xs"
: "border border-border/70 bg-background/85 text-muted-foreground",
)}
>

View File

@@ -353,7 +353,7 @@ export function PersonaDialog({
Preferred runtime
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={isPending || providersLoading}
id="persona-provider"
onChange={(event) => setProvider(event.target.value)}

View File

@@ -115,7 +115,7 @@ export function CreateAgentRespondToField({
Who can talk to this agent
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
data-testid="agent-respond-to-select"
disabled={disabled}
id="agent-respond-to"

View File

@@ -485,7 +485,7 @@ export function AddChannelBotDialog({
<div className="space-y-1.5">
<div className="text-sm font-medium">Run on</div>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={createBotsMutation.isPending}
onChange={(e) => handleRunOnChange(e.target.value)}
value={runOn}

View File

@@ -34,7 +34,7 @@ function SelectionChipButton({
<button
aria-pressed={selected}
className={cn(
"inline-flex min-h-9 items-center gap-2 rounded-full border py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"inline-flex min-h-9 items-center gap-2 rounded-full border py-1.5 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
showAvatar ? "pl-1.5 pr-3" : "px-3",
selected
? "border-primary bg-primary/10 text-foreground"

View File

@@ -24,7 +24,7 @@ export function AddChannelBotReuseGuard({
Agent instance
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs"
disabled={disabled}
id="agent-instance-mode"
onChange={(e) => onForceNewChange(e.target.value === "new")}

View File

@@ -31,7 +31,7 @@ function SelectionChipButton({
<button
aria-pressed={selected}
className={cn(
"inline-flex min-h-9 items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"inline-flex min-h-9 items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
selected
? "border-primary bg-primary/10 text-foreground"
: "border-border/80 bg-background/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground",

View File

@@ -160,7 +160,7 @@ export function BotActivityComposerAction({
<button
aria-label={`${triggerLabel}. View activity.`}
className={cn(
"inline-flex items-center justify-center rounded-full border border-border/60 bg-background font-medium text-muted-foreground transition-colors hover:border-primary/30 hover:bg-primary/5 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring data-[state=open]:border-primary/40 data-[state=open]:bg-primary/10 data-[state=open]:text-primary",
"inline-flex items-center justify-center rounded-full border border-border/60 bg-background font-medium text-muted-foreground transition-colors hover:border-primary/30 hover:bg-primary/5 hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring data-[state=open]:border-primary/40 data-[state=open]:bg-primary/10 data-[state=open]:text-primary",
isInline
? "h-7 min-w-0 gap-2 border-transparent bg-transparent px-0 text-xs font-semibold leading-none shadow-none hover:border-transparent hover:bg-transparent data-[state=open]:border-transparent data-[state=open]:bg-transparent"
: "h-9 min-w-9 gap-1.5 px-2 text-xs",
@@ -183,7 +183,7 @@ export function BotActivityComposerAction({
className={cn(
"rounded-full border border-background",
isInline
? "!h-[18px] !w-[18px] shadow-sm ring-1 ring-primary/25 text-[7px]"
? "!h-[18px] !w-[18px] shadow-xs ring-1 ring-primary/25 text-[7px]"
: "!h-5 !w-5 text-[8px]",
)}
displayName={agent.name}

View File

@@ -203,13 +203,13 @@ export function ChannelBrowserDialog({
>
<DialogHeader className="border-b border-border/80 px-6 py-5">
<DialogTitle className="flex items-center gap-3">
<span className="flex h-10 w-10 items-center justify-center rounded-2xl bg-primary text-primary-foreground shadow-sm">
<span className="flex h-10 w-10 items-center justify-center rounded-2xl bg-primary text-primary-foreground shadow-xs">
<Compass className="h-4 w-4" />
</span>
{browseTitle}
</DialogTitle>
<DialogDescription>{browseDescription}</DialogDescription>
<div className="mt-4 flex items-center gap-3 rounded-2xl border border-input bg-card px-3 py-3 shadow-sm">
<div className="mt-4 flex items-center gap-3 rounded-2xl border border-input bg-card px-3 py-3 shadow-xs">
<Search className="h-4 w-4 text-muted-foreground" />
<Input
className="h-auto border-0 bg-transparent px-0 py-0 text-base shadow-none focus-visible:ring-0"
@@ -354,8 +354,8 @@ function ChannelCard({
<button
className={
isSelected
? "w-full rounded-2xl border border-primary/30 bg-primary/10 px-4 py-4 text-left shadow-sm outline-none transition-colors"
: "w-full rounded-2xl border border-border/80 bg-card/60 px-4 py-4 text-left shadow-sm outline-none transition-colors hover:border-primary/20 hover:bg-accent"
? "w-full rounded-2xl border border-primary/30 bg-primary/10 px-4 py-4 text-left shadow-xs outline-hidden transition-colors"
: "w-full rounded-2xl border border-border/80 bg-card/60 px-4 py-4 text-left shadow-xs outline-hidden transition-colors hover:border-primary/20 hover:bg-accent"
}
data-testid={`browse-channel-${channel.name}`}
onClick={onSelect}

View File

@@ -83,7 +83,7 @@ function ChannelIdRow({ channelId }: { channelId: string }) {
return (
<button
className="group flex w-full items-center gap-3 rounded-xl border border-border/70 bg-muted/20 px-3 py-2.5 text-left transition-colors hover:border-border hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="group flex w-full items-center gap-3 rounded-xl border border-border/70 bg-muted/20 px-3 py-2.5 text-left transition-colors hover:border-border hover:bg-muted/40 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
data-testid="channel-management-channel-id"
onClick={() => {
void handleCopyChannelId();

View File

@@ -55,9 +55,9 @@ export function QuickBotBar({ personas, pending, onAdd }: QuickBotBarProps) {
aria-label={`Add ${persona.displayName}`}
className={cn(
"relative flex h-7 w-7 shrink-0 items-center justify-center rounded-full",
"border border-border/50 shadow-sm",
"border border-border/50 shadow-xs",
"transition-transform duration-150 hover:scale-110",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
isThisPending && "pointer-events-none opacity-60",
)}
disabled={pending}

View File

@@ -72,7 +72,7 @@ export function ForumPostCard({
<div onClick={(e) => e.stopPropagation()} role="presentation">
<UserProfilePopover pubkey={post.pubkey}>
<button
className="flex items-center gap-2 rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="flex items-center gap-2 rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<UserAvatar

View File

@@ -77,7 +77,7 @@ function ReplyRow({
<div className="flex items-center gap-2">
<UserProfilePopover pubkey={reply.pubkey}>
<button
className="flex items-center gap-2 rounded-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="flex items-center gap-2 rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<UserAvatar
@@ -218,7 +218,7 @@ export function ForumThreadPanel({
<div className="flex items-center gap-2">
<UserProfilePopover pubkey={post.pubkey}>
<button
className="flex items-center gap-2 rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="flex items-center gap-2 rounded-xl focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<UserAvatar

View File

@@ -215,7 +215,7 @@ export function InboxDetailPane({
<div className="min-w-0">
{canOpenChannel && contextChannelId && onOpenContext ? (
<button
className="truncate text-left text-sm font-semibold leading-5 tracking-tight text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
className="truncate text-left text-sm font-semibold leading-5 tracking-tight text-foreground hover:underline focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
onClick={() => onOpenContext(contextChannelId, item.id)}
title={item.fullTimestampLabel}
type="button"

View File

@@ -34,7 +34,7 @@ export function InboxListPane({
<div className="flex flex-nowrap gap-1">
{FILTER_OPTIONS.map((option) => (
<Button
className="h-7 rounded-full border border-transparent px-1.5 text-[10.5px] font-medium text-muted-foreground data-[active=true]:border-border/70 data-[active=true]:bg-background/80 data-[active=true]:text-foreground data-[active=true]:shadow-sm data-[active=true]:backdrop-blur-sm"
className="h-7 rounded-full border border-transparent px-1.5 text-[10.5px] font-medium text-muted-foreground data-[active=true]:border-border/70 data-[active=true]:bg-background/80 data-[active=true]:text-foreground data-[active=true]:shadow-xs data-[active=true]:backdrop-blur-sm"
data-active={filter === option.value}
key={option.value}
onClick={() => onFilterChange(option.value)}

View File

@@ -121,7 +121,7 @@ function HexAvatar({
aria-label={ariaLabel ?? `Participant ${pubkey.slice(0, 8)}`}
role="img"
className={cn(
"flex h-7 w-7 items-center justify-center rounded-lg text-[9px] font-semibold shadow-sm",
"flex h-7 w-7 items-center justify-center rounded-lg text-[9px] font-semibold shadow-xs",
isActive &&
"ring-2 ring-green-500 ring-offset-1 ring-offset-background",
)}

View File

@@ -268,7 +268,7 @@ export function useRichTextEditor({
editorProps: {
attributes: {
class:
"min-h-0 resize-none overflow-y-hidden border-0 bg-transparent px-0 py-0 text-sm leading-6 md:leading-6 shadow-none focus-visible:ring-0 caret-foreground outline-none prose-sm max-w-none",
"min-h-0 resize-none overflow-y-hidden border-0 bg-transparent px-0 py-0 text-sm leading-6 md:leading-6 shadow-none focus-visible:ring-0 caret-foreground outline-hidden prose-sm max-w-none",
"data-testid": "message-input",
},
},

View File

@@ -113,7 +113,7 @@ export const ComposerAttachments = React.memo(function ComposerAttachments({
src={rewriteRelayUrl(attachment.url)}
/>
)}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white focus:outline-none focus:ring-2 focus:ring-white/30">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white focus:outline-hidden focus:ring-2 focus:ring-white/30">
<X className="h-5 w-5" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>

View File

@@ -197,7 +197,7 @@ export const FormattingToolbar = React.memo(function FormattingToolbar({
className={cn(
"inline-flex h-7 w-7 min-w-7 items-center justify-center rounded-md text-sm font-medium transition-colors",
"hover:bg-muted hover:text-foreground",
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
"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-3.5 [&_svg]:shrink-0",
item.active

View File

@@ -231,12 +231,12 @@ export function MessageActionBar({
return (
<div
className={cn(
"max-w-36 overflow-hidden rounded-full border border-border/70 bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/85 transition-all duration-150 ease-out",
"max-w-36 overflow-hidden rounded-full border border-border/70 bg-background/95 shadow-xs backdrop-blur-sm supports-[backdrop-filter]:bg-background/85 transition-all duration-150 ease-out",
"translate-y-0 opacity-100 sm:max-w-0 sm:border-0 sm:shadow-none sm:translate-y-1 sm:opacity-0",
"sm:group-hover/message:max-w-36 sm:group-hover/message:border sm:group-hover/message:border-border/70 sm:group-hover/message:shadow-sm sm:group-hover/message:translate-y-0 sm:group-hover/message:opacity-100",
"sm:group-focus-within/message:max-w-36 sm:group-focus-within/message:border sm:group-focus-within/message:border-border/70 sm:group-focus-within/message:shadow-sm sm:group-focus-within/message:translate-y-0 sm:group-focus-within/message:opacity-100",
"sm:group-hover/message:max-w-36 sm:group-hover/message:border sm:group-hover/message:border-border/70 sm:group-hover/message:shadow-xs sm:group-hover/message:translate-y-0 sm:group-hover/message:opacity-100",
"sm:group-focus-within/message:max-w-36 sm:group-focus-within/message:border sm:group-focus-within/message:border-border/70 sm:group-focus-within/message:shadow-xs sm:group-focus-within/message:translate-y-0 sm:group-focus-within/message:opacity-100",
isReplyingToMessage || isReactionPickerOpen || isDropdownOpen
? "sm:max-w-36 sm:border sm:border-border/70 sm:shadow-sm sm:translate-y-0 sm:opacity-100"
? "sm:max-w-36 sm:border sm:border-border/70 sm:shadow-xs sm:translate-y-0 sm:opacity-100"
: "",
)}
data-testid={`message-action-bar-${message.id}`}

View File

@@ -94,7 +94,7 @@ export const MessageComposerToolbar = React.memo(
className={cn(
"inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm font-medium transition-colors",
"hover:bg-muted hover:text-foreground",
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
"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",
isFormattingOpen
@@ -221,7 +221,7 @@ export const MessageComposerToolbar = React.memo(
className={cn(
"inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm font-medium transition-colors",
"hover:bg-muted hover:text-foreground",
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
"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",
isFormattingOpen

View File

@@ -135,7 +135,7 @@ function ReactionPill({
? "border-primary/40 bg-primary/10 text-primary"
: "border-border/70 bg-muted/70 text-foreground/90",
canToggle
? "hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
? "hover:bg-accent hover:text-accent-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
: "cursor-default",
);

View File

@@ -318,7 +318,7 @@ export const MessageRow = React.memo(
>
<button
className={cn(
"flex shrink-0 items-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"flex shrink-0 items-start focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
avatarButtonRadiusClass,
)}
type="button"
@@ -338,7 +338,7 @@ export const MessageRow = React.memo(
botIdenticonValue={message.author}
>
<button
className="truncate rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="truncate rounded focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
{authorNode}
@@ -368,7 +368,7 @@ export const MessageRow = React.memo(
>
<button
className={cn(
"flex shrink-0 items-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"flex shrink-0 items-start focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
avatarButtonRadiusClass,
)}
type="button"
@@ -388,7 +388,7 @@ export const MessageRow = React.memo(
botIdenticonValue={message.author}
>
<button
className="truncate rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="truncate rounded focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
{authorNode}

View File

@@ -290,7 +290,7 @@ export function MessageThreadPanel({
{!isAtBottom ? (
<div className="pointer-events-none absolute inset-x-0 bottom-36 z-20 flex justify-center px-4">
<Button
className="pointer-events-auto h-7 min-h-7 gap-1.5 rounded-full border-border/50 bg-background/85 px-2.5 text-[11px] font-medium text-muted-foreground shadow-sm backdrop-blur-sm hover:bg-muted/70 hover:text-foreground [&_svg]:size-3.5"
className="pointer-events-auto h-7 min-h-7 gap-1.5 rounded-full border-border/50 bg-background/85 px-2.5 text-[11px] font-medium text-muted-foreground shadow-xs backdrop-blur-sm hover:bg-muted/70 hover:text-foreground [&_svg]:size-3.5"
data-testid="thread-scroll-to-latest"
onClick={() => scrollToBottom("smooth")}
size="sm"

View File

@@ -169,7 +169,7 @@ export const MessageTimeline = React.memo(function MessageTimeline({
{!isLoading && messages.length === 0 ? (
<div
className="rounded-3xl border border-dashed border-border/80 bg-card/70 px-6 py-10 text-center shadow-sm"
className="rounded-3xl border border-dashed border-border/80 bg-card/70 px-6 py-10 text-center shadow-xs"
data-testid="message-empty"
>
<p className="text-base font-semibold tracking-tight">
@@ -209,7 +209,7 @@ export const MessageTimeline = React.memo(function MessageTimeline({
{!isAtBottom ? (
<div className="pointer-events-none absolute inset-x-0 bottom-36 z-20 flex justify-center px-4">
<Button
className="pointer-events-auto h-7 min-h-7 gap-1.5 rounded-full border-border/50 bg-background/85 px-2.5 text-[11px] font-medium text-muted-foreground shadow-sm backdrop-blur-sm hover:bg-muted/70 hover:text-foreground [&_svg]:size-3.5"
className="pointer-events-auto h-7 min-h-7 gap-1.5 rounded-full border-border/50 bg-background/85 px-2.5 text-[11px] font-medium text-muted-foreground shadow-xs backdrop-blur-sm hover:bg-muted/70 hover:text-foreground [&_svg]:size-3.5"
data-testid="message-scroll-to-latest"
onClick={() => {
scrollToBottom("smooth");

View File

@@ -79,7 +79,7 @@ function ProfileName({
const node = (
<span
className={cn(
"rounded-sm transition-colors hover:text-foreground",
"rounded-xs transition-colors hover:text-foreground",
pubkey && "cursor-pointer",
highlight &&
"rounded-md bg-primary/15 px-1 py-0.5 font-medium text-primary hover:bg-primary/25 hover:text-primary/90",
@@ -339,12 +339,12 @@ export const SystemMessageRow = React.memo(function SystemMessageRow({
{canToggleReactions ? (
<div
className={cn(
"overflow-hidden rounded-full border border-border/70 bg-background/95 shadow-sm backdrop-blur supports-[backdrop-filter]:bg-background/85 transition-all duration-150 ease-out",
"overflow-hidden rounded-full border border-border/70 bg-background/95 shadow-xs backdrop-blur-sm supports-[backdrop-filter]:bg-background/85 transition-all duration-150 ease-out",
"max-w-0 border-0 shadow-none translate-y-1 opacity-0",
"group-hover/message:max-w-9 group-hover/message:border group-hover/message:border-border/70 group-hover/message:shadow-sm group-hover/message:translate-y-0 group-hover/message:opacity-100",
"group-focus-within/message:max-w-9 group-focus-within/message:border group-focus-within/message:border-border/70 group-focus-within/message:shadow-sm group-focus-within/message:translate-y-0 group-focus-within/message:opacity-100",
"group-hover/message:max-w-9 group-hover/message:border group-hover/message:border-border/70 group-hover/message:shadow-xs group-hover/message:translate-y-0 group-hover/message:opacity-100",
"group-focus-within/message:max-w-9 group-focus-within/message:border group-focus-within/message:border-border/70 group-focus-within/message:shadow-xs group-focus-within/message:translate-y-0 group-focus-within/message:opacity-100",
isReactionPickerOpen
? "max-w-9 border border-border/70 shadow-sm translate-y-0 opacity-100"
? "max-w-9 border border-border/70 shadow-xs translate-y-0 opacity-100"
: "",
)}
>

View File

@@ -41,7 +41,7 @@ export function MembershipDenied({
return (
<div className="flex min-h-dvh items-center justify-center bg-[radial-gradient(circle_at_top,hsl(var(--primary)/0.14),transparent_48%),linear-gradient(180deg,hsl(var(--background)),hsl(var(--muted)/0.55))] px-4 py-8">
<div className="w-full max-w-md rounded-[28px] border border-border/70 bg-background/92 p-8 shadow-2xl backdrop-blur">
<div className="w-full max-w-md rounded-[28px] border border-border/70 bg-background/92 p-8 shadow-2xl backdrop-blur-sm">
<div className="space-y-3">
<Badge variant="warning">Membership required</Badge>
<div className="flex items-center gap-3">

View File

@@ -331,7 +331,7 @@ export function OnboardingFlow({
className="flex min-h-dvh items-center justify-center bg-[radial-gradient(circle_at_top,hsl(var(--primary)/0.16),transparent_44%),linear-gradient(180deg,hsl(var(--background)),hsl(var(--muted)/0.5))] px-4 py-8"
data-testid="onboarding-gate"
>
<div className="w-full max-w-xl rounded-[32px] border border-border/70 bg-background/94 p-6 shadow-2xl backdrop-blur sm:p-8">
<div className="w-full max-w-xl rounded-[32px] border border-border/70 bg-background/94 p-6 shadow-2xl backdrop-blur-sm sm:p-8">
{currentPage === "profile" ? (
<ProfileStep
actions={{

View File

@@ -84,7 +84,7 @@ export function AvatarUpload({
/>
{showClear && onClear ? (
<button
className="absolute -right-1 -top-1 flex h-6 w-6 items-center justify-center rounded-full border border-background bg-destructive text-destructive-foreground shadow-sm transition-colors hover:bg-destructive/80"
className="absolute -right-1 -top-1 flex h-6 w-6 items-center justify-center rounded-full border border-background bg-destructive text-destructive-foreground shadow-xs transition-colors hover:bg-destructive/80"
data-testid={`${testIdPrefix}-clear`}
onClick={onClear}
title="Remove photo"
@@ -93,7 +93,7 @@ export function AvatarUpload({
<X className="h-3 w-3" />
</button>
) : (
<div className="absolute -bottom-1 -right-1 flex h-8 w-8 items-center justify-center rounded-full border border-background bg-primary text-primary-foreground shadow-sm">
<div className="absolute -bottom-1 -right-1 flex h-8 w-8 items-center justify-center rounded-full border border-background bg-primary text-primary-foreground shadow-xs">
<Camera className="h-4 w-4" />
</div>
)}

View File

@@ -24,7 +24,7 @@ export function ProfileAvatar({
return (
<Avatar
className={cn("shrink-0 bg-primary/20 text-primary shadow-sm", className)}
className={cn("shrink-0 bg-primary/20 text-primary shadow-xs", className)}
data-testid={testId}
>
{avatarUrl ? (

View File

@@ -162,12 +162,12 @@ export function UserProfilePanel({
{profile?.avatarUrl ? (
<img
alt={displayName}
className="aspect-square w-full rounded-2xl object-cover shadow-sm"
className="aspect-square w-full rounded-2xl object-cover shadow-xs"
referrerPolicy="no-referrer"
src={rewriteRelayUrl(profile.avatarUrl)}
/>
) : (
<div className="flex aspect-square w-full items-center justify-center rounded-2xl bg-secondary text-5xl font-semibold text-secondary-foreground shadow-sm">
<div className="flex aspect-square w-full items-center justify-center rounded-2xl bg-secondary text-5xl font-semibold text-secondary-foreground shadow-xs">
{displayName.slice(0, 2).toUpperCase()}
</div>
)}

View File

@@ -171,12 +171,12 @@ export function UserProfilePopover({
{profile?.avatarUrl ? (
<img
alt={profile.displayName ?? "User avatar"}
className="h-10 w-10 shrink-0 rounded-xl object-cover shadow-sm"
className="h-10 w-10 shrink-0 rounded-xl object-cover shadow-xs"
referrerPolicy="no-referrer"
src={rewriteRelayUrl(profile.avatarUrl)}
/>
) : (
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-secondary text-xs font-semibold text-secondary-foreground shadow-sm">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-secondary text-xs font-semibold text-secondary-foreground shadow-xs">
{(profile?.displayName ?? pubkey.slice(0, 2))
.slice(0, 2)
.toUpperCase()}

View File

@@ -67,7 +67,7 @@ export function NoteCard({
const [replyDraft, setReplyDraft] = React.useState("");
const replyInputRef = React.useRef<HTMLTextAreaElement>(null);
const actionButtonClass =
"inline-flex min-w-7 items-center gap-1.5 text-muted-foreground/60 transition-colors hover:text-foreground focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
"inline-flex min-w-7 items-center gap-1.5 text-muted-foreground/60 transition-colors hover:text-foreground focus-visible:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring";
const activeActionClass = "text-foreground";
const countPlaceholder = <span aria-hidden className="w-2.5" />;
const currentUserAvatarUrl = currentUserProfile?.avatarUrl ?? null;
@@ -167,7 +167,7 @@ export function NoteCard({
{!isOwnNote ? (
isFollowing ? (
<button
className="text-muted-foreground/60 transition-colors hover:text-foreground hover:underline focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="text-muted-foreground/60 transition-colors hover:text-foreground hover:underline focus-visible:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
onClick={() => onUnfollow?.(note.pubkey)}
type="button"
>
@@ -175,7 +175,7 @@ export function NoteCard({
</button>
) : (
<button
className="text-muted-foreground/60 transition-colors hover:text-foreground hover:underline focus-visible:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="text-muted-foreground/60 transition-colors hover:text-foreground hover:underline focus-visible:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
onClick={() => onFollow?.(note.pubkey)}
type="button"
>
@@ -208,7 +208,7 @@ export function NoteCard({
/>
<div className="min-w-0 flex-1">
<textarea
className="min-h-16 w-full resize-none bg-transparent text-sm text-foreground placeholder:text-muted-foreground/70 focus:outline-none"
className="min-h-16 w-full resize-none bg-transparent text-sm text-foreground placeholder:text-muted-foreground/70 focus:outline-hidden"
onChange={(event) => setReplyDraft(event.target.value)}
placeholder="Post your reply"
ref={replyInputRef}
@@ -218,28 +218,28 @@ export function NoteCard({
<div className="flex items-center gap-1 text-muted-foreground">
<button
aria-label="Mention someone"
className="inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<AtSign className="h-4 w-4" />
</button>
<button
aria-label="Attach media"
className="inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<Paperclip className="h-4 w-4" />
</button>
<button
aria-label="Add emoji"
className="inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<SmilePlus className="h-4 w-4" />
</button>
<button
aria-label="Formatting"
className="inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm font-medium transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="inline-flex h-8 min-w-8 items-center justify-center rounded-md px-2 text-sm font-medium transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
type="button"
>
<ALargeSmall className="h-4 w-4" />
@@ -247,7 +247,7 @@ export function NoteCard({
</div>
<div className="flex items-center gap-2">
<button
className="text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
onClick={() => {
setReplyDraft("");
setIsReplyComposerOpen(false);

View File

@@ -36,7 +36,7 @@ import { UserAvatar } from "@/shared/ui/UserAvatar";
type PulseTab = "search" | "foryou" | "people" | "agents" | "mine";
const tabTriggerClassName =
"h-7 rounded-full px-3.5 py-0 text-xs font-semibold shadow-none transition-colors !text-muted-foreground hover:!text-foreground data-[state=active]:bg-background data-[state=active]:!text-foreground data-[state=active]:shadow-sm dark:!text-white/35 dark:hover:!text-white/70 dark:data-[state=active]:!text-white";
"h-7 rounded-full px-3.5 py-0 text-xs font-semibold shadow-none transition-colors !text-muted-foreground hover:!text-foreground data-[state=active]:bg-background data-[state=active]:!text-foreground data-[state=active]:shadow-xs dark:!text-white/35 dark:hover:!text-white/70 dark:data-[state=active]:!text-white";
type PulseViewProps = {
currentPubkey?: string;
@@ -351,7 +351,7 @@ export function PulseView({ currentPubkey }: PulseViewProps) {
<TabsTrigger
aria-label="Search Pulse"
value="search"
className="h-7 w-7 rounded-full p-0 !text-muted-foreground shadow-none transition-colors hover:!text-foreground data-[state=active]:bg-background data-[state=active]:!text-foreground data-[state=active]:shadow-sm dark:!text-white/35 dark:hover:!text-white/70 dark:data-[state=active]:!text-white"
className="h-7 w-7 rounded-full p-0 !text-muted-foreground shadow-none transition-colors hover:!text-foreground data-[state=active]:bg-background data-[state=active]:!text-foreground data-[state=active]:shadow-xs dark:!text-white/35 dark:hover:!text-white/70 dark:data-[state=active]:!text-white"
>
<Search className="h-4 w-4" />
</TabsTrigger>

View File

@@ -459,7 +459,7 @@ export function RelayMembersSettingsCard({
<div className="relative">
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<input
className="w-full rounded-lg border border-border/70 bg-background/70 py-2 pl-9 pr-3 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="w-full rounded-lg border border-border/70 bg-background/70 py-2 pl-9 pr-3 text-sm placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
data-testid="relay-members-search"
onChange={(event) => setSearch(event.target.value)}
placeholder="Search members by name, npub, or role…"

View File

@@ -65,7 +65,7 @@ export function ChannelFindBar({
className={cn(
"h-7 w-full rounded-md border border-input bg-transparent px-2 pr-20 text-sm",
"placeholder:text-muted-foreground",
"focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
"focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring",
)}
onChange={(event) => onQueryChange(event.target.value)}
onKeyDown={handleKeyDown}

View File

@@ -213,7 +213,7 @@ export function SearchDialog({
>
<DialogHeader className="border-b border-border/80 px-6 py-5">
<DialogTitle className="flex items-center gap-3">
<span className="flex h-10 w-10 items-center justify-center rounded-2xl bg-primary text-primary-foreground shadow-sm">
<span className="flex h-10 w-10 items-center justify-center rounded-2xl bg-primary text-primary-foreground shadow-xs">
<Search className="h-4 w-4" />
</span>
Search
@@ -221,7 +221,7 @@ export function SearchDialog({
<DialogDescription>
Full-text search across accessible channels.
</DialogDescription>
<div className="mt-4 flex items-center gap-3 rounded-2xl border border-input bg-card px-3 py-3 shadow-sm">
<div className="mt-4 flex items-center gap-3 rounded-2xl border border-input bg-card px-3 py-3 shadow-xs">
<Search className="h-4 w-4 text-muted-foreground" />
<Input
autoFocus

View File

@@ -63,8 +63,8 @@ export function SearchResultShell({
<button
className={
isSelected
? "w-full rounded-2xl border border-primary/30 bg-primary/10 px-4 py-4 text-left shadow-sm outline-none transition-colors"
: "w-full rounded-2xl border border-border/80 bg-card/60 px-4 py-4 text-left shadow-sm outline-none transition-colors hover:border-primary/20 hover:bg-accent"
? "w-full rounded-2xl border border-primary/30 bg-primary/10 px-4 py-4 text-left shadow-xs outline-hidden transition-colors"
: "w-full rounded-2xl border border-border/80 bg-card/60 px-4 py-4 text-left shadow-xs outline-hidden transition-colors hover:border-primary/20 hover:bg-accent"
}
data-testid={testId}
onClick={onClick}

View File

@@ -622,7 +622,7 @@ function TemplateTeamSelector({
type="button"
aria-pressed={isSelected}
className={cn(
"inline-flex min-h-9 items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"inline-flex min-h-9 items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
isSelected
? "border-primary bg-primary/10 text-foreground"
: "border-border/80 bg-background/60 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
@@ -765,7 +765,7 @@ function ProviderRow({
<span className="truncate text-sm">{label}</span>
</div>
<select
className="h-7 rounded-md border border-input bg-background px-2 text-xs shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
className="h-7 rounded-md border border-input bg-background px-2 text-xs shadow-xs focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
disabled={disabled}
onChange={(e) => onChange(e.target.value)}
value={value}

View File

@@ -161,7 +161,7 @@ function ThemeSettingsCard() {
<div className="relative mb-3">
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<input
className="w-full rounded-lg border border-border/70 bg-background/70 py-2 pl-9 pr-3 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="w-full rounded-lg border border-border/70 bg-background/70 py-2 pl-9 pr-3 text-sm placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
onChange={(e) => setSearch(e.target.value)}
placeholder="Search themes..."
type="text"
@@ -183,7 +183,7 @@ function ThemeSettingsCard() {
<button
aria-pressed={isActive}
className={cn(
"flex w-full items-center gap-3 px-3 py-2 text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
"flex w-full items-center gap-3 px-3 py-2 text-left text-sm transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring",
isActive
? "bg-primary/10 text-foreground"
: "text-muted-foreground hover:bg-accent hover:text-accent-foreground",

View File

@@ -39,9 +39,9 @@ function SettingsSectionButton({
<button
aria-pressed={active}
className={cn(
"group inline-flex min-w-fit items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium whitespace-nowrap motion-safe:transition-all motion-safe:duration-200 motion-safe:ease-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
"group inline-flex min-w-fit items-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium whitespace-nowrap motion-safe:transition-all motion-safe:duration-200 motion-safe:ease-out focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
active
? "border-border bg-background text-foreground shadow-sm"
? "border-border bg-background text-foreground shadow-xs"
: "border-transparent bg-transparent text-muted-foreground hover:bg-background/70 hover:text-foreground",
isLoaded ? "opacity-100 translate-x-0" : "opacity-0 -translate-x-2",
)}
@@ -159,7 +159,7 @@ export function SettingsView({
</h2>
<button
aria-label="Close settings"
className="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
data-testid="settings-close"
onClick={onClose}
type="button"

View File

@@ -476,7 +476,7 @@ export function AppSidebar({
/>
</div>
<Button
className="w-full justify-between rounded-xl border border-sidebar-border/80 bg-sidebar-accent/60 px-3 text-sidebar-foreground/80 shadow-sm hover:bg-sidebar-accent hover:text-sidebar-foreground"
className="w-full justify-between rounded-xl border border-sidebar-border/80 bg-sidebar-accent/60 px-3 text-sidebar-foreground/80 shadow-xs hover:bg-sidebar-accent hover:text-sidebar-foreground"
data-testid="open-search"
onClick={onOpenSearch}
size="sm"

View File

@@ -274,7 +274,7 @@ export function CreateChannelDialog({
</span>
</label>
<select
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
className="flex h-9 w-full rounded-md border border-input bg-background px-3 py-2 text-sm shadow-xs focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
data-testid="create-channel-template"
disabled={isCreating || templates.length === 0}
id="create-channel-template"

View File

@@ -88,7 +88,7 @@ export function ChannelCombobox({
<button
aria-expanded={open}
className={cn(
"flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
"flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 text-sm shadow-xs transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
!selected && "text-muted-foreground",
)}
disabled={disabled}
@@ -104,7 +104,7 @@ export function ChannelCombobox({
</PopoverTrigger>
<PopoverContent
align="start"
className="w-[--radix-popover-trigger-width] p-0"
className="w-(--radix-popover-trigger-width) p-0"
>
<div className="flex items-center gap-2 border-b border-border px-3 py-2">
<Search className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
@@ -112,7 +112,7 @@ export function ChannelCombobox({
autoCapitalize="off"
autoComplete="off"
ref={(el) => el?.focus()}
className="flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
className="flex-1 bg-transparent text-sm outline-hidden placeholder:text-muted-foreground"
onChange={(e) => {
setQuery(e.target.value);
setHighlightedIndex(0);
@@ -131,7 +131,7 @@ export function ChannelCombobox({
filtered.map((channel, index) => (
<button
className={cn(
"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground",
"flex w-full items-center gap-2 rounded-xs px-2 py-1.5 text-left text-sm transition-colors hover:bg-accent hover:text-accent-foreground",
channel.id === value && "bg-accent/50",
index === highlightedIndex &&
"bg-accent text-accent-foreground",

View File

@@ -64,7 +64,7 @@ export function WorkflowCard({
return (
<div
className={`relative w-full rounded-lg border bg-card p-3 text-left transition-colors hover:bg-muted/50 ${
isActive ? "border-primary/40 bg-primary/5 shadow-sm" : ""
isActive ? "border-primary/40 bg-primary/5 shadow-xs" : ""
}`}
data-testid={`workflow-card-${workflow.id}`}
>

View File

@@ -157,7 +157,7 @@ export function WorkflowDetailPanel({
<div
className={`overflow-hidden rounded-xl border bg-card/70 transition-colors ${
isSelected
? "border-primary/40 bg-primary/5 shadow-sm"
? "border-primary/40 bg-primary/5 shadow-xs"
: "border-border/70 hover:bg-muted/20"
}`}
key={run.id}

View File

@@ -77,7 +77,7 @@ export function WorkflowRunTrace({
return (
<div
className="rounded-xl border border-border/60 bg-background/80 p-3 shadow-sm"
className="rounded-xl border border-border/60 bg-background/80 p-3 shadow-xs"
key={step.stepId}
>
<div className="flex flex-wrap items-center gap-2 text-sm">

View File

@@ -17,7 +17,7 @@ export function FormSelect({
return (
<div className="relative">
<select
className="flex h-9 w-full appearance-none rounded-md border border-input bg-transparent px-3 pr-8 text-sm shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
className="flex h-9 w-full appearance-none rounded-md border border-input bg-transparent px-3 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
disabled={disabled}
id={id}
onChange={(event) => onChange(event.target.value)}

View File

@@ -57,7 +57,7 @@ export function WelcomeSetup({
return (
<div className="flex min-h-dvh items-center justify-center bg-[radial-gradient(circle_at_top,hsl(var(--primary)/0.14),transparent_48%),linear-gradient(180deg,hsl(var(--background)),hsl(var(--muted)/0.55))] px-4 py-8">
<div className="w-full max-w-sm rounded-[28px] border border-border/70 bg-background/92 p-8 shadow-2xl backdrop-blur">
<div className="w-full max-w-sm rounded-[28px] border border-border/70 bg-background/92 p-8 shadow-2xl backdrop-blur-sm">
<p className="text-xs font-medium uppercase tracking-[0.2em] text-muted-foreground">
Sprout
</p>

View File

@@ -116,7 +116,7 @@ export function WorkspaceSwitcher({
</DropdownMenuTrigger>
<DropdownMenuContent
align="start"
className="w-[--radix-dropdown-menu-trigger-width] min-w-[220px]"
className="w-(--radix-dropdown-menu-trigger-width) min-w-[220px]"
onCloseAutoFocus={(e) => e.preventDefault()}
side="bottom"
sideOffset={4}

View File

@@ -67,7 +67,7 @@ export default function rehypeSearchHighlight({ query }: { query: string }) {
tagName: "mark",
properties: {
className:
"rounded-sm bg-primary/20 text-foreground dark:bg-primary/30",
"rounded-xs bg-primary/20 text-foreground dark:bg-primary/30",
},
children: [{ type: "text", value: part }],
});

View File

@@ -1,6 +1,6 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@import "tw-animate-css";
@config "../../../tailwind.config.js";
/* ── Tiptap rich-text composer ──────────────────────────────────────── */
.rich-text-composer .tiptap {

View File

@@ -32,7 +32,7 @@ export function UserAvatar({
return (
<Avatar
className={cn(sizeClasses[size], "rounded-lg shadow-sm", className)}
className={cn(sizeClasses[size], "rounded-lg shadow-xs", className)}
>
{avatarUrl ? (
<AvatarImage

View File

@@ -29,7 +29,7 @@ function LoadingHeaderSkeleton() {
>
<div className="min-w-0 flex-1">
<div className="flex min-w-0 items-center gap-[6px]">
<Skeleton className="h-3.5 w-3.5 rounded-sm" />
<Skeleton className="h-3.5 w-3.5 rounded-xs" />
<Skeleton className="h-4 w-28 max-w-[50vw]" />
</div>
<Skeleton className="mt-2 h-4 w-full max-w-2xl" />

View File

@@ -5,18 +5,18 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/lib/cn";
const buttonVariants = cva(
"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",
"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",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},

View File

@@ -9,7 +9,7 @@ const Card = React.forwardRef<
<div
ref={ref}
className={cn(
"rounded-xl border border-border/70 bg-card/80 text-card-foreground shadow-sm",
"rounded-xl border border-border/70 bg-card/80 text-card-foreground shadow-xs",
className,
)}
{...props}

View File

@@ -11,7 +11,7 @@ const Checkbox = React.forwardRef<
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
"peer h-4 w-4 shrink-0 rounded-xs border border-primary ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className,
)}
{...props}

View File

@@ -25,7 +25,7 @@ const ContextMenuSubTrigger = React.forwardRef<
<ContextMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center gap-2 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",
"flex cursor-default select-none items-center gap-2 rounded-xs 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",
inset && "pl-8",
className,
)}
@@ -79,7 +79,7 @@ const ContextMenuItem = React.forwardRef<
<ContextMenuPrimitive.Item
ref={ref}
className={cn(
"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",
"relative flex cursor-default select-none items-center gap-2 rounded-xs 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",
inset && "pl-8",
className,
)}
@@ -95,7 +95,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
<ContextMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"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",
"relative flex cursor-default select-none items-center rounded-xs 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",
className,
)}
checked={checked}
@@ -119,7 +119,7 @@ const ContextMenuRadioItem = React.forwardRef<
<ContextMenuPrimitive.RadioItem
ref={ref}
className={cn(
"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",
"relative flex cursor-default select-none items-center rounded-xs 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",
className,
)}
{...props}

View File

@@ -42,7 +42,7 @@ const DialogContent = React.forwardRef<
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-md p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-none focus:ring-1 focus:ring-ring">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-md p-1 text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground focus:outline-hidden focus:ring-1 focus:ring-ring">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>

View File

@@ -25,7 +25,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center gap-2 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",
"flex cursor-default select-none items-center gap-2 rounded-xs 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",
inset && "pl-8",
className,
)}
@@ -45,7 +45,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-dropdown-menu-content-transform-origin)",
className,
)}
{...props}
@@ -64,7 +64,7 @@ const DropdownMenuContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-dropdown-menu-content-transform-origin)",
className,
)}
{...props}
@@ -82,7 +82,7 @@ const DropdownMenuItem = React.forwardRef<
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"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",
"relative flex cursor-default select-none items-center gap-2 rounded-xs 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",
inset && "pl-8",
className,
)}
@@ -98,7 +98,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
<DropdownMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"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",
"relative flex cursor-default select-none items-center rounded-xs 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",
className,
)}
checked={checked}
@@ -122,7 +122,7 @@ const DropdownMenuRadioItem = React.forwardRef<
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"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",
"relative flex cursor-default select-none items-center rounded-xs 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",
className,
)}
{...props}

View File

@@ -8,7 +8,7 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base 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 md:text-sm",
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base 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 md:text-sm",
className,
)}
ref={ref}

View File

@@ -86,7 +86,7 @@ function ImageContextMenu({
>
<button
type="button"
className="flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground"
className="flex w-full cursor-default select-none items-center rounded-xs px-2 py-1.5 text-sm outline-hidden hover:bg-accent hover:text-accent-foreground"
onClick={() => {
setMenu(null);
invokeTauri("download_image", { url: src }).catch(
@@ -151,14 +151,14 @@ function MarkdownCodeBlock({ children }: { children?: React.ReactNode }) {
return (
<div className="group relative">
<pre className="overflow-x-auto rounded-xl border border-border/70 bg-muted/60 px-3 py-1.5 pr-12 shadow-sm">
<pre className="overflow-x-auto rounded-xl border border-border/70 bg-muted/60 px-3 py-1.5 pr-12 shadow-xs">
{children}
</pre>
<Tooltip>
<TooltipTrigger asChild>
<Button
aria-label="Copy code block"
className="absolute right-2 top-2 h-7 w-7 bg-background/80 text-muted-foreground opacity-0 shadow-sm ring-1 ring-border/60 backdrop-blur transition-opacity hover:bg-background hover:text-foreground hover:opacity-100 focus-visible:opacity-100 group-hover:opacity-100 group-focus-within:opacity-100 disabled:opacity-60"
className="absolute right-2 top-2 h-7 w-7 bg-background/80 text-muted-foreground opacity-0 shadow-xs ring-1 ring-border/60 backdrop-blur-sm transition-opacity hover:bg-background hover:text-foreground hover:opacity-100 focus-visible:opacity-100 group-hover:opacity-100 group-focus-within:opacity-100 disabled:opacity-60"
disabled={isCopying}
onClick={handleCopy}
size="icon"
@@ -313,7 +313,7 @@ function createMarkdownComponents(
onContextMenu={(e) => e.preventDefault()}
/>
</ImageContextMenu>
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white focus:outline-none focus:ring-2 focus:ring-white/30">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-full bg-black/50 p-2 text-white/80 transition-colors hover:bg-black/70 hover:text-white focus:outline-hidden focus:ring-2 focus:ring-white/30">
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"

View File

@@ -19,7 +19,7 @@ const PopoverContent = React.forwardRef<
align={align}
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-popover-content-transform-origin)",
className,
)}
{...props}

View File

@@ -64,7 +64,7 @@ const SheetContent = React.forwardRef<
className={cn(sheetVariants({ side }), className)}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>

View File

@@ -186,7 +186,7 @@ const Sidebar = React.forwardRef<
return (
<div
className={cn(
"flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",
"flex h-full w-(--sidebar-width) flex-col bg-sidebar text-sidebar-foreground",
className,
)}
ref={ref}
@@ -203,7 +203,7 @@ const Sidebar = React.forwardRef<
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
className="w-(--sidebar-width) bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
style={
{
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
@@ -233,24 +233,24 @@ const Sidebar = React.forwardRef<
{/* This is what handles the sidebar gap on desktop */}
<div
className={cn(
"relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear",
"relative w-(--sidebar-width) bg-transparent transition-[width] duration-200 ease-linear",
"group-data-[collapsible=offcanvas]:w-0",
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_16px)]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
)}
/>
<div
className={cn(
"absolute inset-y-0 z-10 hidden h-full w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex",
"absolute inset-y-0 z-10 hidden h-full w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
// Adjust the padding for floating and inset variants.
variant === "floating" || variant === "inset"
? "p-[8px] group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_18px)]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
className,
)}
{...props}
@@ -448,7 +448,7 @@ const SidebarGroupLabel = React.forwardRef<
ref={ref}
data-sidebar="group-label"
className={cn(
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-hidden ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
className,
)}
@@ -469,7 +469,7 @@ const SidebarGroupAction = React.forwardRef<
ref={ref}
data-sidebar="group-action"
className={cn(
"absolute right-3 top-3.5 z-10 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"absolute right-3 top-3.5 z-10 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden",
"group-data-[collapsible=icon]:hidden",
@@ -521,7 +521,7 @@ const SidebarMenuItem = React.forwardRef<
SidebarMenuItem.displayName = "SidebarMenuItem";
const sidebarMenuButtonVariants = cva(
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-primary data-[active=true]:font-semibold data-[active=true]:text-sidebar-primary-foreground data-[active=true]:shadow-sm data-[active=true]:hover:bg-sidebar-primary data-[active=true]:hover:text-sidebar-primary-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-primary data-[active=true]:font-semibold data-[active=true]:text-sidebar-primary-foreground data-[active=true]:shadow-xs data-[active=true]:hover:bg-sidebar-primary data-[active=true]:hover:text-sidebar-primary-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
{
variants: {
variant: {
@@ -615,7 +615,7 @@ const SidebarMenuAction = React.forwardRef<
ref={ref}
data-sidebar="menu-action"
className={cn(
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-hidden ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden",
"peer-data-[size=sm]/menu-button:top-1",
@@ -678,7 +678,7 @@ const SidebarMenuSkeleton = React.forwardRef<
/>
)}
<Skeleton
className="h-4 max-w-[--skeleton-width] flex-1"
className="h-4 max-w-(--skeleton-width) flex-1"
data-sidebar="menu-skeleton-text"
style={
{
@@ -731,7 +731,7 @@ const SidebarMenuSubButton = React.forwardRef<
data-size={size}
data-active={isActive}
className={cn(
"flex h-7 min-w-0 items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground data-[active=true]:[&>svg]:text-sidebar-primary-foreground",
"flex h-7 min-w-0 items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-hidden ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground data-[active=true]:[&>svg]:text-sidebar-primary-foreground",
"data-[active=true]:bg-sidebar-primary data-[active=true]:font-semibold data-[active=true]:text-sidebar-primary-foreground data-[active=true]:hover:bg-sidebar-primary data-[active=true]:hover:text-sidebar-primary-foreground",
size === "sm" && "text-xs",
size === "md" && "text-sm",

View File

@@ -9,7 +9,7 @@ const Switch = React.forwardRef<
>(({ className, ...props }, ref) => (
<SwitchPrimitives.Root
className={cn(
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-xs transition-colors focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
className,
)}
{...props}

View File

@@ -27,7 +27,7 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
className,
)}
{...props}
@@ -42,7 +42,7 @@ const TabsContent = React.forwardRef<
<TabsPrimitive.Content
ref={ref}
className={cn(
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
"mt-2 ring-offset-background focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
className,
)}
{...props}

View File

@@ -9,7 +9,7 @@ const Textarea = React.forwardRef<
return (
<textarea
className={cn(
"flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
ref={ref}

View File

@@ -5,13 +5,13 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/lib/cn";
const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-primary data-[state=on]:text-primary-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-primary data-[state=on]:text-primary-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default: "bg-transparent",
outline:
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-9 px-3 min-w-9",

View File

@@ -18,7 +18,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin)",
className,
)}
{...props}

View File

@@ -1,9 +1,5 @@
import tailwindcssAnimate from "tailwindcss-animate";
/** @type {import('tailwindcss').Config} */
export default {
darkMode: ["class"],
content: ["./index.html", "./src/**/*.{ts,tsx}"],
theme: {
extend: {
borderRadius: {
@@ -67,5 +63,5 @@ export default {
},
},
},
plugins: [tailwindcssAnimate],
plugins: [],
};

645
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -42,10 +42,10 @@
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^6.0.0",
"autoprefixer": "^10.4.27",
"@tailwindcss/postcss": "^4.3.0",
"postcss": "^8.5.8",
"tailwindcss": "^3.4.17",
"tailwindcss-animate": "^1.0.7",
"tailwindcss": "^4.3.0",
"tw-animate-css": "^1.4.0",
"typescript": "~5.9.0",
"vite": "^8.0.0"
}

View File

@@ -1,6 +1,5 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
"@tailwindcss/postcss": {},
},
};

View File

@@ -146,7 +146,7 @@ export function ReposPage() {
value={sort}
onChange={(e) => setSort(e.target.value as SortOrder)}
aria-label="Sort repositories"
className="rounded-md border border-input bg-background px-3 py-1 text-sm text-foreground shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
className="rounded-md border border-input bg-background px-3 py-1 text-sm text-foreground shadow-xs focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring"
>
<option value="newest">Newest</option>
<option value="oldest">Oldest</option>

View File

@@ -1,6 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "tailwindcss";
@import "tw-animate-css";
@plugin "@tailwindcss/typography";
@config "../../../tailwind.config.js";
@layer base {
:root {

View File

@@ -2,7 +2,7 @@ import { cn } from "@/shared/lib/cn";
import { type VariantProps, cva } from "class-variance-authority";
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
"inline-flex items-center rounded-md border px-2 py-0.5 text-xs font-medium transition-colors focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2",
{
variants: {
variant: {

View File

@@ -5,18 +5,18 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/lib/cn";
const buttonVariants = cva(
"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",
"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",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
"bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
"border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},

View File

@@ -9,7 +9,7 @@ const Card = React.forwardRef<
<div
ref={ref}
className={cn(
"rounded-xl border border-border/70 bg-card/80 text-card-foreground shadow-sm",
"rounded-xl border border-border/70 bg-card/80 text-card-foreground shadow-xs",
className,
)}
{...props}

View File

@@ -8,7 +8,7 @@ const Input = forwardRef<
<input
type={type}
className={cn(
"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 placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
"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 placeholder:text-muted-foreground focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}

View File

@@ -18,7 +18,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin)",
className,
)}
{...props}

View File

@@ -1,10 +1,5 @@
import tailwindcssAnimate from "tailwindcss-animate";
import tailwindcssTypography from "@tailwindcss/typography";
/** @type {import('tailwindcss').Config} */
export default {
darkMode: ["class"],
content: ["./index.html", "./src/**/*.{ts,tsx}"],
theme: {
extend: {
borderRadius: {
@@ -68,5 +63,4 @@ export default {
},
},
},
plugins: [tailwindcssAnimate, tailwindcssTypography],
};