Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions resources/views/components/app/context-nav-item.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@props([
'href',
'label',
'icon',
'current' => false,
])

<a
href="{{ $href }}"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding aria-current when $current is true (e.g., aria-current="page") so the active context nav item is announced correctly to screen readers, not just styled visually.

Suggested change
href="{{ $href }}"
href="{{ $href }}"
@if($current) aria-current="page" @endif

Copilot uses AI. Check for mistakes.
@class([
'flex items-center gap-3 rounded-md px-3 py-2.5 text-sm transition-colors',
'bg-main font-medium text-copy' => $current,
'text-muted hover:bg-main hover:text-copy' => ! $current,
])
>
<span class="flex size-8 items-center justify-center rounded-md bg-main text-muted">
<x-dynamic-component :component="$icon" class="size-4" />
</span>
<span>{{ $label }}</span>
</a>
20 changes: 20 additions & 0 deletions resources/views/components/app/toolbar-item.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@props([
'href',
'label',
'icon',
'current' => false,
])

<a
href="{{ $href }}"
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding aria-current when $current is true (e.g., aria-current="page") so the active toolbar item is announced correctly to screen readers, not just styled visually.

Suggested change
href="{{ $href }}"
href="{{ $href }}"
@if ($current) aria-current="page" @endif

Copilot uses AI. Check for mistakes.
@class([
'flex min-w-16 flex-col items-center gap-2 rounded-md px-2 py-3 text-center text-[0.7rem] transition-colors',
'bg-white/12 text-white' => $current,
'text-toolbar-muted hover:bg-white/8 hover:text-white' => ! $current,
])
>
<span class="flex size-9 items-center justify-center rounded-md bg-white/8">
<x-dynamic-component :component="$icon" class="size-5" />
</span>
<span>{{ $label }}</span>
</a>
42 changes: 14 additions & 28 deletions resources/views/components/layouts/app-shell.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,12 @@ class="flex size-10 items-center justify-center rounded-lg bg-white/10 text-whit

<nav aria-label="Applications" class="mt-4 flex gap-2 overflow-x-auto lg:mt-0 lg:flex-1 lg:flex-col lg:items-center">
@foreach ($toolbarItems as $item)
<a
href="{{ $item['href'] ?? '#' }}"
@class([
'flex min-w-16 flex-col items-center gap-2 rounded-lg px-2 py-3 text-center text-[0.7rem] transition-colors',
'bg-white/12 text-white' => $item['current'] ?? false,
'text-toolbar-muted hover:bg-white/8 hover:text-white' => ! ($item['current'] ?? false),
])
>
<span class="flex size-9 items-center justify-center rounded-lg bg-white/8">
<x-dynamic-component :component="$item['icon']" class="size-5" />
</span>
<span>{{ $item['label'] }}</span>
</a>
<x-app.toolbar-item
:href="$item['href'] ?? '#'"
:label="$item['label']"
:icon="$item['icon']"
:current="$item['current'] ?? false"
/>
@endforeach
</nav>
</aside>
Expand All @@ -106,31 +99,24 @@ class="flex size-10 items-center justify-center rounded-lg bg-white/10 text-whit
class="bg-panel px-5 py-5 lg:w-72 lg:px-6 lg:py-8"
>
<div class="mb-6 flex items-center gap-3">
<span class="flex size-10 items-center justify-center rounded-lg bg-accent-soft text-accent-strong">
<span class="flex size-10 items-center justify-center rounded-md bg-accent-soft text-accent-strong">
<x-heroicon-o-light-bulb class="size-5" />
</span>
<div>
<p class="text-xs font-medium uppercase tracking-wide text-muted">Current app</p>
<p class="text-xs font-medium uppercase text-muted">Current app</p>
<h1 class="text-lg font-semibold">Ideas</h1>
</div>
</div>

