refactor: remove gh/GitHub references from tokens, classes, and component names
Rename all --color-gh-* CSS tokens to --color-*, update Tailwind class names (bg-gh-*, text-gh-*, border-gh-*, etc.) across all TSX/TS files, rename GhButton component and file to Button, and remove trivial descriptive comments.
This commit is contained in:
@@ -8,7 +8,7 @@ interface AppShellProps {
|
||||
|
||||
export function AppShell({ children, showUsers }: AppShellProps) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gh-base">
|
||||
<div className="min-h-screen bg-base">
|
||||
<Sidebar showUsers={showUsers} />
|
||||
{/* Offset for sidebar (desktop: left margin, mobile: bottom padding) */}
|
||||
<div className="pb-14 md:pb-0 md:pl-14">
|
||||
|
||||
@@ -9,11 +9,11 @@ interface BadgeProps {
|
||||
}
|
||||
|
||||
const variantClasses: Record<BadgeVariant, string> = {
|
||||
green: 'bg-gh-green-bg text-gh-green border border-gh-green/20',
|
||||
yellow: 'bg-gh-yellow-bg text-gh-yellow border border-gh-yellow/20',
|
||||
red: 'bg-gh-red-bg text-gh-red border border-gh-red/20',
|
||||
blue: 'bg-gh-blue-bg text-gh-blue border border-gh-blue/20',
|
||||
gray: 'bg-gh-overlay text-gh-muted border border-gh-border',
|
||||
green: 'bg-green-bg text-green border border-green/20',
|
||||
yellow: 'bg-yellow-bg text-yellow border border-yellow/20',
|
||||
red: 'bg-red-bg text-red border border-red/20',
|
||||
blue: 'bg-blue-bg text-blue border border-blue/20',
|
||||
gray: 'bg-overlay text-muted border border-border',
|
||||
};
|
||||
|
||||
export function Badge({ variant, children, className }: BadgeProps) {
|
||||
|
||||
73
src/components/ui/Button.tsx
Executable file → Normal file
73
src/components/ui/Button.tsx
Executable file → Normal file
@@ -1,46 +1,47 @@
|
||||
import { forwardRef, ButtonHTMLAttributes } from 'react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { LoadingSpinner } from './LoadingSpinner';
|
||||
import { ButtonHTMLAttributes } from 'react';
|
||||
|
||||
type ButtonVariant = 'primary' | 'ghost' | 'danger-outline' | 'danger-solid';
|
||||
type ButtonSize = 'sm' | 'md';
|
||||
|
||||
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
isLoading?: boolean;
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
}
|
||||
|
||||
const baseClasses =
|
||||
'inline-flex items-center justify-center font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed';
|
||||
|
||||
const variants = {
|
||||
primary: 'bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500',
|
||||
secondary: 'bg-gray-600 text-white hover:bg-gray-700 focus:ring-gray-500',
|
||||
danger: 'bg-red-600 text-white hover:bg-red-700 focus:ring-red-500',
|
||||
ghost: 'text-gray-300 hover:text-white hover:bg-gray-700 focus:ring-gray-500'
|
||||
const variantClasses: Record<ButtonVariant, string> = {
|
||||
primary: 'bg-btn-green border border-btn-green-hover text-white hover:bg-btn-green-hover',
|
||||
ghost: 'bg-transparent border border-border text-secondary hover:bg-overlay hover:text-primary',
|
||||
'danger-outline': 'bg-transparent border border-border text-red hover:border-red/40 hover:bg-red-bg',
|
||||
'danger-solid': 'bg-overlay border border-red/20 text-red hover:bg-red-bg',
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
sm: 'px-3 py-1 text-sm',
|
||||
const sizeClasses: Record<ButtonSize, string> = {
|
||||
sm: 'px-3 py-1.5 text-xs',
|
||||
md: 'px-4 py-2 text-sm',
|
||||
lg: 'px-6 py-3 text-base'
|
||||
};
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
(
|
||||
{ className, variant = 'primary', size = 'md', isLoading, children, disabled, ...props },
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<button
|
||||
className={cn(baseClasses, variants[variant], sizes[size], className)}
|
||||
disabled={disabled || isLoading}
|
||||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
{isLoading && <LoadingSpinner size="sm" className="mr-2" />}
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Button.displayName = 'Button';
|
||||
export function Button({
|
||||
variant = 'ghost',
|
||||
size = 'md',
|
||||
className,
|
||||
children,
|
||||
disabled,
|
||||
...props
|
||||
}: ButtonProps) {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1.5 justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-blue focus:ring-offset-1 focus:ring-offset-base',
|
||||
'disabled:cursor-not-allowed disabled:opacity-40',
|
||||
variantClasses[variant],
|
||||
sizeClasses[size],
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { cn } from '@/lib/utils';
|
||||
import { ButtonHTMLAttributes } from 'react';
|
||||
|
||||
type ButtonVariant = 'primary' | 'ghost' | 'danger-outline' | 'danger-solid';
|
||||
type ButtonSize = 'sm' | 'md';
|
||||
|
||||
interface GhButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: ButtonVariant;
|
||||
size?: ButtonSize;
|
||||
}
|
||||
|
||||
const variantClasses: Record<ButtonVariant, string> = {
|
||||
primary: 'bg-gh-btn-green border border-gh-btn-green-hover text-white hover:bg-gh-btn-green-hover',
|
||||
ghost: 'bg-transparent border border-gh-border text-gh-secondary hover:bg-gh-overlay hover:text-gh-primary',
|
||||
'danger-outline': 'bg-transparent border border-gh-border text-gh-red hover:border-gh-red/40 hover:bg-gh-red-bg',
|
||||
'danger-solid': 'bg-gh-overlay border border-gh-red/20 text-gh-red hover:bg-gh-red-bg',
|
||||
};
|
||||
|
||||
const sizeClasses: Record<ButtonSize, string> = {
|
||||
sm: 'px-3 py-1.5 text-xs',
|
||||
md: 'px-4 py-2 text-sm',
|
||||
};
|
||||
|
||||
export function GhButton({
|
||||
variant = 'ghost',
|
||||
size = 'md',
|
||||
className,
|
||||
children,
|
||||
disabled,
|
||||
...props
|
||||
}: GhButtonProps) {
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
disabled={disabled}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1.5 justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-gh-blue focus:ring-offset-1 focus:ring-offset-gh-base',
|
||||
'disabled:cursor-not-allowed disabled:opacity-40',
|
||||
variantClasses[variant],
|
||||
sizeClasses[size],
|
||||
className
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -37,13 +37,13 @@ export function Modal({ isOpen, onClose, title, children, className }: ModalProp
|
||||
<div className="absolute inset-0" onClick={onClose} />
|
||||
<div
|
||||
className={cn(
|
||||
'relative w-full max-w-md rounded-lg border border-gh-border bg-gh-canvas p-6 shadow-xl',
|
||||
'relative w-full max-w-md rounded-lg border border-border bg-canvas p-6 shadow-xl',
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold text-gh-primary">{title}</h3>
|
||||
<button onClick={onClose} className="text-gh-muted hover:text-gh-primary">
|
||||
<h3 className="text-lg font-semibold text-primary">{title}</h3>
|
||||
<button onClick={onClose} className="text-muted hover:text-primary">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@ interface SidebarProps {
|
||||
|
||||
function ServerIcon({ active }: { active: boolean }) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className={cn('h-5 w-5', active ? 'text-gh-blue' : 'text-gh-subtle')}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className={cn('h-5 w-5', active ? 'text-blue' : 'text-subtle')}>
|
||||
<rect x="2" y="3" width="20" height="5" rx="1" />
|
||||
<rect x="2" y="10" width="20" height="5" rx="1" />
|
||||
<rect x="2" y="17" width="20" height="5" rx="1" />
|
||||
@@ -23,7 +23,7 @@ function ServerIcon({ active }: { active: boolean }) {
|
||||
|
||||
function UsersIcon({ active }: { active: boolean }) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className={cn('h-5 w-5', active ? 'text-gh-blue' : 'text-gh-subtle')}>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className={cn('h-5 w-5', active ? 'text-blue' : 'text-subtle')}>
|
||||
<path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" />
|
||||
<circle cx="9" cy="7" r="4" />
|
||||
<path d="M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75" />
|
||||
@@ -43,16 +43,13 @@ export function Sidebar({ showUsers }: SidebarProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Desktop icon sidebar */}
|
||||
<aside className="fixed inset-y-0 left-0 z-40 hidden w-14 flex-col items-center border-r border-gh-border-muted bg-gh-sidebar py-3 md:flex">
|
||||
{/* Logo */}
|
||||
<div className="mb-4 flex h-8 w-8 items-center justify-center rounded-lg bg-gh-blue">
|
||||
<aside className="fixed inset-y-0 left-0 z-40 hidden w-14 flex-col items-center border-r border-border-muted bg-sidebar py-3 md:flex">
|
||||
<div className="mb-4 flex h-8 w-8 items-center justify-center rounded-lg bg-blue">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="#0d1117" strokeWidth={2.5} className="h-4 w-4">
|
||||
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
{/* Nav icons */}
|
||||
<nav className="flex flex-1 flex-col items-center gap-1">
|
||||
{navItems.map((item) => (
|
||||
<Link
|
||||
@@ -61,7 +58,7 @@ export function Sidebar({ showUsers }: SidebarProps) {
|
||||
title={item.label}
|
||||
className={cn(
|
||||
'flex h-9 w-9 items-center justify-center rounded-lg transition-colors',
|
||||
item.active ? 'bg-gh-blue-bg' : 'hover:bg-gh-overlay'
|
||||
item.active ? 'bg-blue-bg' : 'hover:bg-overlay'
|
||||
)}
|
||||
>
|
||||
{item.icon}
|
||||
@@ -69,19 +66,17 @@ export function Sidebar({ showUsers }: SidebarProps) {
|
||||
))}
|
||||
</nav>
|
||||
|
||||
{/* Avatar placeholder */}
|
||||
<div className="mt-auto h-7 w-7 rounded-full border-2 border-gh-border bg-gh-overlay" />
|
||||
<div className="mt-auto h-7 w-7 rounded-full border-2 border-border bg-overlay" />
|
||||
</aside>
|
||||
|
||||
{/* Mobile bottom tab bar */}
|
||||
<nav className="fixed inset-x-0 bottom-0 z-40 flex h-14 items-center justify-around border-t border-gh-border-muted bg-gh-sidebar md:hidden">
|
||||
<nav className="fixed inset-x-0 bottom-0 z-40 flex h-14 items-center justify-around border-t border-border-muted bg-sidebar md:hidden">
|
||||
{navItems.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className={cn(
|
||||
'flex flex-col items-center justify-center gap-0.5 px-4 py-2 text-xs transition-colors',
|
||||
item.active ? 'text-gh-blue' : 'text-gh-subtle'
|
||||
item.active ? 'text-blue' : 'text-subtle'
|
||||
)}
|
||||
>
|
||||
{item.icon}
|
||||
|
||||
@@ -8,13 +8,13 @@ interface StatusDotProps {
|
||||
|
||||
export function StatusDot({ status, className }: StatusDotProps) {
|
||||
const dotClass = {
|
||||
[ServiceStatus.Running]: 'bg-gh-green shadow-[0_0_0_3px_#3fb95022]',
|
||||
[ServiceStatus.Starting]: 'bg-gh-yellow animate-pulse',
|
||||
[ServiceStatus.Stopping]: 'bg-gh-yellow animate-pulse',
|
||||
[ServiceStatus.Restarting]: 'bg-gh-yellow animate-pulse',
|
||||
[ServiceStatus.Stopped]: 'bg-gh-subtle',
|
||||
[ServiceStatus.Unknown]: 'bg-gh-subtle',
|
||||
}[status] ?? 'bg-gh-subtle';
|
||||
[ServiceStatus.Running]: 'bg-green shadow-[0_0_0_3px_#3fb95022]',
|
||||
[ServiceStatus.Starting]: 'bg-yellow animate-pulse',
|
||||
[ServiceStatus.Stopping]: 'bg-yellow animate-pulse',
|
||||
[ServiceStatus.Restarting]: 'bg-yellow animate-pulse',
|
||||
[ServiceStatus.Stopped]: 'bg-subtle',
|
||||
[ServiceStatus.Unknown]: 'bg-subtle',
|
||||
}[status] ?? 'bg-subtle';
|
||||
|
||||
return (
|
||||
<span
|
||||
|
||||
@@ -12,11 +12,11 @@ export function SteamCMDNotification() {
|
||||
const serverCount = runningSteamServers.size;
|
||||
|
||||
return (
|
||||
<div className="border-l-4 border-gh-yellow bg-gh-yellow-bg px-4 py-3">
|
||||
<div className="border-l-4 border-yellow bg-yellow-bg px-4 py-3">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<svg
|
||||
className="h-5 w-5 text-gh-yellow"
|
||||
className="h-5 w-5 text-yellow"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
@@ -28,7 +28,7 @@ export function SteamCMDNotification() {
|
||||
</svg>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<p className="text-sm text-gh-yellow">
|
||||
<p className="text-sm text-yellow">
|
||||
<strong>SteamCMD is currently running</strong> for {serverCount} server{serverCount !== 1 ? 's' : ''}.
|
||||
Server actions are temporarily disabled to prevent conflicts.
|
||||
This will automatically resolve when the download completes.
|
||||
@@ -36,8 +36,8 @@ export function SteamCMDNotification() {
|
||||
</div>
|
||||
<div className="ml-auto flex-shrink-0">
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin h-4 w-4 border-2 border-gh-yellow border-t-transparent rounded-full mr-2"></div>
|
||||
<span className="text-xs text-gh-yellow">Downloading...</span>
|
||||
<div className="animate-spin h-4 w-4 border-2 border-yellow border-t-transparent rounded-full mr-2"></div>
|
||||
<span className="text-xs text-yellow">Downloading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user