Feature pack: Media, Gamification, Templates, Time Tracking, Kanban, AI Briefing, Webhooks, Icon UI

API features (separate files in /api/src/features/):
- media-input: upload text/audio/photo/video, transcription
- gamification: points, streaks, badges, leaderboard
- templates: predefined task sets (sprint, study, moving)
- time-tracking: start/stop timer, task/user reports
- kanban: board view, drag-and-drop move
- ai-briefing: daily AI summary with tasks/goals/reviews
- webhooks-outgoing: notify external systems on events

UI components (separate files in /components/features/):
- IconButton: icon-only buttons with tooltip
- CompactHeader, PageActionBar, InlineEditField
- TaskDetailActions, GoalActionButtons, CollabActionButtons
- DeleteIconButton, CollabBackButton

All features modular — registry.js enables/disables each one.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 01:13:09 +00:00
parent f9c4ec631c
commit 8cf14dcf59
14 changed files with 875 additions and 200 deletions

View File

@@ -0,0 +1,42 @@
'use client';
import { ReactNode } from 'react';
import IconButton from './IconButton';
interface Props {
title: string;
showAdd?: boolean;
onToggleAdd?: () => void;
addOpen?: boolean;
t: (key: string) => string;
children?: ReactNode;
}
export default function PageActionBar({ title, showAdd, onToggleAdd, addOpen, t, children }: Props) {
return (
<div className="flex items-center justify-between gap-2">
<h1 className="text-xl font-bold dark:text-white truncate">{title}</h1>
<div className="flex items-center gap-2 flex-shrink-0">
{children}
{showAdd && onToggleAdd && (
<IconButton
icon={
addOpen ? (
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
) : (
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4v16m8-8H4" />
</svg>
)
}
label={addOpen ? t("tasks.form.cancel") : t("tasks.add")}
onClick={onToggleAdd}
variant={addOpen ? "danger" : "primary"}
size="md"
/>
)}
</div>
</div>
);
}