lots more icons to do but

This commit is contained in:
Maze Winther
2026-01-24 15:53:46 +01:00
parent 33f453efc7
commit 954160d03b
39 changed files with 519 additions and 710 deletions
+1 -35
View File
@@ -1,12 +1,9 @@
import { OcGithubIcon } from "@opencut/ui/icons";
import { ExternalLink } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { GitHubContributeSection } from "@/components/gitHub-contribute-section";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { EXTERNAL_TOOLS, SOCIAL_LINKS } from "@/constants/site-constants";
import { EXTERNAL_TOOLS } from "@/constants/site-constants";
import { BasePage } from "../base-page";
export const metadata: Metadata = {
@@ -87,7 +84,6 @@ export default async function ContributorsPage() {
{otherContributors.length > 0 && (
<AllContributorsSection contributors={otherContributors} />
)}
{contributors.length === 0 && <EmptyState />}
<ExternalToolsSection />
<GitHubContributeSection
title="Join the community"
@@ -210,36 +206,6 @@ function AllContributorsSection({
);
}
function EmptyState() {
return (
<div className="flex flex-col gap-8 py-20 text-center">
<div className="flex flex-col gap-6">
<div className="bg-muted/50 mx-auto flex size-20 items-center justify-center rounded-full">
<OcGithubIcon className="text-muted-foreground size-8" />
</div>
<div className="flex flex-col gap-3">
<h3 className="text-xl font-medium">No contributors found</h3>
<p className="text-muted-foreground mx-auto max-w-md">
Unable to load contributors at the moment. Check back later or view
on GitHub.
</p>
</div>
</div>
<Link
href={`${SOCIAL_LINKS.github}/graphs/contributors`}
target="_blank"
rel="noopener noreferrer"
>
<Button variant="outline" className="gap-2">
<OcGithubIcon />
View on GitHub
<ExternalLink />
</Button>
</Link>
</div>
);
}
function ExternalToolsSection() {
return (
<div className="flex flex-col gap-10">
+38 -26
View File
@@ -1,16 +1,5 @@
"use client";
import {
ArrowDown01,
Calendar,
ChevronLeft,
MoreHorizontal,
Plus,
Search,
Trash2,
Video,
X,
} from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/navigation";
@@ -41,6 +30,18 @@ import {
import { useEditor } from "@/hooks/use-editor";
import type { TProjectMetadata } from "@/types/project";
import { formatDate } from "@/utils/date";
import { HugeiconsIcon } from "@hugeicons/react";
import {
ArrowHorizontalIcon,
ArrowLeft01Icon,
Calendar04Icon,
Delete02Icon,
MultiplicationSignIcon,
PlusSignIcon,
Search01Icon,
SortingNineOneIcon,
Video01Icon,
} from "@hugeicons/core-free-icons";
export default function ProjectsPage() {
const [isSelectionMode, setIsSelectionMode] = useState(false);
@@ -160,7 +161,7 @@ export default function ProjectsPage() {
href="/"
className="hover:text-muted-foreground flex items-center gap-1 transition-colors"
>
<ChevronLeft className="size-5! shrink-0" />
<HugeiconsIcon icon={ArrowLeft01Icon} className="size-5! shrink-0" />
<span className="text-sm font-medium">Back</span>
</Link>
<div className="block md:hidden">
@@ -171,7 +172,7 @@ export default function ProjectsPage() {
size="sm"
onClick={handleCancelSelection}
>
<X />
<HugeiconsIcon icon={MultiplicationSignIcon} />
Cancel
</Button>
{selectedProjects.size > 0 && (
@@ -180,7 +181,7 @@ export default function ProjectsPage() {
size="sm"
onClick={() => setIsBulkDeleteDialogOpen(true)}
>
<Trash2 />
<HugeiconsIcon icon={Delete02Icon} />
Delete ({selectedProjects.size})
</Button>
)}
@@ -210,7 +211,7 @@ export default function ProjectsPage() {
{isSelectionMode ? (
<div className="flex items-center gap-2">
<Button variant="outline" onClick={handleCancelSelection}>
<X />
<HugeiconsIcon icon={MultiplicationSignIcon} />
Cancel
</Button>
<Button
@@ -218,7 +219,7 @@ export default function ProjectsPage() {
disabled={selectedProjects.size === 0}
onClick={() => setIsBulkDeleteDialogOpen(true)}
>
<Trash2 />
<HugeiconsIcon icon={Delete02Icon} />
Delete {selectedProjects.size} projects
</Button>
</div>
@@ -257,9 +258,8 @@ export default function ProjectsPage() {
variant="outline"
className="size-9 items-center justify-center"
>
<ArrowDown01
strokeWidth={1.5}
className="!size-[1.05rem]"
<HugeiconsIcon
icon={SortingNineOneIcon}
aria-hidden="true"
/>
</Button>
@@ -430,7 +430,10 @@ function ProjectCard({
/>
) : (
<div className="bg-muted/50 flex size-full items-center justify-center">
<Video className="text-muted-foreground size-12 shrink-0" />
<HugeiconsIcon
icon={Video01Icon}
className="text-muted-foreground size-12 shrink-0"
/>
</div>
)}
</div>
@@ -458,7 +461,10 @@ function ProjectCard({
}`}
onClick={(event) => event.preventDefault()}
>
<MoreHorizontal aria-hidden="true" />
<HugeiconsIcon
icon={ArrowHorizontalIcon}
aria-hidden="true"
/>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
@@ -506,7 +512,7 @@ function ProjectCard({
<div className="space-y-1">
<div className="text-muted-foreground flex items-center gap-1.5 text-sm">
<Calendar className="size-4!" />
<HugeiconsIcon icon={Calendar04Icon} className="size-4" />
<span>Created {formatDate({ date: project.createdAt })}</span>
</div>
</div>
@@ -575,7 +581,7 @@ function ProjectsLoader() {
function CreateButton({ onClick }: { onClick?: () => void }) {
return (
<Button className="flex" onClick={onClick}>
<Plus />
<HugeiconsIcon icon={PlusSignIcon} />
<span className="text-sm font-medium">New project</span>
</Button>
);
@@ -596,7 +602,10 @@ function EmptyState({
<div className="flex flex-col items-center justify-center gap-6 py-16 text-center">
<div className="flex flex-col items-center gap-2">
<div className="bg-muted/30 flex size-16 items-center justify-center rounded-full">
<Search className="text-muted-foreground size-8" />
<HugeiconsIcon
icon={Search01Icon}
className="text-muted-foreground size-8"
/>
</div>
<h3 className="text-lg font-medium">No results found</h3>
<p className="text-muted-foreground max-w-md">
@@ -614,7 +623,10 @@ function EmptyState({
<div className="flex flex-col items-center justify-center gap-6 py-16 text-center">
<div className="flex flex-col items-center gap-2">
<div className="bg-muted/30 flex size-16 items-center justify-center rounded-full">
<Video className="text-muted-foreground size-8" />
<HugeiconsIcon
icon={Video01Icon}
className="text-muted-foreground size-8"
/>
</div>
<h3 className="text-lg font-medium">No projects yet</h3>
<p className="text-muted-foreground max-w-md">
@@ -623,7 +635,7 @@ function EmptyState({
</p>
</div>
<Button size="lg" className="gap-2" onClick={onCreateProject}>
<Plus />
<HugeiconsIcon icon={PlusSignIcon} />
Create your first project
</Button>
</div>
+56 -46
View File
@@ -1,17 +1,18 @@
"use client";
import {
ArrowDown,
Clock3,
Folder,
LayoutGrid,
List,
MoreHorizontal,
Plus,
Search,
} from "lucide-react";
import Image from "next/image";
import { useEffect, useMemo, useRef, useState } from "react";
import { HugeiconsIcon } from "@hugeicons/react";
import {
ArrowHorizontalIcon,
Clock03Icon,
Folder03Icon,
GridViewIcon,
LeftToRightListDashIcon,
PlusSignIcon,
SearchIcon,
SortingNineOneIcon,
} from "@hugeicons/core-free-icons";
const projects = [
{
@@ -110,7 +111,7 @@ export default function ProjectsPage() {
href="/projects"
className="flex items-center gap-3 rounded-2xl bg-blue-50/50 px-4 py-3 text-sm font-medium text-[#00A3FF]"
>
<LayoutGrid className="size-5" />
<HugeiconsIcon icon={GridViewIcon} className="size-5" />
Projects
</a>
<div className="px-4 pt-6 pb-2">
@@ -122,14 +123,20 @@ export default function ProjectsPage() {
href="/projects"
className="flex items-center gap-3 rounded-2xl px-4 py-3 text-sm font-medium text-slate-500 hover:bg-slate-50 hover:text-slate-900"
>
<Folder className="size-5 text-slate-400" />
<HugeiconsIcon
icon={Folder03Icon}
className="size-5 text-slate-400"
/>
Marketing
</a>
<a
href="/projects"
className="flex items-center gap-3 rounded-2xl px-4 py-3 text-sm font-medium text-slate-500 hover:bg-slate-50 hover:text-slate-900"
>
<Folder className="size-5 text-slate-400" />
<HugeiconsIcon
icon={Folder03Icon}
className="size-5 text-slate-400"
/>
Social media
</a>
</nav>
@@ -143,7 +150,10 @@ export default function ProjectsPage() {
<div className="flex items-center gap-4">
<div className="group relative">
<Search className="absolute top-1/2 left-3.5 size-4 -translate-y-1/2 text-slate-400" />
<HugeiconsIcon
icon={SearchIcon}
className="absolute top-1/2 left-3.5 size-4 -translate-y-1/2 text-slate-400"
/>
<input
type="text"
placeholder="Search..."
@@ -157,18 +167,22 @@ export default function ProjectsPage() {
className="rounded-full bg-slate-100 p-2 text-slate-900"
aria-label="Grid view"
>
<LayoutGrid className="size-4" aria-hidden="true">
<title>Grid view</title>
</LayoutGrid>
<HugeiconsIcon
icon={GridViewIcon}
className="size-4"
aria-hidden="true"
/>
</button>
<button
type="button"
className="rounded-full p-2 text-slate-400 hover:text-slate-600"
aria-label="List view"
>
<List className="size-4" aria-hidden="true">
<title>List view</title>
</List>
<HugeiconsIcon
icon={LeftToRightListDashIcon}
className="size-4"
aria-hidden="true"
/>
</button>
</div>
@@ -176,7 +190,7 @@ export default function ProjectsPage() {
type="button"
className="flex items-center gap-2 rounded-full bg-[#00A3FF] px-5 py-2.5 text-sm font-semibold text-white hover:bg-[#008BE0] active:scale-95"
>
<Plus className="size-4" />
<HugeiconsIcon icon={PlusSignIcon} className="size-4" />
New project
</button>
</div>
@@ -210,7 +224,7 @@ export default function ProjectsPage() {
className="inline-flex items-center gap-1.5 rounded-lg p-1 text-sm font-medium text-slate-500 hover:text-slate-900"
>
Name
<ArrowDown className="size-3.5" />
<HugeiconsIcon icon={SortingNineOneIcon} className="size-3.5" />
</button>
</div>
@@ -243,9 +257,11 @@ export default function ProjectsPage() {
className="rounded-full bg-white/90 p-2 text-slate-600 backdrop-blur-sm hover:bg-white hover:text-[#00A3FF]"
aria-label="Project menu"
>
<MoreHorizontal className="size-4" aria-hidden="true">
<title>Project menu</title>
</MoreHorizontal>
<HugeiconsIcon
icon={ArrowHorizontalIcon}
className="size-4"
aria-hidden="true"
/>
</button>
</div>
@@ -268,7 +284,11 @@ export default function ProjectsPage() {
{name}
</h3>
<div className="mt-2 flex items-center gap-2 text-slate-400">
<Clock3 className="size-4" aria-hidden="true" />
<HugeiconsIcon
icon={Clock03Icon}
className="size-4"
aria-hidden="true"
/>
<p className="text-xs font-medium">{createdAtLabel}</p>
</div>
</div>
@@ -281,42 +301,33 @@ export default function ProjectsPage() {
</main>
<style jsx global>{`
.project-card:hover .card-actions {
.project-card:hover .card-actions
opacity: 1;
}
.checkbox-wrapper:checked + div {
.checkbox-wrapper:checked + div
border-color: var(--brand-blue);
background-color: #eff6ff;
}
.controls-row.has-selection .controls-select {
.controls-row.has-selection .controls-select
opacity: 1;
}
.project-select-wrapper {
.project-select-wrapper
opacity: 0;
}
.project-card:hover .project-select-wrapper {
.project-card:hover .project-select-wrapper
opacity: 1;
}
.project-card:has(.project-select:checked) .project-select-wrapper {
.project-card:has(.project-select:checked) .project-select-wrapper
opacity: 1;
}
.multi-select .project-menu {
.multi-select .project-menu
opacity: 0 !important;
pointer-events: none;
}
.custom-checkbox {
.custom-checkbox
appearance: none;
background-color: #fff;
border: 2px solid #e2e8f0;
border-radius: 8px;
display: inline-grid;
place-content: center;
}
.custom-checkbox:checked {
.custom-checkbox:checked
background-color: var(--brand-blue);
border-color: var(--brand-blue);
}
.custom-checkbox:checked::after {
.custom-checkbox:checked::after
content: "";
width: 10px;
height: 10px;
@@ -329,7 +340,6 @@ export default function ProjectsPage() {
86% 10%,
40% 70%
);
}
`}</style>
</div>
);
+10 -6
View File
@@ -1,10 +1,11 @@
import { ExternalLink } from "lucide-react";
import type { Metadata } from "next";
import Image from "next/image";
import Link from "next/link";
import { BasePage } from "@/app/base-page";
import { Card, CardContent } from "@/components/ui/card";
import { SPONSORS, type Sponsor } from "@/constants/site-constants";
import { HugeiconsIcon } from "@hugeicons/react";
import { LinkSquare02Icon } from "@hugeicons/core-free-icons";
export const metadata: Metadata = {
title: "Sponsors - OpenCut",
@@ -25,9 +26,9 @@ export default function SponsorsPage() {
<h1 className="text-5xl font-bold tracking-tight md:text-6xl">
Sponsors
</h1>
<p className="text-muted-foreground mx-auto max-w-2xl text-xl leading-relaxed">
Support OpenCut and help us build the future of free and open-source
video editing.
<p className="text-muted-foreground mx-auto max-w-2xl text-xl leading-relaxed text-pretty">
Support OpenCut and help us build the future of privacy-first video
editing.
</p>
</div>
<SponsorsGrid />
@@ -51,7 +52,7 @@ function SponsorCard({ sponsor }: { sponsor: Sponsor }) {
href={sponsor.url}
target="_blank"
rel="noopener noreferrer"
className="size-full"
className="size-full"
>
<Card className="h-full">
<CardContent className="flex h-full flex-col justify-center gap-8 p-8">
@@ -67,7 +68,10 @@ function SponsorCard({ sponsor }: { sponsor: Sponsor }) {
<h3 className="text-xl font-semibold group-hover:underline">
{sponsor.name}
</h3>
<ExternalLink className="text-muted-foreground size-4" />
<HugeiconsIcon
icon={LinkSquare02Icon}
className="text-muted-foreground size-4"
/>
</div>
<p className="text-muted-foreground">{sponsor.description}</p>
</div>