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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 8 additions & 9 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions frontend/src/components/ui/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from "react";
import { cn } from "@/lib/utils";
import type { BadgeProps, BadgeVariant, BadgeSize } from "@/types/ui";

export type { BadgeProps, BadgeVariant, BadgeSize };

const variantColorMap: Record<BadgeVariant, string> = {
open: "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400",
"in-progress":
"bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400",
completed:
"bg-stellar-slate text-stellar-white dark:bg-stellar-navy dark:text-stellar-white",
expired: "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-400",
draft: "bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-400",
active: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400",
passed:
"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400",
rejected: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400",
executed:
"bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-400",
default:
"bg-stellar-lightNavy text-stellar-white dark:bg-stellar-navy dark:text-stellar-white",
};

const sizeClasses: Record<BadgeSize, string> = {
sm: "px-2 py-0.5 text-xs",
md: "px-2.5 py-0.5 text-sm",
lg: "px-3 py-1 text-base",
};

const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
(
{ className, variant = "default", size = "md", children, ...props },
ref,
) => {
const baseClasses =
"inline-flex items-center justify-center font-medium rounded-full transition-colors";

return (
<span
className={cn(
baseClasses,
variantColorMap[variant],
sizeClasses[size],
className,
)}
ref={ref}
{...props}
>
{children}
</span>
);
},
);

Badge.displayName = "Badge";

export { Badge };
1 change: 1 addition & 0 deletions frontend/src/components/ui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { Modal } from "./Modal";
export { Dropzone } from "./Dropzone";
export { EmptyState } from "./EmptyState";
export { SearchInput } from "./SearchInput";
export { Badge } from "./Badge";
export {
DropdownMenu,
DropdownMenuTrigger,
Expand Down
236 changes: 135 additions & 101 deletions frontend/src/types/ui.ts
Original file line number Diff line number Diff line change
@@ -1,156 +1,170 @@
import React from 'react'
import React from "react";

// UI Component Types
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger'
export type ButtonSize = 'sm' | 'md' | 'lg'
export type ButtonVariant =
| "primary"
| "secondary"
| "outline"
| "ghost"
| "danger";
export type ButtonSize = "sm" | "md" | "lg";

export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant
size?: ButtonSize
isLoading?: boolean
leftIcon?: React.ReactNode
rightIcon?: React.ReactNode
variant?: ButtonVariant;
size?: ButtonSize;
isLoading?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
}

export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
label?: string
error?: string
helperText?: string
label?: string;
error?: string;
helperText?: string;
}

export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
title?: string
description?: string
footer?: React.ReactNode
title?: string;
description?: string;
footer?: React.ReactNode;
}

export interface ModalProps {
isOpen: boolean
onClose: () => void
title?: string
children: React.ReactNode
size?: 'sm' | 'md' | 'lg' | 'xl'
isOpen: boolean;
onClose: () => void;
title?: string;
children: React.ReactNode;
size?: "sm" | "md" | "lg" | "xl";
}

// Layout Types
export interface SidebarItem {
id: string
label: string
href: string
icon: React.ReactNode
isActive?: boolean
id: string;
label: string;
href: string;
icon: React.ReactNode;
isActive?: boolean;
}

export interface NavigationItem {
id: string
label: string
href: string
isActive?: boolean
id: string;
label: string;
href: string;
isActive?: boolean;
}

// Mock Data Types
export interface Guild {
id: string
name: string
description: string
tier: 'bronze' | 'silver' | 'gold' | 'platinum'
memberCount: number
reputation: number
createdAt: string
logo?: string
id: string;
name: string;
description: string;
tier: "bronze" | "silver" | "gold" | "platinum";
memberCount: number;
reputation: number;
createdAt: string;
logo?: string;
}

export interface Bounty {
id: string
title: string
description: string
id: string;
title: string;
description: string;
reward: {
amount: number
currency: string
}
deadline: string
status: 'open' | 'in-progress' | 'completed' | 'expired'
guildId: string
createdAt: string
amount: number;
currency: string;
};
deadline: string;
status: "open" | "in-progress" | "completed" | "expired";
guildId: string;
createdAt: string;
}

export interface UserProfile {
id: string
username: string
email: string
avatar?: string
reputation: number
joinedAt: string
guilds: string[]
id: string;
username: string;
email: string;
avatar?: string;
reputation: number;
joinedAt: string;
guilds: string[];
}

// Governance Types
export type ProposalType = 'treasury' | 'rule-change' | 'membership' | 'general'
export type ProposalStatus = 'draft' | 'active' | 'passed' | 'rejected' | 'executed'
export type VoteChoice = 'for' | 'against' | 'abstain'
export type ProposalType =
| "treasury"
| "rule-change"
| "membership"
| "general";
export type ProposalStatus =
| "draft"
| "active"
| "passed"
| "rejected"
| "executed";
export type VoteChoice = "for" | "against" | "abstain";

export interface Vote {
id: string
proposalId: string
voterId: string
voterAddress: string
choice: VoteChoice
votingPower: number
timestamp: string
id: string;
proposalId: string;
voterId: string;
voterAddress: string;
choice: VoteChoice;
votingPower: number;
timestamp: string;
}

export interface VotingStats {
for: number
against: number
abstain: number
total: number
forPower: number
againstPower: number
abstainPower: number
totalPower: number
for: number;
against: number;
abstain: number;
total: number;
forPower: number;
againstPower: number;
abstainPower: number;
totalPower: number;
}

export interface Proposal {
id: string
guildId: string
title: string
description: string
type: ProposalType
status: ProposalStatus
proposerId: string
proposerAddress: string
proposerName: string
createdAt: string
startDate: string
endDate: string
quorum: number
quorumThreshold: number
executionData?: string
votes: Vote[]
votingStats: VotingStats
id: string;
guildId: string;
title: string;
description: string;
type: ProposalType;
status: ProposalStatus;
proposerId: string;
proposerAddress: string;
proposerName: string;
createdAt: string;
startDate: string;
endDate: string;
quorum: number;
quorumThreshold: number;
executionData?: string;
votes: Vote[];
votingStats: VotingStats;
}

// Dropzone Types
export type DropzoneVariant = 'avatar' | 'banner'
export type DropzoneVariant = "avatar" | "banner";

export interface DropzoneProps {
variant?: DropzoneVariant
value?: string | null
onChange?: (url: string | null) => void
onError?: (error: string) => void
disabled?: boolean
className?: string
variant?: DropzoneVariant;
value?: string | null;
onChange?: (url: string | null) => void;
onError?: (error: string) => void;
disabled?: boolean;
className?: string;
}

export interface FileValidationResult {
isValid: boolean
error?: string
isValid: boolean;
error?: string;
}

export interface UploadResult {
success: boolean
url?: string
error?: string
success: boolean;
url?: string;
error?: string;
}

export interface Tab {
Expand All @@ -164,4 +178,24 @@ export interface TabsProps {
tabs: Tab[];
defaultTab?: string;
className?: string;
}
}

// Badge Types
export type BadgeVariant =
| "open"
| "in-progress"
| "completed"
| "expired"
| "draft"
| "active"
| "passed"
| "rejected"
| "executed"
| "default";
export type BadgeSize = "sm" | "md" | "lg";

export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
variant?: BadgeVariant;
size?: BadgeSize;
children: React.ReactNode;
}
Loading