massive landing page improvements

This commit is contained in:
2026-01-27 18:35:50 +00:00
parent 3f1ff128b6
commit 989f4db68d
6 changed files with 130 additions and 98 deletions

View File

@@ -114,7 +114,7 @@ export function ServerConfiguration({ trigger }: { trigger?: ReactNode }) {
<DialogTrigger asChild> <DialogTrigger asChild>
{trigger || ( {trigger || (
<IconButton size="lg" className="absolute top-2 right-2" title={"Server Configuration"}> <IconButton size="lg" className="absolute top-2 right-2" title={"Server Configuration"}>
<Icon icon="serverIcon" className="size-4" /> <Icon icon="server" className="size-4" />
</IconButton> </IconButton>
)} )}
</DialogTrigger> </DialogTrigger>

View File

@@ -2,6 +2,7 @@ import {
Alert as PixelAlert, Alert as PixelAlert,
Check as PixelCheck, Check as PixelCheck,
Checkbox as PixelCheckbox, Checkbox as PixelCheckbox,
CheckboxOn as PixelCheckboxOn,
ChevronDown as PixelChevronDown, ChevronDown as PixelChevronDown,
ChevronLeft as PixelChevronLeft, ChevronLeft as PixelChevronLeft,
ChevronRight as PixelChevronRight, ChevronRight as PixelChevronRight,
@@ -10,7 +11,10 @@ import {
Clock as PixelClock, Clock as PixelClock,
Close as PixelClose, Close as PixelClose,
MessagePlus as PixelCommentSend, MessagePlus as PixelCommentSend,
CreditCard as PixelCreditCard,
Dashboard as PixelDashboard,
Debug as PixelDebug, Debug as PixelDebug,
DebugOff as PixelDebugOff,
Edit as PixelEdit, Edit as PixelEdit,
Home as PixelHome, Home as PixelHome,
InfoBox as PixelInfo, InfoBox as PixelInfo,
@@ -24,14 +28,18 @@ import {
Play as PixelPlay, Play as PixelPlay,
Plus as PixelPlus, Plus as PixelPlus,
Server as PixelServer, Server as PixelServer,
Shield as PixelShield,
Ship as PixelShip,
CheckboxOn as PixelStop, CheckboxOn as PixelStop,
Sun as PixelSun, Sun as PixelSun,
Trash as PixelTrash, Trash as PixelTrash,
Undo as PixelUndo, Undo as PixelUndo,
User as PixelUser, User as PixelUser,
ViewportWide as PixelViewportWide, ViewportWide as PixelViewportWide,
Zap as PixelZap,
} from "@nsmr/pixelart-react"; } from "@nsmr/pixelart-react";
import { import {
ArrowCounterClockwiseIcon as PhosphorArrowCounterClockwise,
BugIcon as PhosphorBug, BugIcon as PhosphorBug,
CheckIcon as PhosphorCheck, CheckIcon as PhosphorCheck,
CheckCircleIcon as PhosphorCheckCircle, CheckCircleIcon as PhosphorCheckCircle,
@@ -41,8 +49,9 @@ import {
CaretRightIcon as PhosphorChevronRight, CaretRightIcon as PhosphorChevronRight,
CaretUpIcon as PhosphorChevronUp, CaretUpIcon as PhosphorChevronUp,
CircleIcon as PhosphorCircle, CircleIcon as PhosphorCircle,
ClockIcon as PhosphorClock,
ChatTextIcon as PhosphorComment, ChatTextIcon as PhosphorComment,
CreditCardIcon as PhosphorCreditCard,
CubeIcon as PhosphorCube,
DotsSixVerticalIcon as PhosphorDotsSixVertical, DotsSixVerticalIcon as PhosphorDotsSixVertical,
DotsThreeVerticalIcon as PhosphorDotsThreeVertical, DotsThreeVerticalIcon as PhosphorDotsThreeVertical,
PencilSimpleIcon as PhosphorEdit, PencilSimpleIcon as PhosphorEdit,
@@ -50,6 +59,8 @@ import {
HashStraightIcon as PhosphorHashStraight, HashStraightIcon as PhosphorHashStraight,
HouseIcon as PhosphorHome, HouseIcon as PhosphorHome,
InfoIcon as PhosphorInfo, InfoIcon as PhosphorInfo,
LayoutIcon as PhosphorLayout,
LightningIcon as PhosphorLightning,
LinkIcon as PhosphorLink, LinkIcon as PhosphorLink,
SpinnerGapIcon as PhosphorLoader, SpinnerGapIcon as PhosphorLoader,
SignOutIcon as PhosphorLogOut, SignOutIcon as PhosphorLogOut,
@@ -59,11 +70,13 @@ import {
PlayIcon as PhosphorPlay, PlayIcon as PhosphorPlay,
PlusIcon as PhosphorPlus, PlusIcon as PhosphorPlus,
QuestionIcon as PhosphorQuestion, QuestionIcon as PhosphorQuestion,
RocketLaunchIcon as PhosphorRocketLaunch,
HardDrivesIcon as PhosphorServer, HardDrivesIcon as PhosphorServer,
ShieldCheckIcon as PhosphorShieldCheck,
StopIcon as PhosphorStop, StopIcon as PhosphorStop,
SunIcon as PhosphorSun, SunIcon as PhosphorSun,
TimerIcon as PhosphorTimer,
TrashIcon as PhosphorTrash, TrashIcon as PhosphorTrash,
ArrowCounterClockwiseIcon as PhosphorUndo,
UserIcon as PhosphorUser, UserIcon as PhosphorUser,
WarningIcon as PhosphorWarning, WarningIcon as PhosphorWarning,
XIcon as PhosphorX, XIcon as PhosphorX,
@@ -71,7 +84,9 @@ import {
import type { IconStyle } from "@sprint/shared"; import type { IconStyle } from "@sprint/shared";
import { import {
AlertTriangle, AlertTriangle,
Box,
Bug, Bug,
BugOff,
Check, Check,
CheckIcon, CheckIcon,
ChevronDown, ChevronDown,
@@ -79,15 +94,16 @@ import {
ChevronLeftIcon, ChevronLeftIcon,
ChevronRightIcon, ChevronRightIcon,
ChevronUp, ChevronUp,
ChevronUpIcon,
CircleCheckIcon, CircleCheckIcon,
CircleIcon, CircleIcon,
CircleQuestionMark, CircleQuestionMark,
CreditCard,
Edit, Edit,
EllipsisVertical, EllipsisVertical,
GripVerticalIcon, GripVerticalIcon,
Hash, Hash,
InfoIcon, InfoIcon,
LayoutDashboard,
Link, Link,
Loader, Loader,
Loader2Icon, Loader2Icon,
@@ -99,17 +115,22 @@ import {
Pause, Pause,
Play, Play,
Plus, Plus,
Rocket,
RotateCcw,
ServerIcon, ServerIcon,
ShieldCheck,
Square, Square,
SquareCheck, SquareCheck,
Sun, Sun,
Timer, Timer,
TimerOff,
Trash, Trash,
TriangleAlertIcon, TriangleAlertIcon,
Undo, Undo,
Undo2, Undo2,
UserRound, UserRound,
X, X,
Zap,
} from "lucide-react"; } from "lucide-react";
import { useSessionSafe } from "@/components/session-provider"; import { useSessionSafe } from "@/components/session-provider";
@@ -118,7 +139,9 @@ import { useSessionSafe } from "@/components/session-provider";
// phosphor: https://phosphoricons.com/ // phosphor: https://phosphoricons.com/
const icons = { const icons = {
alertTriangle: { lucide: AlertTriangle, pixel: PixelAlert, phosphor: PhosphorWarning }, alertTriangle: { lucide: AlertTriangle, pixel: PixelAlert, phosphor: PhosphorWarning },
box: { lucide: Box, pixel: PixelCheckboxOn, phosphor: PhosphorCube },
bug: { lucide: Bug, pixel: PixelDebug, phosphor: PhosphorBug }, bug: { lucide: Bug, pixel: PixelDebug, phosphor: PhosphorBug },
bugOff: { lucide: BugOff, pixel: PixelDebugOff, phosphor: PhosphorBug },
check: { lucide: Check, pixel: PixelCheck, phosphor: PhosphorCheck }, check: { lucide: Check, pixel: PixelCheck, phosphor: PhosphorCheck },
checkIcon: { lucide: CheckIcon, pixel: PixelCheck, phosphor: PhosphorCheck }, checkIcon: { lucide: CheckIcon, pixel: PixelCheck, phosphor: PhosphorCheck },
checkBox: { lucide: SquareCheck, pixel: PixelCheckbox, phosphor: PhosphorCheckSquare }, checkBox: { lucide: SquareCheck, pixel: PixelCheckbox, phosphor: PhosphorCheckSquare },
@@ -127,11 +150,11 @@ const icons = {
chevronLeftIcon: { lucide: ChevronLeftIcon, pixel: PixelChevronLeft, phosphor: PhosphorChevronLeft }, chevronLeftIcon: { lucide: ChevronLeftIcon, pixel: PixelChevronLeft, phosphor: PhosphorChevronLeft },
chevronRightIcon: { lucide: ChevronRightIcon, pixel: PixelChevronRight, phosphor: PhosphorChevronRight }, chevronRightIcon: { lucide: ChevronRightIcon, pixel: PixelChevronRight, phosphor: PhosphorChevronRight },
chevronUp: { lucide: ChevronUp, pixel: PixelChevronUp, phosphor: PhosphorChevronUp }, chevronUp: { lucide: ChevronUp, pixel: PixelChevronUp, phosphor: PhosphorChevronUp },
chevronUpIcon: { lucide: ChevronUpIcon, pixel: PixelChevronUp, phosphor: PhosphorChevronUp }, circleCheck: { lucide: CircleCheckIcon, pixel: PixelCheck, phosphor: PhosphorCheckCircle },
circleCheckIcon: { lucide: CircleCheckIcon, pixel: PixelCheck, phosphor: PhosphorCheckCircle },
circleIcon: { lucide: CircleIcon, pixel: PixelCircle, phosphor: PhosphorCircle }, circleIcon: { lucide: CircleIcon, pixel: PixelCircle, phosphor: PhosphorCircle },
circleQuestionMark: { lucide: CircleQuestionMark, pixel: PixelNoteDelete, phosphor: PhosphorQuestion }, circleQuestionMark: { lucide: CircleQuestionMark, pixel: PixelNoteDelete, phosphor: PhosphorQuestion },
comment: { lucide: MessageSquarePlus, pixel: PixelCommentSend, phosphor: PhosphorComment }, comment: { lucide: MessageSquarePlus, pixel: PixelCommentSend, phosphor: PhosphorComment },
creditCard: { lucide: CreditCard, pixel: PixelCreditCard, phosphor: PhosphorCreditCard },
edit: { lucide: Edit, pixel: PixelEdit, phosphor: PhosphorEdit }, edit: { lucide: Edit, pixel: PixelEdit, phosphor: PhosphorEdit },
ellipsisVertical: { ellipsisVertical: {
lucide: EllipsisVertical, lucide: EllipsisVertical,
@@ -145,26 +168,32 @@ const icons = {
}, },
hash: { lucide: Hash, pixel: PhosphorHashStraight, phosphor: PhosphorHash }, hash: { lucide: Hash, pixel: PhosphorHashStraight, phosphor: PhosphorHash },
home: { lucide: LucideHome, pixel: PixelHome, phosphor: PhosphorHome }, 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 }, link: { lucide: Link, pixel: PixelLink, phosphor: PhosphorLink },
loader: { lucide: Loader, pixel: PixelLoader, phosphor: PhosphorLoader }, 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 }, logOut: { lucide: LogOut, pixel: PixelLogout, phosphor: PhosphorLogOut },
moon: { lucide: Moon, pixel: PixelMoon, phosphor: PhosphorMoon }, 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 }, pause: { lucide: Pause, pixel: PixelPause, phosphor: PhosphorPause },
play: { lucide: Play, pixel: PixelPlay, phosphor: PhosphorPlay }, play: { lucide: Play, pixel: PixelPlay, phosphor: PhosphorPlay },
plus: { lucide: Plus, pixel: PixelPlus, phosphor: PhosphorPlus }, 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 }, sun: { lucide: Sun, pixel: PixelSun, phosphor: PhosphorSun },
stop: { lucide: Square, pixel: PixelStop, phosphor: PhosphorStop }, 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 }, trash: { lucide: Trash, pixel: PixelTrash, phosphor: PhosphorTrash },
triangleAlertIcon: { lucide: TriangleAlertIcon, pixel: PixelAlert, phosphor: PhosphorWarning }, triangleAlert: { lucide: TriangleAlertIcon, pixel: PixelAlert, phosphor: PhosphorWarning },
undo: { lucide: Undo, pixel: PixelUndo, phosphor: PhosphorUndo }, undo: { lucide: Undo, pixel: PixelUndo, phosphor: PhosphorArrowCounterClockwise },
undo2: { lucide: Undo2, pixel: PixelUndo, phosphor: PhosphorUndo }, undo2: { lucide: Undo2, pixel: PixelUndo, phosphor: PhosphorArrowCounterClockwise },
userRound: { lucide: UserRound, pixel: PixelUser, phosphor: PhosphorUser }, userRound: { lucide: UserRound, pixel: PixelUser, phosphor: PhosphorUser },
x: { lucide: X, pixel: PixelClose, phosphor: PhosphorX }, x: { lucide: X, pixel: PixelClose, phosphor: PhosphorX },
zap: { lucide: Zap, pixel: PixelZap, phosphor: PhosphorLightning },
}; };
export type IconName = keyof typeof icons; export type IconName = keyof typeof icons;
@@ -202,7 +231,7 @@ export default function Icon({
// lucide fills sillily // lucide fills sillily
if (color && resolvedStyle !== "lucide") { if (color && resolvedStyle !== "lucide") {
fill = color; fill = color;
} else if (resolvedStyle === "pixel" && ["bug", "moon", "hash"].includes(icon)) { } else if (resolvedStyle === "pixel" && ["bug", "moon", "hash", "bugOff"].includes(icon)) {
fill = "var(--foreground)"; fill = "var(--foreground)";
} else if (resolvedStyle === "phosphor") { } else if (resolvedStyle === "phosphor") {
fill = "var(--foreground)"; fill = "var(--foreground)";

View File

@@ -198,7 +198,7 @@ function SelectScrollUpButton({
className={cn("flex cursor-default items-center justify-center py-1", className)} className={cn("flex cursor-default items-center justify-center py-1", className)}
{...props} {...props}
> >
<Icon icon="chevronUpIcon" className="size-4" /> <Icon icon="chevronUp" className="size-4" />
</SelectPrimitive.ScrollUpButton> </SelectPrimitive.ScrollUpButton>
); );
} }

View File

@@ -10,11 +10,11 @@ const Toaster = ({ ...props }: ToasterProps) => {
theme={theme as ToasterProps["theme"]} theme={theme as ToasterProps["theme"]}
className="toaster group" className="toaster group"
icons={{ icons={{
success: <Icon icon="circleCheckIcon" className="size-4" />, success: <Icon icon="circleCheck" className="size-4" />,
info: <Icon icon="infoIcon" className="size-4" />, info: <Icon icon="info" className="size-4" />,
warning: <Icon icon="triangleAlertIcon" className="size-4" />, warning: <Icon icon="triangleAlert" className="size-4" />,
error: <Icon icon="octagonXIcon" className="size-4" />, error: <Icon icon="octagonX" className="size-4" />,
loading: <Icon icon="loader2Icon" className="size-4 animate-spin" />, loading: <Icon icon="loader2" className="size-4 animate-spin" />,
}} }}
style={ style={
{ {

View File

@@ -1,8 +1,9 @@
import { Icon } from "@iconify/react"; import { HumanRun } from "@nsmr/pixelart-react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useSession } from "@/components/session-provider"; import { useSession } from "@/components/session-provider";
import ThemeToggle from "@/components/theme-toggle"; import ThemeToggle from "@/components/theme-toggle";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import Icon from "@/components/ui/icon";
export default function Landing() { export default function Landing() {
const { user, isLoading } = useSession(); const { user, isLoading } = useSession();
@@ -29,16 +30,19 @@ export default function Landing() {
</header> </header>
<main className="flex-1 flex flex-col items-center py-16 px-4"> <main className="flex-1 flex flex-col items-center py-16 px-4">
<div className="max-w-6xl w-full space-y-24"> <div className="max-w-6xl w-full space-y-18">
{/* hero section */} {/* hero section */}
<div className="text-center space-y-8 pt-8"> <div className="text-center space-y-8 pt-8">
<div className="flex justify-center mb-8">
<HumanRun size={144} fill="var(--foreground)" />
</div>
<div className="space-y-4"> <div className="space-y-4">
<h1 className="text-[64px] font-basteleur font-700 leading-tight"> <h1 className="text-[64px] font-basteleur font-700 leading-tight">
ship faster without the chaos Ship faster without the chaos
</h1> </h1>
<p className="text-[24px] font-goudy text-muted-foreground max-w-3xl mx-auto"> <p className="text-[24px] text-muted-foreground max-w-3xl mx-auto">
sprint is project management that stays out of your way. track issues, manage sprints, and Sprint is project management that stays out of your way. Track issues, manage sprints, and
keep your team movingwithout the jira headache. keep your team movingwithout the Jira headache.
</p> </p>
</div> </div>
@@ -50,42 +54,40 @@ export default function Landing() {
) : ( ) : (
<> <>
<Button asChild size="lg" className="text-lg px-8 py-6"> <Button asChild size="lg" className="text-lg px-8 py-6">
<Link to="/login">start free trial</Link> <Link to="/login">Start free trial</Link>
</Button> </Button>
<Button asChild variant="outline" size="lg" className="text-lg px-8 py-6"> <Button asChild variant="outline" size="lg" className="text-lg px-8 py-6">
<Link to="/pricing">see pricing</Link> <Link to="/pricing">See pricing</Link>
</Button> </Button>
</> </>
)} )}
</div> </div>
<p className="text-sm text-muted-foreground font-goudy"> <p className="text-sm text-muted-foreground">No credit card required · Full access for 14 days</p>
no credit card required · full access for 14 days
</p>
</div> </div>
{/* problem section */} {/* problem section */}
<div className="max-w-4xl mx-auto space-y-6"> <div className="max-w-4xl mx-auto space-y-16">
<h2 className="text-4xl font-basteleur font-700 text-center"> <h2 className="text-4xl font-basteleur font-700 text-center">
tired of spending more time managing jira than building product? Tired of spending more time managing Jira than building your product?
</h2> </h2>
<div className="grid md:grid-cols-3 gap-6"> <div className="grid md:grid-cols-3 gap-6">
<div className="space-y-2"> <div className="space-y-2">
<Icon icon="lucide:timer-off" className="size-8 text-muted-foreground mx-auto" /> <Icon icon="timerOff" className="size-16 mx-auto" color={"var(--muted-foreground)"} />
<p className="text-center font-goudy text-muted-foreground"> <p className="text-center text-muted-foreground">
wasting hours configuring workflows instead of shipping features Wasting hours configuring workflows instead of shipping features
</p> </p>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Icon icon="lucide:boxes" className="size-8 text-muted-foreground mx-auto" /> <Icon icon="box" className="size-16 mx-auto" color={"var(--muted-foreground)"} />
<p className="text-center font-goudy text-muted-foreground"> <p className="text-center text-muted-foreground">
drowning in features you'll never use while missing the basics Drowning in features you'll never use while missing the basics
</p> </p>
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Icon icon="lucide:bug-off" className="size-8 text-muted-foreground mx-auto" /> <Icon icon="bugOff" className="size-16 mx-auto" color={"var(--muted-foreground)"} />
<p className="text-center font-goudy text-muted-foreground"> <p className="text-center text-muted-foreground">
context switching kills momentum—your flow state doesn't stand a chance Context switching kills momentum—your flow state doesn't stand a chance
</p> </p>
</div> </div>
</div> </div>
@@ -94,42 +96,43 @@ export default function Landing() {
{/* solution section */} {/* solution section */}
<div className="max-w-5xl mx-auto space-y-12"> <div className="max-w-5xl mx-auto space-y-12">
<h2 className="text-5xl font-basteleur font-700 text-center"> <h2 className="text-5xl font-basteleur font-700 text-center">
everything you need, nothing you don't Everything you need, nothing you don't
</h2> </h2>
<div className="grid md:grid-cols-2 gap-8"> <div className="grid md:grid-cols-2 gap-8">
<div className="border p-8 space-y-4"> <div className="border p-8 space-y-4">
<Icon icon="lucide:layout-dashboard" className="size-10 text-personality" /> <Icon icon="layoutDashboard" className="size-10" color={"var(--personality)"} />
<h3 className="text-2xl font-basteleur font-700">see your work at a glance</h3> <h3 className="text-2xl font-basteleur font-700">See your work at a glance</h3>
<p className="font-goudy text-muted-foreground text-lg"> <p className="text-muted-foreground text-lg">
beautiful, intuitive issue tracking with customizable statuses. organize by projects and Beautiful, intuitive issue tracking with customizable statuses. Organize by projects and
sprints. find what you need in seconds, not minutes. sprints. Find what you need in seconds, not minutes.
</p> </p>
</div> </div>
<div className="border p-8 space-y-4"> <div className="border p-8 space-y-4">
<Icon icon="lucide:timer" className="size-10 text-personality" /> <Icon icon="timer" className="size-10" color={"var(--personality)"} />
<h3 className="text-2xl font-basteleur font-700">track time without thinking</h3> <h3 className="text-2xl font-basteleur font-700">Track time without thinking</h3>
<p className="font-goudy text-muted-foreground text-lg"> <p className="text-muted-foreground text-lg">
built-in time tracking that actually works. start, pause, resume. see where your time goes Built-in time tracking that actually works. Start, pause, resume. See where your time goes
without juggling another tool. without juggling another tool.
</p> </p>
</div> </div>
<div className="border p-8 space-y-4"> <div className="border p-8 space-y-4">
<Icon icon="lucide:rocket" className="size-10 text-personality" /> <Icon icon="rocket" className="size-10" color={"var(--personality)"} />
<h3 className="text-2xl font-basteleur font-700">ship in sprints</h3> <h3 className="text-2xl font-basteleur font-700">Ship in sprints</h3>
<p className="font-goudy text-muted-foreground text-lg"> <p className="text-muted-foreground text-lg">
sprint planning that actually works. set date ranges, assign issues, track velocity. keep Sprint planning that actually works. Set date ranges, assign issues, track velocity. Keep
your team aligned without the ceremony. your team aligned without the ceremony.
</p> </p>
</div> </div>
<div className="border p-8 space-y-4"> <div className="border p-8 space-y-4">
<Icon icon="lucide:zap" className="size-10 text-personality" /> <Icon icon="checkBox" className="size-10" color={"var(--personality)"} />
<h3 className="text-2xl font-basteleur font-700">stay in flow</h3> <h3 className="text-2xl font-basteleur font-700">Only use what you need</h3>
<p className="font-goudy text-muted-foreground text-lg"> <p className="text-muted-foreground text-lg">
minimal clicks, maximum productivity. keyboard shortcuts, resizable panes, and a clean Every feature is optional. Sprints, time tracking, and other modules can be enabled or
interface that gets out of your way. disabled individually at the organization level. Keep your interface as minimal as your
workflow.
</p> </p>
</div> </div>
</div> </div>
@@ -138,24 +141,24 @@ export default function Landing() {
{/* features list */} {/* features list */}
<div className="max-w-4xl mx-auto border p-8 space-y-6"> <div className="max-w-4xl mx-auto border p-8 space-y-6">
<h2 className="text-3xl font-basteleur font-700 text-center"> <h2 className="text-3xl font-basteleur font-700 text-center">
built for developers, by a developer Built for developers, by a developer
</h2> </h2>
<div className="grid md:grid-cols-2 gap-x-8 gap-y-3"> <div className="grid md:grid-cols-2 gap-x-8 gap-y-3">
{[ {[
"organization and project management", "Organization and project management",
"customizable issue statuses", "Customizable issue statuses",
"sprint planning with date ranges", "Sprint planning with date ranges",
"built-in time tracking", "Built-in time tracking",
"role-based access control", "Role-based access control",
"native desktop app (tauri)", "Native desktop app (Tauri)",
"self-hostable on your infrastructure", "Self-hostable on your infrastructure",
"clean, resizable interface", "Clean, resizable interface",
"issue assignment and collaboration", "Issue assignment and collaboration",
"jwt authentication", "Individual feature toggles (org level)",
].map((feature) => ( ].map((feature) => (
<div key={feature} className="flex items-start gap-2"> <div key={feature} className="flex items-start gap-2">
<Icon icon="lucide:check" className="size-5 text-personality shrink-0 mt-0.5" /> <Icon icon="check" className="size-5 shrink-0 mt-0.5" color={"var(--personality)"} />
<span className="font-goudy">{feature}</span> <span>{feature}</span>
</div> </div>
))} ))}
</div> </div>
@@ -163,34 +166,34 @@ export default function Landing() {
{/* social proof placeholder */} {/* social proof placeholder */}
<div className="max-w-4xl mx-auto text-center space-y-8"> <div className="max-w-4xl mx-auto text-center space-y-8">
<h2 className="text-4xl font-basteleur font-700">join developers who've escaped jira</h2> <h2 className="text-4xl font-basteleur font-700">Join developers who've escaped Jira</h2>
<div className="grid md:grid-cols-3 gap-8"> <div className="grid md:grid-cols-3 gap-8">
<div className="border p-6 space-y-4"> <div className="border p-6 space-y-4">
<p className="font-goudy text-lg italic text-muted-foreground"> <p className="text-lg italic text-muted-foreground">
"finally, a project management tool that doesn't slow me down" "Finally, a project management tool that doesn't slow me down"
</p> </p>
<p className="text-sm font-goudy font-700">early user feedback</p> <p className="text-sm font-700">Early user feedback</p>
</div> </div>
<div className="border p-6 space-y-4"> <div className="border p-6 space-y-4">
<p className="font-goudy text-lg italic text-muted-foreground"> <p className="text-lg italic text-muted-foreground">
"built by someone who actually understands developer workflows" "Built by someone who actually understands developer workflows"
</p> </p>
<p className="text-sm font-goudy font-700">early user feedback</p> <p className="text-sm font-700">Early user feedback</p>
</div> </div>
<div className="border p-6 space-y-4"> <div className="border p-6 space-y-4">
<p className="font-goudy text-lg italic text-muted-foreground"> <p className="text-lg italic text-muted-foreground">
"the simplicity is refreshing. no bloat, just what we need" "The simplicity is refreshing. No bloat, just what we need"
</p> </p>
<p className="text-sm font-goudy font-700">early user feedback</p> <p className="text-sm font-700">Early user feedback</p>
</div> </div>
</div> </div>
</div> </div>
{/* final cta */} {/* final cta */}
<div className="text-center space-y-6 border-t pt-16"> <div className="text-center space-y-6 border-t pt-16">
<h2 className="text-5xl font-basteleur font-700">ready to ship faster?</h2> <h2 className="text-5xl font-basteleur font-700">Ready to ship faster?</h2>
<p className="text-xl font-goudy text-muted-foreground"> <p className="text-xl text-muted-foreground">
start tracking issues, managing sprints, and shipping product in minutes Start tracking issues, managing sprints, and shipping product in minutes
</p> </p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4"> <div className="flex flex-col sm:flex-row items-center justify-center gap-4">
{!isLoading && user ? ( {!isLoading && user ? (
@@ -199,25 +202,25 @@ export default function Landing() {
</Button> </Button>
) : ( ) : (
<Button asChild size="lg" className="text-lg px-8 py-6"> <Button asChild size="lg" className="text-lg px-8 py-6">
<Link to="/login">start your free trial</Link> <Link to="/login">Start your free trial</Link>
</Button> </Button>
)} )}
</div> </div>
<p className="text-sm text-muted-foreground font-goudy"> <p className="text-sm text-muted-foreground">
no credit card required · 14-day free trial · cancel anytime No credit card required · 14-day free trial · Cancel anytime
</p> </p>
</div> </div>
</div> </div>
</main> </main>
<footer className="flex justify-center gap-2 items-center py-1 border-t"> <footer className="flex justify-center gap-2 items-center py-1 border-t">
<span className="font-300 text-lg text-muted-foreground font-goudy"> <span className="font-300 text-lg text-muted-foreground">
Built by{" "} Built by{" "}
<a <a
href="https://ob248.com" href="https://ob248.com"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="hover:text-personality font-goudy font-700" className="hover:text-personality font-700"
> >
Oliver Bryan Oliver Bryan
</a> </a>

View File

@@ -1,9 +1,9 @@
import { Icon } from "@iconify/react";
import { useState } from "react"; import { useState } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { useSession } from "@/components/session-provider"; import { useSession } from "@/components/session-provider";
import ThemeToggle from "@/components/theme-toggle"; import ThemeToggle from "@/components/theme-toggle";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import Icon from "@/components/ui/icon";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
const pricingTiers = [ const pricingTiers = [
@@ -198,7 +198,7 @@ export default function Pricing() {
<ul className="space-y-3 mb-8 flex-1"> <ul className="space-y-3 mb-8 flex-1">
{tier.features.map((feature) => ( {tier.features.map((feature) => (
<li key={feature} className="flex items-start gap-2"> <li key={feature} className="flex items-start gap-2">
<Icon icon="lucide:check" className="size-5 text-personality shrink-0 mt-0.5" /> <Icon icon="check" className="size-5 text-personality shrink-0 mt-0.5" />
<span className={"text-sm"}>{feature}</span> <span className={"text-sm"}>{feature}</span>
</li> </li>
))} ))}
@@ -222,17 +222,17 @@ export default function Pricing() {
<div className="text-center space-y-6 border-t pt-12"> <div className="text-center space-y-6 border-t pt-12">
<div className="grid md:grid-cols-3 gap-8 max-w-4xl mx-auto"> <div className="grid md:grid-cols-3 gap-8 max-w-4xl mx-auto">
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<Icon icon="lucide:shield-check" className="size-8 text-personality" /> <Icon icon="shieldCheck" className="size-8 text-personality" />
<p className="font-goudy font-700">Secure & Encrypted</p> <p className="font-goudy font-700">Secure & Encrypted</p>
<p className="text-sm text-muted-foreground">Your data is encrypted and secure</p> <p className="text-sm text-muted-foreground">Your data is encrypted and secure</p>
</div> </div>
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<Icon icon="lucide:credit-card" className="size-8 text-personality" /> <Icon icon="creditCard" className="size-8 text-personality" />
<p className="font-goudy font-700">No Credit Card Required</p> <p className="font-goudy font-700">No Credit Card Required</p>
<p className="text-sm text-muted-foreground">Start your free trial today</p> <p className="text-sm text-muted-foreground">Start your free trial today</p>
</div> </div>
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<Icon icon="lucide:rotate-ccw" className="size-8 text-personality" /> <Icon icon="rotateCcw" className="size-8 text-personality" />
<p className="font-goudy font-700">30-day money back</p> <p className="font-goudy font-700">30-day money back</p>
<p className="text-sm text-muted-foreground">Cancel anytime, no questions</p> <p className="text-sm text-muted-foreground">Cancel anytime, no questions</p>
</div> </div>