Rebrand frontend to ResolutionFlow #26
@@ -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() {
|
||||
|
||||
30
frontend/public/icons/app-icon-gradient.svg
Normal file
30
frontend/public/icons/app-icon-gradient.svg
Normal 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 |
18
frontend/public/icons/favicon.svg
Normal file
18
frontend/public/icons/favicon.svg
Normal 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 |
23
frontend/public/icons/icon.svg
Normal file
23
frontend/public/icons/icon.svg
Normal 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 |
23
frontend/src/assets/brand/icon.svg
Normal file
23
frontend/src/assets/brand/icon.svg
Normal 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 |
32
frontend/src/assets/brand/logo-horizontal.svg
Normal file
32
frontend/src/assets/brand/logo-horizontal.svg
Normal 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 |
37
frontend/src/assets/brand/logo-with-tagline.svg
Normal file
37
frontend/src/assets/brand/logo-with-tagline.svg
Normal 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 |
56
frontend/src/components/common/BrandLogo.tsx
Normal file
56
frontend/src/components/common/BrandLogo.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
25
frontend/src/components/common/BrandWordmark.tsx
Normal file
25
frontend/src/components/common/BrandWordmark.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: [],
|
||||
|
||||
Reference in New Issue
Block a user