<ul class="space-y-1.5">
@foreach ($contextItems as $item)
<li>
<a
href="{{ $item['href'] ?? '#' }}"
@class([
'flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm transition-colors',
'bg-main font-medium text-copy' => $item['current'] ?? false,
'text-muted hover:bg-main hover:text-copy' => ! ($item['current'] ?? false),
])
>
<span class="flex size-8 items-center justify-center rounded-lg bg-main text-muted">
<x-dynamic-component :component="$item['icon']" class="size-4" />
</span>
<span>{{ $item['label'] }}</span>
</a>
<x-app.context-nav-item
:href="$item['href'] ?? '#'"
:label="$item['label']"
:icon="$item['icon']"
:current="$item['current'] ?? false"
/>
</li>
@endforeach
</ul>
Expand Down
17 changes: 17 additions & 0 deletions resources/views/components/ui/avatar.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@props([
'name' => null,
'initials' => null,
'size' => 'md',
])

@php
$sizeClasses = [
'sm' => 'size-8 text-xs',
'md' => 'size-10 text-sm',
'lg' => 'size-12 text-base',
];
@endphp

<span {{ $attributes->class(['inline-flex items-center justify-center rounded-md bg-accent-soft font-medium text-accent-strong', $sizeClasses[$size] ?? $sizeClasses['md']]) }}>
{{ $initials ?? \Illuminate\Support\Str::of((string) $name)->trim()->explode(' ')->filter()->take(2)->map(fn (string $part): string => mb_strtoupper(mb_substr($part, 0, 1)))->implode('') ?: '?' }}
</span>
15 changes: 15 additions & 0 deletions resources/views/components/ui/badge.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@props([
'tone' => 'neutral',
])

@php
$toneClasses = [
'neutral' => 'bg-main text-muted',
'accent' => 'bg-accent-soft text-accent-strong',
'success' => 'bg-emerald-500/12 text-emerald-700 dark:text-emerald-300',
];
@endphp

<span {{ $attributes->class(['inline-flex items-center rounded-md px-2 py-1 text-xs font-medium', $toneClasses[$tone] ?? $toneClasses['neutral']]) }}>
{{ $slot }}
</span>
21 changes: 21 additions & 0 deletions resources/views/components/ui/button.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@props([
'type' => 'button',
'variant' => 'primary',
])

@php
$variantClasses = [
'primary' => 'bg-accent text-white hover:bg-accent-strong',
'secondary' => 'bg-main text-copy hover:bg-panel',
'ghost' => 'bg-transparent text-copy hover:bg-main',
];

$baseClasses = 'inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50';
@endphp

<button
type="{{ $type }}"
{{ $attributes->class([$baseClasses, $variantClasses[$variant] ?? $variantClasses['primary']]) }}
>
{{ $slot }}
</button>
13 changes: 13 additions & 0 deletions resources/views/components/ui/dropdown.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@props([
'label' => 'Menu',
])

<details {{ $attributes->class(['group relative']) }}>
<summary class="list-none rounded-md bg-main px-3 py-2 text-sm font-medium text-copy marker:hidden">
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

marker:hidden is unlikely to affect the <summary> disclosure marker (::marker doesn’t support display: none). Since list-none is already present, consider removing marker:hidden, or hide the marker via a targeted CSS rule (e.g., summary::-webkit-details-marker { display: none; }) if needed.

Suggested change
<summary class="list-none rounded-md bg-main px-3 py-2 text-sm font-medium text-copy marker:hidden">
<summary class="list-none rounded-md bg-main px-3 py-2 text-sm font-medium text-copy">

Copilot uses AI. Check for mistakes.
{{ $label }}
</summary>

<div class="absolute z-10 mt-2 min-w-48 rounded-md bg-panel p-2 shadow-none ring-1 ring-inset ring-black/5">
{{ $slot }}
</div>
</details>
20 changes: 20 additions & 0 deletions resources/views/components/ui/input.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@props([
'label' => null,
'error' => null,
])

