diff --git a/apps/web/src/app/(auth)/reset-password/[token]/page.tsx b/apps/web/src/app/(auth)/reset-password/[token]/page.tsx index 6f5907e..7d09ecb 100644 --- a/apps/web/src/app/(auth)/reset-password/[token]/page.tsx +++ b/apps/web/src/app/(auth)/reset-password/[token]/page.tsx @@ -83,7 +83,7 @@ export default function ResetPasswordTokenPage() { {/* Heading */}
-

+

{t('resetPassword.newPasswordTitle')}

@@ -99,7 +99,7 @@ export default function ResetPasswordTokenPage() {

{t('resetPassword.backToLogin')} @@ -164,7 +164,7 @@ export default function ResetPasswordTokenPage() { diff --git a/apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx b/apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx index eefe97f..bdd8799 100644 --- a/apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx +++ b/apps/web/src/app/(portal)/admin/groups/components/GroupFormModal.tsx @@ -77,7 +77,7 @@ export function GroupFormModal({ group, onClose, onSaved }: GroupFormModalProps) return (
-
+

{group ? t('edit') : t('create')}

@@ -101,7 +101,7 @@ export function GroupFormModal({ group, onClose, onSaved }: GroupFormModalProps) {!group && (

{t('createLdapHint')}{' '} - + {t('goToLdap')}

@@ -139,14 +139,14 @@ export function GroupFormModal({ group, onClose, onSaved }: GroupFormModalProps) diff --git a/apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx b/apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx index 84912fa..1579279 100644 --- a/apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx +++ b/apps/web/src/app/(portal)/admin/groups/components/GroupMembersModal.tsx @@ -158,7 +158,7 @@ export function GroupMembersModal({ group, onClose, onChanged }: GroupMembersMod return (
-
+

{t('members.title')} — {group.name}

@@ -252,7 +252,7 @@ export function GroupMembersModal({ group, onClose, onChanged }: GroupMembersMod @@ -260,7 +260,7 @@ export function GroupMembersModal({ group, onClose, onChanged }: GroupMembersMod type="button" onClick={handleAdd} disabled={adding || selectedUserIds.length === 0} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {adding ? tCommon('loading') : `${t('members.addTitle')} (${selectedUserIds.length})`} diff --git a/apps/web/src/app/(portal)/admin/groups/page.tsx b/apps/web/src/app/(portal)/admin/groups/page.tsx index f85f235..0845dbc 100644 --- a/apps/web/src/app/(portal)/admin/groups/page.tsx +++ b/apps/web/src/app/(portal)/admin/groups/page.tsx @@ -124,11 +124,11 @@ export default function AdminGroupsPage() { return (
-

{t('title')}

+

{t('title')}

@@ -149,7 +149,7 @@ export default function AdminGroupsPage() { diff --git a/apps/web/src/app/(portal)/admin/layout.tsx b/apps/web/src/app/(portal)/admin/layout.tsx index 7d72dce..b0657ce 100644 --- a/apps/web/src/app/(portal)/admin/layout.tsx +++ b/apps/web/src/app/(portal)/admin/layout.tsx @@ -12,9 +12,9 @@ export default function AdminLayout({ const t = useTranslations('settings'); return ( -
+
-
+
-

{t('title')}

+

{t('title')}

{/* Section 1: Connection Settings */}
@@ -646,7 +646,7 @@ export default function AdminLdapPage() { @@ -654,7 +654,7 @@ export default function AdminLdapPage() { type="button" onClick={handleTestConnection} disabled={!config && !formData.serverUrl} - className="rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50" + className="btn btn-secondary" > {t('testConnection')} @@ -816,7 +816,7 @@ export default function AdminLdapPage() { type="button" onClick={handleDiscoverGroups} disabled={discovering} - className="rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50" + className="btn btn-secondary" > {discovering ? tCommon('loading') : t('groupFilter.discover')} @@ -919,7 +919,7 @@ export default function AdminLdapPage() { type="button" onClick={handleSaveGroupFilter} disabled={savingFilter} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {savingFilter ? tCommon('loading') : t('groupFilter.save')} @@ -941,7 +941,7 @@ export default function AdminLdapPage() { type="button" onClick={handleDiscoverGroupsToImport} disabled={discoveringGroupImport} - className="rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50" + className="btn btn-secondary" > {discoveringGroupImport ? tCommon('loading') @@ -1015,7 +1015,7 @@ export default function AdminLdapPage() { type="button" onClick={handleImportGroups} disabled={importingGroups || selectedImportDns.length === 0} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {importingGroups ? tCommon('loading') @@ -1142,7 +1142,7 @@ export default function AdminLdapPage() { type="button" onClick={() => handleImportUsers(selectedUserDns)} disabled={importingUsers || selectedUserDns.length === 0} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {importingUsers ? tCommon('loading') @@ -1234,7 +1234,7 @@ export default function AdminLdapPage() { type="button" onClick={handleSaveExcludeList} disabled={savingExclude} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {savingExclude ? tCommon('loading') : t('userExclude.save')} @@ -1297,7 +1297,7 @@ export default function AdminLdapPage() { type="button" onClick={handleSave} disabled={saving} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {t('save')} @@ -1319,7 +1319,7 @@ export default function AdminLdapPage() { type="button" onClick={handleSync} disabled={syncing} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:opacity-50" + className="btn btn-primary" > {syncing ? t('sync.syncing') : t('sync.trigger')} diff --git a/apps/web/src/app/(portal)/admin/modules/components/ActivateModuleDialog.tsx b/apps/web/src/app/(portal)/admin/modules/components/ActivateModuleDialog.tsx index 1aad7df..5dde13f 100644 --- a/apps/web/src/app/(portal)/admin/modules/components/ActivateModuleDialog.tsx +++ b/apps/web/src/app/(portal)/admin/modules/components/ActivateModuleDialog.tsx @@ -142,7 +142,7 @@ export function ActivateModuleDialog({ role="dialog" aria-modal="true" > -
+

{t('title', { module: moduleName })}

@@ -157,7 +157,7 @@ export function ActivateModuleDialog({ type="button" onClick={onCancel} disabled={isSubmitting} - className="rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50" + className="btn btn-secondary" > {t('cancel')} @@ -165,7 +165,7 @@ export function ActivateModuleDialog({ type="button" onClick={handleConfigureLater} disabled={isSubmitting} - className="rounded-md border border-border px-4 py-2 text-sm font-medium text-foreground hover:bg-muted transition-colors disabled:opacity-50" + className="btn btn-secondary" > {t('configureLater')} @@ -173,7 +173,7 @@ export function ActivateModuleDialog({ type="button" onClick={handleGrantNow} disabled={grantNowDisabled} - className="rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:opacity-90 transition-opacity disabled:cursor-not-allowed disabled:opacity-50" + className="btn btn-primary" > {t('grantNow')} diff --git a/apps/web/src/app/(portal)/admin/modules/grants/page.tsx b/apps/web/src/app/(portal)/admin/modules/grants/page.tsx index 78edfe0..30b147e 100644 --- a/apps/web/src/app/(portal)/admin/modules/grants/page.tsx +++ b/apps/web/src/app/(portal)/admin/modules/grants/page.tsx @@ -189,7 +189,7 @@ export default function AdminModuleGrantsPage() { return (
-

{t('title')}

+

{t('title')}

{error && ( @@ -205,7 +205,7 @@ export default function AdminModuleGrantsPage() {

{t('emptyModules')}

{t('emptyModulesLink')} diff --git a/apps/web/src/app/(portal)/admin/modules/page.tsx b/apps/web/src/app/(portal)/admin/modules/page.tsx index 5cd8e26..9701a67 100644 --- a/apps/web/src/app/(portal)/admin/modules/page.tsx +++ b/apps/web/src/app/(portal)/admin/modules/page.tsx @@ -134,12 +134,12 @@ export default function AdminModulesPage() {
-

{t('title')}

+

{t('title')}

{t('description')}

{t('grantsLink')} diff --git a/apps/web/src/app/(portal)/admin/tenants/page.tsx b/apps/web/src/app/(portal)/admin/tenants/page.tsx index 0c76f84..d22d4e3 100644 --- a/apps/web/src/app/(portal)/admin/tenants/page.tsx +++ b/apps/web/src/app/(portal)/admin/tenants/page.tsx @@ -146,11 +146,11 @@ export default function AdminTenantsPage() {
{/* Page header */}
-

{t('title')}

+

{t('title')}

@@ -244,7 +244,7 @@ export default function AdminTenantsPage() { {/* Create/Edit modal */} {showForm && (
-
+

{editingTenant ? t('edit') : t('create')}

@@ -287,13 +287,13 @@ export default function AdminTenantsPage() { @@ -306,7 +306,7 @@ export default function AdminTenantsPage() { {/* Delete confirmation modal */} {deleteConfirm && (
-
+

{t('deleteConfirm')}

@@ -314,7 +314,7 @@ export default function AdminTenantsPage() { diff --git a/apps/web/src/app/(portal)/admin/users/components/UserAccessModal.tsx b/apps/web/src/app/(portal)/admin/users/components/UserAccessModal.tsx index c3be598..ad2257e 100644 --- a/apps/web/src/app/(portal)/admin/users/components/UserAccessModal.tsx +++ b/apps/web/src/app/(portal)/admin/users/components/UserAccessModal.tsx @@ -128,7 +128,7 @@ export function UserAccessModal({ userId, username, onClose }: UserAccessModalPr role="dialog" aria-modal="true" > -
+

{t('modalTitle', { username })}

@@ -349,7 +349,7 @@ export default function AdminUsersPage() { {/* Create/Edit modal */} {showForm && (
-
+

{editingUser ? t('edit') : t('create')}

@@ -455,13 +455,13 @@ export default function AdminUsersPage() { @@ -474,7 +474,7 @@ export default function AdminUsersPage() { {/* Delete confirmation modal */} {deleteConfirm && (
-
+

{t('deleteConfirm')}

@@ -490,7 +490,7 @@ export default function AdminUsersPage() { diff --git a/apps/web/src/app/(portal)/change-password/page.tsx b/apps/web/src/app/(portal)/change-password/page.tsx index 97ba2a8..f669a6e 100644 --- a/apps/web/src/app/(portal)/change-password/page.tsx +++ b/apps/web/src/app/(portal)/change-password/page.tsx @@ -47,7 +47,7 @@ export default function ChangePasswordPage() { return (
-

+

{t('changePassword.title')}

@@ -129,7 +129,7 @@ export default function ChangePasswordPage() { diff --git a/apps/web/src/app/(portal)/marketplace/components/CategoryFilter.tsx b/apps/web/src/app/(portal)/marketplace/components/CategoryFilter.tsx index ea7b11a..632c59f 100644 --- a/apps/web/src/app/(portal)/marketplace/components/CategoryFilter.tsx +++ b/apps/web/src/app/(portal)/marketplace/components/CategoryFilter.tsx @@ -1,6 +1,7 @@ 'use client'; import { useTranslations } from 'next-intl'; +import { useCategoryLabel } from '@/lib/use-category-label'; interface CategoryFilterProps { categories: string[]; @@ -10,17 +11,23 @@ interface CategoryFilterProps { export function CategoryFilter({ categories, value, onChange }: CategoryFilterProps) { const t = useTranslations('marketplace'); + const categoryLabel = useCategoryLabel(); + // Dezente Pillen (Fluent „subtle“): gewaehlt = dunkle Fuellung wie bei + // GitHub-Filtern, nicht die gelbe Akzentflaeche. + const chip = (selected: boolean) => + `inline-flex h-7 items-center rounded-full border px-3 text-xs font-medium whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${ + selected + ? 'border-foreground bg-foreground text-background' + : 'border-border bg-card text-foreground hover:bg-muted' + }`; return ( -
+
@@ -29,13 +36,10 @@ export function CategoryFilter({ categories, value, onChange }: CategoryFilterPr key={cat} type="button" onClick={() => onChange(cat)} - className={`rounded-full px-3 py-1 text-xs font-medium whitespace-nowrap transition-colors ${ - value === cat - ? 'bg-primary text-primary-foreground' - : 'bg-muted text-foreground hover:bg-muted/80' - }`} + aria-pressed={value === cat} + className={chip(value === cat)} > - {cat} + {categoryLabel(cat)} ))}
diff --git a/apps/web/src/app/(portal)/marketplace/components/MarketplaceCard.tsx b/apps/web/src/app/(portal)/marketplace/components/MarketplaceCard.tsx index 008bd68..4c01457 100644 --- a/apps/web/src/app/(portal)/marketplace/components/MarketplaceCard.tsx +++ b/apps/web/src/app/(portal)/marketplace/components/MarketplaceCard.tsx @@ -1,6 +1,8 @@ 'use client'; import { useTranslations } from 'next-intl'; +import { ModuleTile } from '@/components/modules/module-tile'; +import { useCategoryLabel } from '@/lib/use-category-label'; /** * Props for the MarketplaceCard component. @@ -25,53 +27,6 @@ export interface MarketplaceCardProps { onLockedClick: () => void; } -/** - * Default icon mapping for known module icons. - * Renders inline SVG to avoid external icon library dependency. - */ -function ModuleIcon({ icon }: { icon?: string }) { - if (icon === 'Globe') { - return ( - - ); - } - - // Default puzzle-piece icon for generic modules - return ( - - ); -} - /** * Marketplace card showing a module with activation controls. * @@ -84,7 +39,6 @@ export function MarketplaceCard({ name, slug, description, - icon, category, isActive, hasAccess, @@ -95,6 +49,7 @@ export function MarketplaceCard({ onLockedClick, }: MarketplaceCardProps) { const t = useTranslations('marketplace'); + const categoryLabel = useCategoryLabel(); const locale = (typeof window !== 'undefined' && document.documentElement.lang) || 'de'; const localizedDescription = description[locale] || description.en || description.de || ''; @@ -114,10 +69,9 @@ export function MarketplaceCard({ return (
{/* Deckende Schaltflaeche: traegt den Kartenklick, damit die verschachtelte Aktivieren-Schaltflaeche im Fuss kein -
- )} + )} +
); } diff --git a/apps/web/src/app/(portal)/marketplace/components/MarketplaceSearch.tsx b/apps/web/src/app/(portal)/marketplace/components/MarketplaceSearch.tsx index 6e69c08..64be631 100644 --- a/apps/web/src/app/(portal)/marketplace/components/MarketplaceSearch.tsx +++ b/apps/web/src/app/(portal)/marketplace/components/MarketplaceSearch.tsx @@ -23,13 +23,30 @@ export function MarketplaceSearch({ onChange }: MarketplaceSearchProps) { }, [value, onChange]); return ( -
+
+ setValue(e.target.value)} placeholder={t('searchPlaceholder')} - className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" + aria-label={t('searchPlaceholder')} + className="flex h-8 w-full rounded-md border border-input bg-card pl-8 pr-8 text-sm placeholder:text-muted-foreground" /> {value && ( - ))} + {tabs.map((tab) => { + const selected = value === tab.key; + return ( + + ); + })}
); } diff --git a/apps/web/src/app/(portal)/marketplace/components/TenantContextSelector.tsx b/apps/web/src/app/(portal)/marketplace/components/TenantContextSelector.tsx index 57062a1..30a7e9d 100644 --- a/apps/web/src/app/(portal)/marketplace/components/TenantContextSelector.tsx +++ b/apps/web/src/app/(portal)/marketplace/components/TenantContextSelector.tsx @@ -37,8 +37,8 @@ export function TenantContextSelector() { if (!isSuperAdmin) return null; return ( -
-