mirror of
https://github.com/hex248/sprint.git
synced 2026-02-08 18:33:01 +00:00
massive landing page improvements
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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)";
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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={
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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 moving—without the jira headache.
|
keep your team moving—without 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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user