Initial commit: everythingbutwork MVP
Internes Project-Management-Tool für ToolCTRL — ergänzend zu Plane (Tickets) und Outline (Doku). Umfasst Puls-Übersicht, Tagesrhythmus (Lock-in + Reflexion), Bereichs-Detail-Views (Entwicklung/Vertrieb/Marketing), Pflicht-Minimum-Check und Blocker-Lifecycle gemäß Projektmanagement-Leitfaden v3.0. Stack: pnpm-Monorepo · Vite + React 18 + Tailwind · Fastify + tRPC v11 + Drizzle ORM · Postgres 16 · Authentik OIDC (Phase 2, Dev-Auto-Login aktiv). Planungs-Artefakte unter _bmad-output/planning-artifacts/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
4f33509a0f
131 files changed
+34339
No files matched your search
@@ -0,0 +1,39 @@
|
||||
import { clsx } from 'clsx';
|
||||
import { forwardRef, type ButtonHTMLAttributes } from 'react';
|
||||
|
||||
type Variant = 'primary' | 'secondary' | 'ghost' | 'destructive';
|
||||
type Size = 'sm' | 'md' | 'lg';
|
||||
|
||||
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: Variant;
|
||||
size?: Size;
|
||||
}
|
||||
|
||||
const base =
|
||||
'inline-flex items-center justify-center gap-2 font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed';
|
||||
|
||||
const variantStyles: Record<Variant, string> = {
|
||||
primary: 'bg-[var(--color-brand)] text-[var(--color-brand-fg)] hover:bg-black/85',
|
||||
secondary: 'border border-[var(--color-ink)] text-[var(--color-ink)] hover:bg-black/5',
|
||||
ghost: 'text-[var(--color-ink)] hover:bg-black/5',
|
||||
destructive: 'bg-[var(--color-ampel-red-fg)] text-white hover:bg-red-800',
|
||||
};
|
||||
|
||||
const sizeStyles: Record<Size, string> = {
|
||||
sm: 'h-7 px-3 text-xs rounded-[var(--radius-md)]',
|
||||
md: 'h-9 px-4 text-sm rounded-[var(--radius-md)]',
|
||||
lg: 'h-11 px-6 text-base rounded-[var(--radius-md)]',
|
||||
};
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
||||
{ variant = 'primary', size = 'md', className, ...rest },
|
||||
ref,
|
||||
) {
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
className={clsx(base, variantStyles[variant], sizeStyles[size], className)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { clsx } from 'clsx';
|
||||
import type { HTMLAttributes } from 'react';
|
||||
|
||||
function Root({ className, ...rest }: HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-[var(--color-surface)] border border-[var(--color-border)] rounded-[var(--radius-lg)] shadow-[var(--shadow-sm)]',
|
||||
className,
|
||||
)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function Header({ className, ...rest }: HTMLAttributes<HTMLDivElement>) {
|
||||
return <div className={clsx('px-6 pt-6 pb-3', className)} {...rest} />;
|
||||
}
|
||||
|
||||
function Body({ className, ...rest }: HTMLAttributes<HTMLDivElement>) {
|
||||
return <div className={clsx('px-6 py-3', className)} {...rest} />;
|
||||
}
|
||||
|
||||
function Footer({ className, ...rest }: HTMLAttributes<HTMLDivElement>) {
|
||||
return (
|
||||
<div
|
||||
className={clsx('px-6 pt-3 pb-6 border-t border-[var(--color-border)]', className)}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export const Card = { Root, Header, Body, Footer };
|
||||
@@ -0,0 +1,28 @@
|
||||
// macOS-Ctrl-Caret als Brand-Akzent. Skalierbar via currentColor.
|
||||
|
||||
export function KeyCaret({
|
||||
size = 16,
|
||||
className,
|
||||
'aria-hidden': ariaHidden = true,
|
||||
}: {
|
||||
size?: number;
|
||||
className?: string;
|
||||
'aria-hidden'?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 16 16"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.6}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={className}
|
||||
aria-hidden={ariaHidden}
|
||||
>
|
||||
<polyline points="3 10 8 5 13 10" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { clsx } from 'clsx';
|
||||
|
||||
export function SkeletonCard({ className, lines = 3 }: { className?: string; lines?: number }) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-[var(--color-surface)] border border-[var(--color-border)] rounded-[var(--radius-lg)] p-6 animate-pulse',
|
||||
className,
|
||||
)}
|
||||
aria-hidden
|
||||
>
|
||||
<div className="h-4 w-1/3 bg-[var(--color-border)] rounded" />
|
||||
<div className="mt-3 space-y-2">
|
||||
{Array.from({ length: lines }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="h-3 bg-[var(--color-border)] rounded"
|
||||
style={{ width: `${100 - i * 12}%` }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Brand-Emblem (das Tool-Ctrl-Tastenkappensymbol). Ersetzt den früher
|
||||
// verwendeten Caret als Marken-Anker im Logo-Lockup und in Streaks.
|
||||
|
||||
export function ToolCtrlLogo({
|
||||
size = 16,
|
||||
className,
|
||||
'aria-hidden': ariaHidden = true,
|
||||
alt = 'ToolCTRL',
|
||||
}: {
|
||||
size?: number;
|
||||
className?: string;
|
||||
'aria-hidden'?: boolean;
|
||||
alt?: string;
|
||||
}) {
|
||||
return (
|
||||
<img
|
||||
src="/toolctrl-emblem.svg"
|
||||
width={size}
|
||||
height={(size * 678) / 713}
|
||||
className={className}
|
||||
aria-hidden={ariaHidden}
|
||||
alt={ariaHidden ? '' : alt}
|
||||
draggable={false}
|
||||
style={{ display: 'inline-block' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user