@php
$fieldClasses = 'block w-full rounded-md border-0 bg-main px-3 py-2 text-sm text-copy shadow-none ring-1 ring-inset ring-transparent transition placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-accent';
@endphp

<label class="block space-y-2">
@if ($label)
<span class="text-sm font-medium text-copy">{{ $label }}</span>
@endif

<input {{ $attributes->class([$fieldClasses]) }}>

@if ($error)
<span class="text-sm text-red-500">{{ $error }}</span>
@endif
Comment on lines +15 to +19
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $error is present, the input isn’t marked/linked for assistive tech: consider setting aria-invalid="true" and associating the error text via aria-describedby (using a stable id from $attributes->get('id') or derived from name). This makes validation errors discoverable to screen readers.

Copilot uses AI. Check for mistakes.
</label>
13 changes: 13 additions & 0 deletions resources/views/components/ui/modal.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@props([
'title' => null,
])

<div {{ $attributes->class(['rounded-md bg-panel p-5']) }}>
@if ($title)
<h2 class="text-base font-semibold text-copy">{{ $title }}</h2>
Comment on lines +5 to +7
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component is named modal, but the markup is only a styled container and doesn’t provide dialog/modal semantics (e.g., role="dialog", aria-modal, labeling via aria-labelledby, backdrop/focus management). Either rename it to reflect that it’s a non-modal surface, or implement the expected modal semantics to avoid consumers shipping an inaccessible/non-modal “modal”.

Suggested change
<div {{ $attributes->class(['rounded-md bg-panel p-5']) }}>
@if ($title)
<h2 class="text-base font-semibold text-copy">{{ $title }}</h2>
@php
$titleId = $title ? 'modal-title-' . uniqid() : null;
@endphp
<div
role="dialog"
aria-modal="true"
@if ($titleId) aria-labelledby="{{ $titleId }}" @endif
tabindex="-1"
{{ $attributes->class(['rounded-md bg-panel p-5']) }}
>
@if ($title)
<h2 id="{{ $titleId }}" class="text-base font-semibold text-copy">{{ $title }}</h2>

Copilot uses AI. Check for mistakes.
@endif

<div class="mt-4">
{{ $slot }}
</div>
</div>
26 changes: 26 additions & 0 deletions resources/views/components/ui/page-header.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@props([
'eyebrow' => null,
'title' => null,
'description' => null,
'actions' => null,
])

<header {{ $attributes->class(['space-y-3']) }}>
@if ($eyebrow)
<p class="text-sm font-medium uppercase text-muted">{{ $eyebrow }}</p>
@endif

@if ($title)
<h1 class="max-w-3xl text-3xl font-semibold text-copy">{{ $title }}</h1>
@endif

@if ($description)
<p class="max-w-3xl text-base leading-7 text-muted">{{ $description }}</p>
@endif

@if ($actions)
<div class="flex flex-wrap items-center gap-3">
{{ $actions }}
</div>
@endif
</header>
20 changes: 20 additions & 0 deletions resources/views/components/ui/panel.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@props([
'title' => null,
'subtitle' => null,
])

<section {{ $attributes->class(['rounded-md bg-panel px-5 py-5']) }}>
@if ($title || $subtitle)
<header class="space-y-1">
@if ($title)
<h2 class="text-base font-semibold text-copy">{{ $title }}</h2>
@endif

@if ($subtitle)
<p class="text-sm text-muted">{{ $subtitle }}</p>
@endif
</header>
@endif

{{ $slot }}
</section>
22 changes: 22 additions & 0 deletions resources/views/components/ui/select.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
@props([
'label' => null,
'error' => null,
])

@php
$fieldClasses = 'block w-full rounded-md border-0 bg-main px-3 py-2 text-sm text-copy shadow-none ring-1 ring-inset ring-transparent transition focus:outline-none focus:ring-2 focus:ring-accent';
@endphp

<label class="block space-y-2">
@if ($label)
<span class="text-sm font-medium text-copy">{{ $label }}</span>
@endif

