Merge pull request #26 from patherly/rebrand-to-resolutionflow

Rebrand frontend to ResolutionFlow
This commit was merged in pull request #26.
This commit is contained in:
chihlasm
2026-02-04 00:03:21 -05:00
committed by GitHub
16 changed files with 385 additions and 54 deletions

View File

@@ -2,9 +2,20 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/icons/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Patherly</title>
<title>ResolutionFlow - Decision Tree Platform</title>
<meta name="description" content="Transform troubleshooting into guided workflows with automatic documentation" />
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Inter:wght@400;500;600&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- PWA Icons -->
<link rel="apple-touch-icon" href="/icons/app-icon-gradient.svg" />
<meta name="theme-color" content="#09090b" />
<script>
// Prevent flash of wrong theme on initial load
(function() {

View File

@@ -0,0 +1,30 @@
<svg viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="bg-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<!-- Background -->
<rect width="512" height="512" rx="96" fill="url(#bg-gradient)"/>
<!-- Icon scaled and centered (white version) -->
<g transform="translate(96, 96) scale(4)">
<!-- Input circles -->
<circle cx="10" cy="14" r="5" fill="white" opacity="0.4"/>
<circle cx="10" cy="30" r="5.5" fill="white" opacity="0.55"/>
<circle cx="10" cy="50" r="5.5" fill="white" opacity="0.55"/>
<circle cx="10" cy="66" r="5" fill="white" opacity="0.4"/>
<!-- Connecting lines -->
<path d="M15 14L28 34" stroke="white" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.5"/>
<path d="M15.5 30L28 38" stroke="white" stroke-width="2" stroke-linecap="round" opacity="0.65"/>
<path d="M15.5 50L28 42" stroke="white" stroke-width="2" stroke-linecap="round" opacity="0.65"/>
<path d="M15 66L28 46" stroke="white" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.5"/>
<!-- Center node with glow -->
<circle cx="36" cy="40" r="10" fill="white" opacity="0.2"/>
<circle cx="36" cy="40" r="7" fill="white"/>
<!-- Arrow -->
<path d="M43 40H70M70 40L60 30M70 40L60 50" stroke="white" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,18 @@
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="fav-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<!-- Simplified icon for small sizes -->
<!-- Input circles -->
<circle cx="5" cy="8" r="2.5" fill="url(#fav-gradient)" opacity="0.35"/>
<circle cx="5" cy="16" r="3" fill="url(#fav-gradient)" opacity="0.5"/>
<circle cx="5" cy="24" r="2.5" fill="url(#fav-gradient)" opacity="0.35"/>
<!-- Center node -->
<circle cx="14" cy="16" r="4" fill="url(#fav-gradient)"/>
<!-- Arrow -->
<path d="M18 16H28M28 16L24 12M28 16L24 20" stroke="url(#fav-gradient)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 825 B

View File

@@ -0,0 +1,23 @@
<svg viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="resolutionflow-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<!-- Input circles (choices) -->
<circle cx="10" cy="14" r="5" fill="url(#resolutionflow-gradient)" opacity="0.25"/>
<circle cx="10" cy="30" r="5.5" fill="url(#resolutionflow-gradient)" opacity="0.4"/>
<circle cx="10" cy="50" r="5.5" fill="url(#resolutionflow-gradient)" opacity="0.4"/>
<circle cx="10" cy="66" r="5" fill="url(#resolutionflow-gradient)" opacity="0.25"/>
<!-- Connecting lines (outer dotted, inner solid) -->
<path d="M15 14L28 34" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.35"/>
<path d="M15.5 30L28 38" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<path d="M15.5 50L28 42" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<path d="M15 66L28 46" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.35"/>
<!-- Center node with glow -->
<circle cx="36" cy="40" r="10" fill="url(#resolutionflow-gradient)" opacity="0.12"/>
<circle cx="36" cy="40" r="7" fill="url(#resolutionflow-gradient)" opacity="0.9"/>
<!-- Arrow (documentation output) -->
<path d="M43 40H70M70 40L60 30M70 40L60 50" stroke="url(#resolutionflow-gradient)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,23 @@
<svg viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="resolutionflow-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<!-- Input circles (choices) -->
<circle cx="10" cy="14" r="5" fill="url(#resolutionflow-gradient)" opacity="0.25"/>
<circle cx="10" cy="30" r="5.5" fill="url(#resolutionflow-gradient)" opacity="0.4"/>
<circle cx="10" cy="50" r="5.5" fill="url(#resolutionflow-gradient)" opacity="0.4"/>
<circle cx="10" cy="66" r="5" fill="url(#resolutionflow-gradient)" opacity="0.25"/>
<!-- Connecting lines (outer dotted, inner solid) -->
<path d="M15 14L28 34" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.35"/>
<path d="M15.5 30L28 38" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<path d="M15.5 50L28 42" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<path d="M15 66L28 46" stroke="url(#resolutionflow-gradient)" stroke-width="2" stroke-linecap="round" stroke-dasharray="2 3" opacity="0.35"/>
<!-- Center node with glow -->
<circle cx="36" cy="40" r="10" fill="url(#resolutionflow-gradient)" opacity="0.12"/>
<circle cx="36" cy="40" r="7" fill="url(#resolutionflow-gradient)" opacity="0.9"/>
<!-- Arrow (documentation output) -->
<path d="M43 40H70M70 40L60 30M70 40L60 50" stroke="url(#resolutionflow-gradient)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,32 @@
<svg viewBox="0 0 320 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="rf-gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<!-- Icon -->
<g transform="translate(0, 8)">
<!-- Input circles -->
<circle cx="10" cy="11" r="4" fill="url(#rf-gradient)" opacity="0.25"/>
<circle cx="10" cy="24" r="4.5" fill="url(#rf-gradient)" opacity="0.4"/>
<circle cx="10" cy="40" r="4.5" fill="url(#rf-gradient)" opacity="0.4"/>
<circle cx="10" cy="53" r="4" fill="url(#rf-gradient)" opacity="0.25"/>
<!-- Connecting lines -->
<path d="M14 11L24 27" stroke="url(#rf-gradient)" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="2 2.5" opacity="0.35"/>
<path d="M14.5 24L24 30" stroke="url(#rf-gradient)" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<path d="M14.5 40L24 34" stroke="url(#rf-gradient)" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<path d="M14 53L24 37" stroke="url(#rf-gradient)" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="2 2.5" opacity="0.35"/>
<!-- Center node with glow -->
<circle cx="30" cy="32" r="8" fill="url(#rf-gradient)" opacity="0.12"/>
<circle cx="30" cy="32" r="5.5" fill="url(#rf-gradient)" opacity="0.9"/>
<!-- Arrow -->
<path d="M36 32H56M56 32L48 24M56 32L48 40" stroke="url(#rf-gradient)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<!-- Text -->
<text x="72" y="50" font-family="'Plus Jakarta Sans', 'Segoe UI', sans-serif" font-size="28" font-weight="700" letter-spacing="-0.5">
<tspan fill="#ffffff">Resolution</tspan><tspan fill="url(#rf-gradient)">Flow</tspan>
</text>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,37 @@
<svg viewBox="0 0 320 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="rf-gradient-tag" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#a78bfa"/>
</linearGradient>
</defs>
<!-- Icon -->
<g transform="translate(0, 8)">
<!-- Input circles -->
<circle cx="10" cy="11" r="4" fill="url(#rf-gradient-tag)" opacity="0.25"/>
<circle cx="10" cy="24" r="4.5" fill="url(#rf-gradient-tag)" opacity="0.4"/>
<circle cx="10" cy="40" r="4.5" fill="url(#rf-gradient-tag)" opacity="0.4"/>
<circle cx="10" cy="53" r="4" fill="url(#rf-gradient-tag)" opacity="0.25"/>
<!-- Connecting lines -->
<path d="M14 11L24 27" stroke="url(#rf-gradient-tag)" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="2 2.5" opacity="0.35"/>
<path d="M14.5 24L24 30" stroke="url(#rf-gradient-tag)" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<path d="M14.5 40L24 34" stroke="url(#rf-gradient-tag)" stroke-width="1.5" stroke-linecap="round" opacity="0.5"/>
<path d="M14 53L24 37" stroke="url(#rf-gradient-tag)" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="2 2.5" opacity="0.35"/>
<!-- Center node with glow -->
<circle cx="30" cy="32" r="8" fill="url(#rf-gradient-tag)" opacity="0.12"/>
<circle cx="30" cy="32" r="5.5" fill="url(#rf-gradient-tag)" opacity="0.9"/>
<!-- Arrow -->
<path d="M36 32H56M56 32L48 24M56 32L48 40" stroke="url(#rf-gradient-tag)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<!-- Text -->
<text x="72" y="50" font-family="'Plus Jakarta Sans', 'Segoe UI', sans-serif" font-size="28" font-weight="700" letter-spacing="-0.5">
<tspan fill="#ffffff">Resolution</tspan><tspan fill="url(#rf-gradient-tag)">Flow</tspan>
</text>
<!-- Tagline -->
<text x="72" y="75" font-family="'Plus Jakarta Sans', 'Segoe UI', sans-serif" font-size="13" font-weight="500" fill="url(#rf-gradient-tag)">
From issue to resolution, documented.
</text>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,56 @@
import { cn } from '@/lib/utils'
interface BrandLogoProps {
size?: 'sm' | 'lg'
className?: string
}
/**
* ResolutionFlow brand logo icon.
* sm (32x32) for header/navbar, lg (80x80) for login/register pages.
*/
export function BrandLogo({ size = 'sm', className }: BrandLogoProps) {
const sizeClasses = size === 'sm' ? 'h-8 w-8' : 'h-20 w-20'
// The SVG scales via viewBox - same paths work at any size.
// Stroke widths are tuned per size for visual clarity.
const strokeBase = size === 'sm' ? 1 : 2
const strokeThick = size === 'sm' ? 1.25 : 2.5
const dashArray = size === 'sm' ? '1 1.5' : '2 3'
const nodeR = size === 'sm' ? { outer: 2.5, inner: 2.75 } : { outer: 5, inner: 5.5 }
const hubR = size === 'sm' ? { glow: 5, solid: 3.5 } : { glow: 10, solid: 7 }
// Positions scale with viewBox
const vb = size === 'sm' ? '0 0 40 40' : '0 0 80 80'
const s = size === 'sm' ? 1 : 2 // scale factor
return (
<svg viewBox={vb} fill="none" className={cn(sizeClasses, className)}>
<defs>
<linearGradient id="brand-logo-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#818cf8" />
<stop offset="100%" stopColor="#a78bfa" />
</linearGradient>
</defs>
{/* Input nodes */}
<circle cx={5 * s} cy={7 * s} r={nodeR.outer} fill="url(#brand-logo-grad)" opacity="0.35" />
<circle cx={5 * s} cy={15 * s} r={nodeR.inner} fill="url(#brand-logo-grad)" opacity="0.5" />
<circle cx={5 * s} cy={25 * s} r={nodeR.inner} fill="url(#brand-logo-grad)" opacity="0.5" />
<circle cx={5 * s} cy={33 * s} r={nodeR.outer} fill="url(#brand-logo-grad)" opacity="0.35" />
{/* Connecting lines */}
<path d={`M${7.5 * s} ${7 * s}L${14 * s} ${17 * s}`} stroke="url(#brand-logo-grad)" strokeWidth={strokeBase} strokeLinecap="round" strokeDasharray={dashArray} opacity="0.45" />
<path d={`M${7.75 * s} ${15 * s}L${14 * s} ${19 * s}`} stroke="url(#brand-logo-grad)" strokeWidth={strokeBase} strokeLinecap="round" opacity="0.6" />
<path d={`M${7.75 * s} ${25 * s}L${14 * s} ${21 * s}`} stroke="url(#brand-logo-grad)" strokeWidth={strokeBase} strokeLinecap="round" opacity="0.6" />
<path d={`M${7.5 * s} ${33 * s}L${14 * s} ${23 * s}`} stroke="url(#brand-logo-grad)" strokeWidth={strokeBase} strokeLinecap="round" strokeDasharray={dashArray} opacity="0.45" />
{/* Central hub */}
<circle cx={18 * s} cy={20 * s} r={hubR.glow} fill="url(#brand-logo-grad)" opacity="0.15" />
<circle cx={18 * s} cy={20 * s} r={hubR.solid} fill="url(#brand-logo-grad)" />
{/* Output arrow */}
<path d={`M${21.5 * s} ${20 * s}H${35 * s}M${35 * s} ${20 * s}L${30 * s} ${15 * s}M${35 * s} ${20 * s}L${30 * s} ${25 * s}`} stroke="url(#brand-logo-grad)" strokeWidth={strokeThick} strokeLinecap="round" strokeLinejoin="round" />
</svg>
)
}

View File

@@ -0,0 +1,25 @@
import { cn } from '@/lib/utils'
interface BrandWordmarkProps {
size?: 'sm' | 'lg'
className?: string
}
/**
* ResolutionFlow wordmark with gradient "Flow" text.
* sm for header/navbar, lg for login/register pages.
*/
export function BrandWordmark({ size = 'sm', className }: BrandWordmarkProps) {
return (
<span
className={cn(
'font-heading font-bold',
size === 'sm' ? 'text-xl' : 'text-3xl tracking-tight',
className
)}
>
<span className="text-foreground">Resolution</span>
<span className="text-gradient-brand">Flow</span>
</span>
)
}

View File

@@ -1,6 +1,8 @@
import { Link, useLocation, useNavigate, Outlet } from 'react-router-dom'
import { useAuthStore } from '@/store/authStore'
import { ThemeToggle } from '@/components/common/ThemeToggle'
import { BrandLogo } from '@/components/common/BrandLogo'
import { BrandWordmark } from '@/components/common/BrandWordmark'
import { cn } from '@/lib/utils'
export function AppLayout() {
@@ -22,11 +24,12 @@ export function AppLayout() {
return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="sticky top-0 z-50 border-b border-border bg-card">
<div className="container mx-auto flex h-14 items-center justify-between px-4">
<header className="sticky top-0 z-50 border-b border-border bg-card backdrop-blur-sm">
<div className="container mx-auto flex h-16 items-center justify-between px-4">
<div className="flex items-center gap-8">
<Link to="/trees" className="text-lg font-bold text-foreground">
Patherly
<Link to="/trees" className="flex items-center gap-2">
<BrandLogo size="sm" />
<BrandWordmark size="sm" />
</Link>
<nav className="hidden items-center gap-1 sm:flex">
{navItems.map((item) => (

View File

@@ -136,10 +136,10 @@ function FolderItem({
)}
<Folder className="h-4 w-4 shrink-0" style={{ color: folder.color }} />
<span className="flex-1 truncate text-left">{folder.name}</span>
<span className="text-xs text-muted-foreground">{folder.tree_count}</span>
<span className="text-xs text-muted-foreground group-hover:hidden">{folder.tree_count}</span>
</button>
{/* Folder menu button */}
{/* Folder menu button - replaces tree count on hover */}
<button
onClick={(e) => {
e.stopPropagation()
@@ -147,7 +147,7 @@ function FolderItem({
}}
className={cn(
'absolute right-1 top-1/2 -translate-y-1/2 rounded p-1',
'opacity-0 group-hover:opacity-100',
'hidden group-hover:block',
'hover:bg-accent'
)}
>

View File

@@ -4,13 +4,14 @@
@layer base {
:root {
/* Light mode (fallback) */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary: 243 75% 59%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
@@ -22,30 +23,31 @@
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
--ring: 243 75% 59%;
--radius: 0.75rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
/* ResolutionFlow Dark Theme */
--background: 240 10% 3.9%;
--foreground: 0 0% 100%;
--card: 240 10% 9.4%;
--card-foreground: 0 0% 100%;
--popover: 240 10% 9.4%;
--popover-foreground: 0 0% 100%;
--primary: 243 75% 59%;
--primary-foreground: 0 0% 100%;
--secondary: 240 5.9% 15%;
--secondary-foreground: 0 0% 100%;
--muted: 240 5.9% 15%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 5.9% 15%;
--accent-foreground: 0 0% 100%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
--destructive-foreground: 0 0% 100%;
--border: 240 5.9% 15%;
--input: 240 5.9% 15%;
--ring: 243 75% 59%;
}
}
@@ -53,8 +55,21 @@
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-weight: 700;
letter-spacing: -0.02em;
}
}
@layer utilities {
.text-gradient-brand {
@apply bg-gradient-brand bg-clip-text text-transparent;
}
}

View File

@@ -1,6 +1,8 @@
import { useState } from 'react'
import { Link, useNavigate, useLocation } from 'react-router-dom'
import { useAuthStore } from '@/store/authStore'
import { BrandLogo } from '@/components/common/BrandLogo'
import { BrandWordmark } from '@/components/common/BrandWordmark'
import { cn } from '@/lib/utils'
export function LoginPage() {
@@ -36,20 +38,30 @@ export function LoginPage() {
<div className="flex min-h-screen items-center justify-center bg-background px-4">
<div className="w-full max-w-md space-y-8">
<div className="text-center">
<h1 className="text-3xl font-bold tracking-tight text-foreground">Patherly</h1>
<p className="mt-2 text-muted-foreground">Sign in to your account</p>
<div className="mb-6 flex justify-center">
<BrandLogo size="lg" />
</div>
<h1>
<BrandWordmark size="lg" />
</h1>
<p className="mt-3 text-lg font-medium text-gradient-brand">
Decision Tree Platform
</p>
<p className="mt-2 text-sm text-muted-foreground">
Sign in to your account
</p>
</div>
<form onSubmit={handleSubmit} className="mt-8 space-y-6">
<div className="space-y-4 rounded-lg border border-border bg-card p-6 shadow-sm">
<div className="space-y-4 rounded-lg border border-border bg-card p-6 shadow-lg">
{(error || localError) && (
<div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
<div className="rounded-md border border-destructive/20 bg-destructive/10 p-3 text-sm text-destructive">
{localError || error}
</div>
)}
<div>
<label htmlFor="email" className="block text-sm font-medium text-foreground">
<label htmlFor="email" className="mb-1 block text-sm font-medium text-foreground">
Email address
</label>
<input
@@ -61,16 +73,17 @@ export function LoginPage() {
value={email}
onChange={(e) => setEmail(e.target.value)}
className={cn(
'mt-1 block w-full rounded-md border border-input bg-background px-3 py-2',
'block w-full rounded-md border border-input bg-background px-3 py-2',
'text-foreground placeholder:text-muted-foreground',
'focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary'
'focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20',
'transition-colors'
)}
placeholder="you@example.com"
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-foreground">
<label htmlFor="password" className="mb-1 block text-sm font-medium text-foreground">
Password
</label>
<input
@@ -82,9 +95,10 @@ export function LoginPage() {
value={password}
onChange={(e) => setPassword(e.target.value)}
className={cn(
'mt-1 block w-full rounded-md border border-input bg-background px-3 py-2',
'block w-full rounded-md border border-input bg-background px-3 py-2',
'text-foreground placeholder:text-muted-foreground',
'focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary'
'focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20',
'transition-colors'
)}
placeholder="••••••••••"
/>
@@ -94,9 +108,11 @@ export function LoginPage() {
type="submit"
disabled={isLoading}
className={cn(
'w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground',
'hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50'
'w-full rounded-md px-4 py-2.5 text-sm font-semibold text-white',
'bg-gradient-brand hover:bg-gradient-brand-hover',
'focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'transition-all shadow-lg shadow-primary/20'
)}
>
{isLoading ? 'Signing in...' : 'Sign in'}
@@ -105,7 +121,7 @@ export function LoginPage() {
<p className="text-center text-sm text-muted-foreground">
Don't have an account?{' '}
<Link to="/register" className="font-medium text-primary hover:text-primary/90">
<Link to="/register" className="font-medium text-gradient-brand hover:underline">
Register
</Link>
</p>

View File

@@ -2,6 +2,8 @@ import { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { useAuthStore } from '@/store/authStore'
import { inviteApi } from '@/api'
import { BrandLogo } from '@/components/common/BrandLogo'
import { BrandWordmark } from '@/components/common/BrandWordmark'
import { cn } from '@/lib/utils'
export function RegisterPage() {
@@ -77,8 +79,18 @@ export function RegisterPage() {
<div className="flex min-h-screen items-center justify-center bg-background px-4">
<div className="w-full max-w-md space-y-8">
<div className="text-center">
<h1 className="text-3xl font-bold tracking-tight text-foreground">Patherly</h1>
<p className="mt-2 text-muted-foreground">Create your account</p>
<div className="mb-6 flex justify-center">
<BrandLogo size="lg" />
</div>
<h1>
<BrandWordmark size="lg" />
</h1>
<p className="mt-3 text-lg font-medium text-gradient-brand">
Decision Tree Platform
</p>
<p className="mt-2 text-sm text-muted-foreground">
Create your account
</p>
</div>
<form onSubmit={handleSubmit} className="mt-8 space-y-6">
@@ -216,9 +228,11 @@ export function RegisterPage() {
type="submit"
disabled={isLoading}
className={cn(
'w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground',
'hover:bg-primary/90 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50'
'w-full rounded-md px-4 py-2.5 text-sm font-semibold text-white',
'bg-gradient-brand hover:bg-gradient-brand-hover',
'focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'transition-all shadow-lg shadow-primary/20'
)}
>
{isLoading ? 'Creating account...' : 'Create account'}
@@ -227,7 +241,7 @@ export function RegisterPage() {
<p className="text-center text-sm text-muted-foreground">
Already have an account?{' '}
<Link to="/login" className="font-medium text-primary hover:text-primary/90">
<Link to="/login" className="font-medium text-gradient-brand hover:underline">
Sign in
</Link>
</p>

View File

@@ -25,7 +25,7 @@ export function SettingsPage() {
<div className="rounded-lg border border-border bg-card p-6 shadow-sm">
<h2 className="text-lg font-semibold text-card-foreground">Appearance</h2>
<p className="mt-1 text-sm text-muted-foreground">
Customize how Patherly looks on your device
Customize how ResolutionFlow looks on your device
</p>
<div className="mt-4">
@@ -79,10 +79,10 @@ export function SettingsPage() {
<div className="rounded-lg border border-border bg-card p-6 shadow-sm">
<h2 className="text-lg font-semibold text-card-foreground">About</h2>
<p className="mt-1 text-sm text-muted-foreground">
Patherly - Troubleshooting Decision Trees
ResolutionFlow - Decision Tree Platform
</p>
<p className="mt-2 text-sm text-muted-foreground">
"Take the path MOST traveled."
Transform troubleshooting into guided workflows
</p>
</div>
</div>

View File

@@ -8,6 +8,25 @@ export default {
theme: {
extend: {
colors: {
// ResolutionFlow Brand Colors
brand: {
gradient: {
from: '#818cf8',
to: '#a78bfa',
},
dark: {
DEFAULT: '#09090b',
card: '#18181b',
surface: '#12121c',
},
text: {
primary: '#ffffff',
secondary: '#a1a1aa',
muted: '#52525b',
},
border: '#27272a',
},
// shadcn/ui color system
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
@@ -47,6 +66,15 @@ export default {
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
fontFamily: {
sans: ['Inter', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
heading: ['Plus Jakarta Sans', 'system-ui', 'sans-serif'],
label: ['Outfit', 'system-ui', 'sans-serif'],
},
backgroundImage: {
'gradient-brand': 'linear-gradient(90deg, #818cf8 0%, #a78bfa 100%)',
'gradient-brand-hover': 'linear-gradient(90deg, #6366f1 0%, #9333ea 100%)',
},
},
},
plugins: [],