diff --git a/packages/frontend/src/components/server-configuration.tsx b/packages/frontend/src/components/server-configuration.tsx index 41b62d4..779730b 100644 --- a/packages/frontend/src/components/server-configuration.tsx +++ b/packages/frontend/src/components/server-configuration.tsx @@ -114,7 +114,7 @@ export function ServerConfiguration({ trigger }: { trigger?: ReactNode }) { {trigger || ( - + )} diff --git a/packages/frontend/src/components/ui/icon.tsx b/packages/frontend/src/components/ui/icon.tsx index a57b270..c44d843 100644 --- a/packages/frontend/src/components/ui/icon.tsx +++ b/packages/frontend/src/components/ui/icon.tsx @@ -2,6 +2,7 @@ import { Alert as PixelAlert, Check as PixelCheck, Checkbox as PixelCheckbox, + CheckboxOn as PixelCheckboxOn, ChevronDown as PixelChevronDown, ChevronLeft as PixelChevronLeft, ChevronRight as PixelChevronRight, @@ -10,7 +11,10 @@ import { Clock as PixelClock, Close as PixelClose, MessagePlus as PixelCommentSend, + CreditCard as PixelCreditCard, + Dashboard as PixelDashboard, Debug as PixelDebug, + DebugOff as PixelDebugOff, Edit as PixelEdit, Home as PixelHome, InfoBox as PixelInfo, @@ -24,14 +28,18 @@ import { Play as PixelPlay, Plus as PixelPlus, Server as PixelServer, + Shield as PixelShield, + Ship as PixelShip, CheckboxOn as PixelStop, Sun as PixelSun, Trash as PixelTrash, Undo as PixelUndo, User as PixelUser, ViewportWide as PixelViewportWide, + Zap as PixelZap, } from "@nsmr/pixelart-react"; import { + ArrowCounterClockwiseIcon as PhosphorArrowCounterClockwise, BugIcon as PhosphorBug, CheckIcon as PhosphorCheck, CheckCircleIcon as PhosphorCheckCircle, @@ -41,8 +49,9 @@ import { CaretRightIcon as PhosphorChevronRight, CaretUpIcon as PhosphorChevronUp, CircleIcon as PhosphorCircle, - ClockIcon as PhosphorClock, ChatTextIcon as PhosphorComment, + CreditCardIcon as PhosphorCreditCard, + CubeIcon as PhosphorCube, DotsSixVerticalIcon as PhosphorDotsSixVertical, DotsThreeVerticalIcon as PhosphorDotsThreeVertical, PencilSimpleIcon as PhosphorEdit, @@ -50,6 +59,8 @@ import { HashStraightIcon as PhosphorHashStraight, HouseIcon as PhosphorHome, InfoIcon as PhosphorInfo, + LayoutIcon as PhosphorLayout, + LightningIcon as PhosphorLightning, LinkIcon as PhosphorLink, SpinnerGapIcon as PhosphorLoader, SignOutIcon as PhosphorLogOut, @@ -59,11 +70,13 @@ import { PlayIcon as PhosphorPlay, PlusIcon as PhosphorPlus, QuestionIcon as PhosphorQuestion, + RocketLaunchIcon as PhosphorRocketLaunch, HardDrivesIcon as PhosphorServer, + ShieldCheckIcon as PhosphorShieldCheck, StopIcon as PhosphorStop, SunIcon as PhosphorSun, + TimerIcon as PhosphorTimer, TrashIcon as PhosphorTrash, - ArrowCounterClockwiseIcon as PhosphorUndo, UserIcon as PhosphorUser, WarningIcon as PhosphorWarning, XIcon as PhosphorX, @@ -71,7 +84,9 @@ import { import type { IconStyle } from "@sprint/shared"; import { AlertTriangle, + Box, Bug, + BugOff, Check, CheckIcon, ChevronDown, @@ -79,15 +94,16 @@ import { ChevronLeftIcon, ChevronRightIcon, ChevronUp, - ChevronUpIcon, CircleCheckIcon, CircleIcon, CircleQuestionMark, + CreditCard, Edit, EllipsisVertical, GripVerticalIcon, Hash, InfoIcon, + LayoutDashboard, Link, Loader, Loader2Icon, @@ -99,17 +115,22 @@ import { Pause, Play, Plus, + Rocket, + RotateCcw, ServerIcon, + ShieldCheck, Square, SquareCheck, Sun, Timer, + TimerOff, Trash, TriangleAlertIcon, Undo, Undo2, UserRound, X, + Zap, } from "lucide-react"; import { useSessionSafe } from "@/components/session-provider"; @@ -118,7 +139,9 @@ import { useSessionSafe } from "@/components/session-provider"; // phosphor: https://phosphoricons.com/ const icons = { alertTriangle: { lucide: AlertTriangle, pixel: PixelAlert, phosphor: PhosphorWarning }, + box: { lucide: Box, pixel: PixelCheckboxOn, phosphor: PhosphorCube }, bug: { lucide: Bug, pixel: PixelDebug, phosphor: PhosphorBug }, + bugOff: { lucide: BugOff, pixel: PixelDebugOff, phosphor: PhosphorBug }, check: { lucide: Check, pixel: PixelCheck, phosphor: PhosphorCheck }, checkIcon: { lucide: CheckIcon, pixel: PixelCheck, phosphor: PhosphorCheck }, checkBox: { lucide: SquareCheck, pixel: PixelCheckbox, phosphor: PhosphorCheckSquare }, @@ -127,11 +150,11 @@ const icons = { chevronLeftIcon: { lucide: ChevronLeftIcon, pixel: PixelChevronLeft, phosphor: PhosphorChevronLeft }, chevronRightIcon: { lucide: ChevronRightIcon, pixel: PixelChevronRight, phosphor: PhosphorChevronRight }, chevronUp: { lucide: ChevronUp, pixel: PixelChevronUp, phosphor: PhosphorChevronUp }, - chevronUpIcon: { lucide: ChevronUpIcon, pixel: PixelChevronUp, phosphor: PhosphorChevronUp }, - circleCheckIcon: { lucide: CircleCheckIcon, pixel: PixelCheck, phosphor: PhosphorCheckCircle }, + circleCheck: { lucide: CircleCheckIcon, pixel: PixelCheck, phosphor: PhosphorCheckCircle }, circleIcon: { lucide: CircleIcon, pixel: PixelCircle, phosphor: PhosphorCircle }, circleQuestionMark: { lucide: CircleQuestionMark, pixel: PixelNoteDelete, phosphor: PhosphorQuestion }, comment: { lucide: MessageSquarePlus, pixel: PixelCommentSend, phosphor: PhosphorComment }, + creditCard: { lucide: CreditCard, pixel: PixelCreditCard, phosphor: PhosphorCreditCard }, edit: { lucide: Edit, pixel: PixelEdit, phosphor: PhosphorEdit }, ellipsisVertical: { lucide: EllipsisVertical, @@ -145,26 +168,32 @@ const icons = { }, hash: { lucide: Hash, pixel: PhosphorHashStraight, phosphor: PhosphorHash }, home: { lucide: LucideHome, pixel: PixelHome, phosphor: PhosphorHome }, - infoIcon: { lucide: InfoIcon, pixel: PixelInfo, phosphor: PhosphorInfo }, + info: { lucide: InfoIcon, pixel: PixelInfo, phosphor: PhosphorInfo }, + layoutDashboard: { lucide: LayoutDashboard, pixel: PixelDashboard, phosphor: PhosphorLayout }, link: { lucide: Link, pixel: PixelLink, phosphor: PhosphorLink }, loader: { lucide: Loader, pixel: PixelLoader, phosphor: PhosphorLoader }, - loader2Icon: { lucide: Loader2Icon, pixel: PixelLoader, phosphor: PhosphorLoader }, + loader2: { lucide: Loader2Icon, pixel: PixelLoader, phosphor: PhosphorLoader }, logOut: { lucide: LogOut, pixel: PixelLogout, phosphor: PhosphorLogOut }, moon: { lucide: Moon, pixel: PixelMoon, phosphor: PhosphorMoon }, - octagonXIcon: { lucide: OctagonXIcon, pixel: PixelClose, phosphor: PhosphorOctagon }, + octagonX: { lucide: OctagonXIcon, pixel: PixelClose, phosphor: PhosphorOctagon }, pause: { lucide: Pause, pixel: PixelPause, phosphor: PhosphorPause }, play: { lucide: Play, pixel: PixelPlay, phosphor: PhosphorPlay }, plus: { lucide: Plus, pixel: PixelPlus, phosphor: PhosphorPlus }, - serverIcon: { lucide: ServerIcon, pixel: PixelServer, phosphor: PhosphorServer }, + rocket: { lucide: Rocket, pixel: PixelShip, phosphor: PhosphorRocketLaunch }, + rotateCcw: { lucide: RotateCcw, pixel: PixelUndo, phosphor: PhosphorArrowCounterClockwise }, + server: { lucide: ServerIcon, pixel: PixelServer, phosphor: PhosphorServer }, + shieldCheck: { lucide: ShieldCheck, pixel: PixelShield, phosphor: PhosphorShieldCheck }, sun: { lucide: Sun, pixel: PixelSun, phosphor: PhosphorSun }, stop: { lucide: Square, pixel: PixelStop, phosphor: PhosphorStop }, - timer: { lucide: Timer, pixel: PixelClock, phosphor: PhosphorClock }, + timer: { lucide: Timer, pixel: PixelClock, phosphor: PhosphorTimer }, + timerOff: { lucide: TimerOff, pixel: PixelClock, phosphor: PhosphorTimer }, trash: { lucide: Trash, pixel: PixelTrash, phosphor: PhosphorTrash }, - triangleAlertIcon: { lucide: TriangleAlertIcon, pixel: PixelAlert, phosphor: PhosphorWarning }, - undo: { lucide: Undo, pixel: PixelUndo, phosphor: PhosphorUndo }, - undo2: { lucide: Undo2, pixel: PixelUndo, phosphor: PhosphorUndo }, + triangleAlert: { lucide: TriangleAlertIcon, pixel: PixelAlert, phosphor: PhosphorWarning }, + undo: { lucide: Undo, pixel: PixelUndo, phosphor: PhosphorArrowCounterClockwise }, + undo2: { lucide: Undo2, pixel: PixelUndo, phosphor: PhosphorArrowCounterClockwise }, userRound: { lucide: UserRound, pixel: PixelUser, phosphor: PhosphorUser }, x: { lucide: X, pixel: PixelClose, phosphor: PhosphorX }, + zap: { lucide: Zap, pixel: PixelZap, phosphor: PhosphorLightning }, }; export type IconName = keyof typeof icons; @@ -202,7 +231,7 @@ export default function Icon({ // lucide fills sillily if (color && resolvedStyle !== "lucide") { fill = color; - } else if (resolvedStyle === "pixel" && ["bug", "moon", "hash"].includes(icon)) { + } else if (resolvedStyle === "pixel" && ["bug", "moon", "hash", "bugOff"].includes(icon)) { fill = "var(--foreground)"; } else if (resolvedStyle === "phosphor") { fill = "var(--foreground)"; diff --git a/packages/frontend/src/components/ui/select.tsx b/packages/frontend/src/components/ui/select.tsx index 2b0ea18..c9c4d1e 100644 --- a/packages/frontend/src/components/ui/select.tsx +++ b/packages/frontend/src/components/ui/select.tsx @@ -198,7 +198,7 @@ function SelectScrollUpButton({ className={cn("flex cursor-default items-center justify-center py-1", className)} {...props} > - + ); } diff --git a/packages/frontend/src/components/ui/sonner.tsx b/packages/frontend/src/components/ui/sonner.tsx index 48d6dec..9aa9c83 100644 --- a/packages/frontend/src/components/ui/sonner.tsx +++ b/packages/frontend/src/components/ui/sonner.tsx @@ -10,11 +10,11 @@ const Toaster = ({ ...props }: ToasterProps) => { theme={theme as ToasterProps["theme"]} className="toaster group" icons={{ - success: , - info: , - warning: , - error: , - loading: , + success: , + info: , + warning: , + error: , + loading: , }} style={ { diff --git a/packages/frontend/src/pages/Landing.tsx b/packages/frontend/src/pages/Landing.tsx index f348669..bacb8c5 100644 --- a/packages/frontend/src/pages/Landing.tsx +++ b/packages/frontend/src/pages/Landing.tsx @@ -1,8 +1,9 @@ -import { Icon } from "@iconify/react"; +import { HumanRun } from "@nsmr/pixelart-react"; import { Link } from "react-router-dom"; import { useSession } from "@/components/session-provider"; import ThemeToggle from "@/components/theme-toggle"; import { Button } from "@/components/ui/button"; +import Icon from "@/components/ui/icon"; export default function Landing() { const { user, isLoading } = useSession(); @@ -29,16 +30,19 @@ export default function Landing() {
-
+
{/* hero section */}
+
+ +

- ship faster without the chaos + Ship faster without the chaos

-

- sprint is project management that stays out of your way. track issues, manage sprints, and - keep your team moving—without the jira headache. +

+ Sprint is project management that stays out of your way. Track issues, manage sprints, and + keep your team moving—without the Jira headache.

@@ -50,42 +54,40 @@ export default function Landing() { ) : ( <> )}
-

- no credit card required · full access for 14 days -

+

No credit card required · Full access for 14 days

{/* problem section */} -
+

- tired of spending more time managing jira than building product? + Tired of spending more time managing Jira than building your product?

- -

- wasting hours configuring workflows instead of shipping features + +

+ Wasting hours configuring workflows instead of shipping features

- -

- drowning in features you'll never use while missing the basics + +

+ Drowning in features you'll never use while missing the basics

- -

- context switching kills momentum—your flow state doesn't stand a chance + +

+ Context switching kills momentum—your flow state doesn't stand a chance

@@ -94,42 +96,43 @@ export default function Landing() { {/* solution section */}

- everything you need, nothing you don't + Everything you need, nothing you don't

- -

see your work at a glance

-

- beautiful, intuitive issue tracking with customizable statuses. organize by projects and - sprints. find what you need in seconds, not minutes. + +

See your work at a glance

+

+ Beautiful, intuitive issue tracking with customizable statuses. Organize by projects and + sprints. Find what you need in seconds, not minutes.

- -

track time without thinking

-

- built-in time tracking that actually works. start, pause, resume. see where your time goes + +

Track time without thinking

+

+ Built-in time tracking that actually works. Start, pause, resume. See where your time goes without juggling another tool.

- -

ship in sprints

-

- sprint planning that actually works. set date ranges, assign issues, track velocity. keep + +

Ship in sprints

+

+ Sprint planning that actually works. Set date ranges, assign issues, track velocity. Keep your team aligned without the ceremony.

- -

stay in flow

-

- minimal clicks, maximum productivity. keyboard shortcuts, resizable panes, and a clean - interface that gets out of your way. + +

Only use what you need

+

+ Every feature is optional. Sprints, time tracking, and other modules can be enabled or + disabled individually at the organization level. Keep your interface as minimal as your + workflow.

@@ -138,24 +141,24 @@ export default function Landing() { {/* features list */}

- built for developers, by a developer + Built for developers, by a developer

{[ - "organization and project management", - "customizable issue statuses", - "sprint planning with date ranges", - "built-in time tracking", - "role-based access control", - "native desktop app (tauri)", - "self-hostable on your infrastructure", - "clean, resizable interface", - "issue assignment and collaboration", - "jwt authentication", + "Organization and project management", + "Customizable issue statuses", + "Sprint planning with date ranges", + "Built-in time tracking", + "Role-based access control", + "Native desktop app (Tauri)", + "Self-hostable on your infrastructure", + "Clean, resizable interface", + "Issue assignment and collaboration", + "Individual feature toggles (org level)", ].map((feature) => (
- - {feature} + + {feature}
))}
@@ -163,34 +166,34 @@ export default function Landing() { {/* social proof placeholder */}
-

join developers who've escaped jira

+

Join developers who've escaped Jira

-

- "finally, a project management tool that doesn't slow me down" +

+ "Finally, a project management tool that doesn't slow me down"

-

early user feedback

+

Early user feedback

-

- "built by someone who actually understands developer workflows" +

+ "Built by someone who actually understands developer workflows"

-

early user feedback

+

Early user feedback

-

- "the simplicity is refreshing. no bloat, just what we need" +

+ "The simplicity is refreshing. No bloat, just what we need"

-

early user feedback

+

Early user feedback

{/* final cta */}
-

ready to ship faster?

-

- start tracking issues, managing sprints, and shipping product in minutes +

Ready to ship faster?

+

+ Start tracking issues, managing sprints, and shipping product in minutes

{!isLoading && user ? ( @@ -199,25 +202,25 @@ export default function Landing() { ) : ( )}
-

- no credit card required · 14-day free trial · cancel anytime +

+ No credit card required · 14-day free trial · Cancel anytime