<select {{ $attributes->class([$fieldClasses]) }}>
{{ $slot }}
</select>

@if ($error)
Comment on lines +15 to +19
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $error is present, the select isn’t marked/linked for assistive tech: consider setting aria-invalid="true" and associating the error text via aria-describedby (using a stable id from $attributes->get('id') or derived from name).

Copilot uses AI. Check for mistakes.
<span class="text-sm text-red-500">{{ $error }}</span>
@endif
</label>
20 changes: 20 additions & 0 deletions resources/views/components/ui/textarea.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@props([
'label' => null,
'error' => null,
])

@php
$fieldClasses = 'block w-full rounded-md border-0 bg-main px-3 py-2 text-sm text-copy shadow-none ring-1 ring-inset ring-transparent transition placeholder:text-muted focus:outline-none focus:ring-2 focus:ring-accent';
@endphp

<label class="block space-y-2">
@if ($label)
<span class="text-sm font-medium text-copy">{{ $label }}</span>
@endif

<textarea {{ $attributes->class([$fieldClasses]) }}></textarea>

@if ($error)
<span class="text-sm text-red-500">{{ $error }}</span>
@endif
Comment on lines +15 to +19
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When $error is present, the textarea isn’t marked/linked for assistive tech: consider setting aria-invalid="true" and associating the error text via aria-describedby (using a stable id from $attributes->get('id') or derived from name).

Copilot uses AI. Check for mistakes.
</label>
29 changes: 14 additions & 15 deletions resources/views/home.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,25 +65,22 @@

<x-layouts.app-shell :title="config('app.name', 'Replicator')" :toolbar-items="$toolbarItems" :context-items="$contextItems">
<div class="mx-auto max-w-5xl space-y-8">
<section class="space-y-3">
<p class="text-sm font-medium uppercase tracking-wide text-muted">Workspace</p>
<h2 class="max-w-3xl text-3xl font-semibold text-copy">Turn rough product thoughts into team-ready software proposals.</h2>
<p class="max-w-3xl text-base leading-7 text-muted">
This shell is the first pass at the shared product frame: app switcher on the left, context navigation beside it,
and a main work area ready for ideas, planning, development, testing, security, ops, and admin tools.
</p>
</section>
<x-ui.page-header
eyebrow="Workspace"
title="Turn rough product thoughts into team-ready software proposals."
description="This shell is the first pass at the shared product frame: app switcher on the left, context navigation beside it, and a main work area ready for ideas, planning, development, testing, security, ops, and admin tools."
/>

<section class="grid gap-6 lg:grid-cols-[minmax(0,2fr)_minmax(18rem,1fr)]">
<div class="space-y-5 rounded-lg bg-panel px-5 py-5">
<x-ui.panel>
<div class="flex items-start justify-between gap-4">
<div class="space-y-2">
<p class="text-sm font-medium text-muted">Current draft</p>
<h3 class="text-xl font-semibold text-copy">Private idea workspace</h3>
</div>
<span class="rounded-lg bg-accent-soft px-3 py-1 text-sm font-medium text-accent-strong">
<x-ui.badge tone="accent">
Draft
</span>
</x-ui.badge>
</div>

<div class="space-y-4 text-sm leading-7 text-muted">
Expand All @@ -96,10 +93,12 @@
features can slot in without rewriting the frame.
</p>
</div>
</div>
</x-ui.panel>

<section class="space-y-4 rounded-lg bg-panel px-5 py-5">
<h3 class="text-sm font-semibold uppercase tracking-wide text-muted">Next in this app</h3>
<x-ui.panel
title="Next in this app"
subtitle="The app frame stays stable while the product grows around it."
>

<ul class="space-y-3 text-sm text-muted">
<li class="flex items-center gap-3">
Expand All @@ -115,7 +114,7 @@
Propose a polished draft to the team
</li>
</ul>
</section>
</x-ui.panel>
</section>
</div>
</x-layouts.app-shell>
Loading
Loading