Files
teOS/.claude/agent-memory/frontend-specialist/component-patterns.md
Flexomatic81 fe305f6fc8 feat: complete tOS project with HR, LEAN, Dashboard and Integrations modules
Full enterprise web operating system including:
- Next.js 14 frontend with App Router, i18n (DE/EN), shadcn/ui
- NestJS 10 backend with Prisma, JWT auth, Swagger docs
- Keycloak 24 SSO with role-based access control
- HR module (employees, time tracking, absences, org chart)
- LEAN module (3S planning, morning meeting SQCDM, skill matrix)
- Integrations module (PlentyONE, Zulip, Todoist, FreeScout, Nextcloud, ecoDMS, GembaDocs)
- Dashboard with customizable drag & drop widget grid
- Docker Compose infrastructure (PostgreSQL 16, Redis 7, Keycloak 24)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 19:37:55 +01:00

4.8 KiB

Component Patterns - tOS Frontend

Layout Component Pattern

// src/components/layout/sidebar.tsx
'use client';

import { usePathname } from 'next/navigation';
import { motion } from 'framer-motion';
import { useSidebarStore } from '@/stores/sidebar-store';

export function Sidebar({ locale }: { locale: string }) {
  const { isExpanded, toggleSidebar } = useSidebarStore();
  const pathname = usePathname();

  return (
    <motion.aside
      initial={false}
      animate={{ width: isExpanded ? 240 : 64 }}
      transition={{ duration: 0.2, ease: 'easeInOut' }}
      className="fixed left-0 top-0 z-40 h-screen border-r bg-sidebar"
    >
      {/* Content */}
    </motion.aside>
  );
}

Page with Metadata Pattern

// page.tsx (Server Component)
import { Metadata } from 'next';
import { getTranslations } from 'next-intl/server';
import { ContentComponent } from './content-component';

export async function generateMetadata(): Promise<Metadata> {
  const t = await getTranslations('namespace');
  return { title: t('title') };
}

export default function Page() {
  return <ContentComponent />;
}

// content-component.tsx (Client Component)
'use client';
import { useTranslations } from 'next-intl';

export function ContentComponent() {
  const t = useTranslations('namespace');
  return <div>{t('key')}</div>;
}

Zustand Store Pattern

// src/stores/sidebar-store.ts
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

interface SidebarState {
  isExpanded: boolean;
  toggleSidebar: () => void;
}

export const useSidebarStore = create<SidebarState>()(
  persist(
    (set) => ({
      isExpanded: true,
      toggleSidebar: () => set((state) => ({ isExpanded: !state.isExpanded })),
    }),
    {
      name: 'tos-sidebar-state',
      partialize: (state) => ({ isExpanded: state.isExpanded }),
    }
  )
);

Animation Pattern with Framer Motion

import { motion } from 'framer-motion';

// Staggered list animation
<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  transition={{ staggerChildren: 0.1 }}
>
  {items.map((item, index) => (
    <motion.div
      key={item.id}
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ delay: index * 0.1, duration: 0.3, ease: 'easeOut' }}
    >
      {item.content}
    </motion.div>
  ))}
</motion.div>

shadcn/ui Component with Variants

// src/components/ui/button.tsx
import { cva, type VariantProps } from 'class-variance-authority';

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors',
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-destructive-foreground',
        outline: 'border border-input bg-background hover:bg-accent',
        ghost: 'hover:bg-accent hover:text-accent-foreground',
      },
      size: {
        default: 'h-9 px-4 py-2',
        sm: 'h-8 px-3 text-xs',
        lg: 'h-10 px-8',
        icon: 'h-9 w-9',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
);

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean;
}

Provider Composition Pattern

// src/components/providers/index.tsx
'use client';

export function Providers({ children }: { children: ReactNode }) {
  return (
    <SessionProvider>
      <QueryProvider>
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </QueryProvider>
    </SessionProvider>
  );
}

i18n Usage Pattern

// In components
import { useTranslations } from 'next-intl';

export function Component() {
  const t = useTranslations('namespace');
  return <span>{t('key', { param: 'value' })}</span>;
}

// In server components
import { getTranslations } from 'next-intl/server';

export async function ServerComponent() {
  const t = await getTranslations('namespace');
  return <span>{t('key')}</span>;
}

Protected Route Layout Pattern

// src/app/[locale]/(auth)/layout.tsx
'use client';

export default function AuthLayout({ children, params: { locale } }) {
  const { isExpanded } = useSidebarStore();

  return (
    <div className="min-h-screen bg-background">
      <div className="hidden lg:block">
        <Sidebar locale={locale} />
      </div>
      <MobileSidebar locale={locale} />

      <div className={cn(
        'flex min-h-screen flex-col transition-[margin-left] duration-200',
        'ml-0',
        isExpanded ? 'lg:ml-[240px]' : 'lg:ml-[64px]'
      )}>
        <Header locale={locale} />
        <main className="flex-1 p-4 md:p-6 lg:p-8">
          <PageTransition>{children}</PageTransition>
        </main>
      </div>
    </div>
  );
}