144 lines
4.7 KiB
TypeScript
144 lines
4.7 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import type { KnowledgeTag } from "@mosaic/shared";
|
|
import { EntryStatus, Visibility } from "@mosaic/shared";
|
|
|
|
interface EntryMetadataProps {
|
|
title: string;
|
|
status: EntryStatus;
|
|
visibility: Visibility;
|
|
selectedTags: string[];
|
|
availableTags: KnowledgeTag[];
|
|
onTitleChange: (title: string) => void;
|
|
onStatusChange: (status: EntryStatus) => void;
|
|
onVisibilityChange: (visibility: Visibility) => void;
|
|
onTagsChange: (tags: string[]) => void;
|
|
}
|
|
|
|
/**
|
|
* EntryMetadata - Title, tags, status, and visibility controls
|
|
*/
|
|
export function EntryMetadata({
|
|
title,
|
|
status,
|
|
visibility,
|
|
selectedTags,
|
|
availableTags,
|
|
onTitleChange,
|
|
onStatusChange,
|
|
onVisibilityChange,
|
|
onTagsChange,
|
|
}: EntryMetadataProps) {
|
|
const handleTagToggle = (tagId: string): void => {
|
|
if (selectedTags.includes(tagId)) {
|
|
onTagsChange(selectedTags.filter((id) => id !== tagId));
|
|
} else {
|
|
onTagsChange([...selectedTags, tagId]);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="entry-metadata space-y-4">
|
|
{/* Title */}
|
|
<div>
|
|
<label
|
|
htmlFor="entry-title"
|
|
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
|
>
|
|
Title
|
|
</label>
|
|
<input
|
|
id="entry-title"
|
|
type="text"
|
|
value={title}
|
|
onChange={(e) => onTitleChange(e.target.value)}
|
|
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
placeholder="Entry title..."
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
{/* Status and Visibility Row */}
|
|
<div className="grid grid-cols-2 gap-4">
|
|
{/* Status */}
|
|
<div>
|
|
<label
|
|
htmlFor="entry-status"
|
|
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
|
>
|
|
Status
|
|
</label>
|
|
<select
|
|
id="entry-status"
|
|
value={status}
|
|
onChange={(e) => onStatusChange(e.target.value as EntryStatus)}
|
|
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
>
|
|
<option value={EntryStatus.DRAFT}>Draft</option>
|
|
<option value={EntryStatus.PUBLISHED}>Published</option>
|
|
<option value={EntryStatus.ARCHIVED}>Archived</option>
|
|
</select>
|
|
</div>
|
|
|
|
{/* Visibility */}
|
|
<div>
|
|
<label
|
|
htmlFor="entry-visibility"
|
|
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
|
>
|
|
Visibility
|
|
</label>
|
|
<select
|
|
id="entry-visibility"
|
|
value={visibility}
|
|
onChange={(e) => onVisibilityChange(e.target.value as Visibility)}
|
|
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
|
>
|
|
<option value={Visibility.PRIVATE}>Private</option>
|
|
<option value={Visibility.WORKSPACE}>Workspace</option>
|
|
<option value={Visibility.PUBLIC}>Public</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tags */}
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Tags
|
|
</label>
|
|
<div className="flex flex-wrap gap-2">
|
|
{availableTags.length > 0 ? (
|
|
availableTags.map((tag) => {
|
|
const isSelected = selectedTags.includes(tag.id);
|
|
return (
|
|
<button
|
|
key={tag.id}
|
|
type="button"
|
|
onClick={() => handleTagToggle(tag.id)}
|
|
className={`px-3 py-1 rounded-full text-sm font-medium transition-colors ${
|
|
isSelected
|
|
? "bg-blue-600 text-white"
|
|
: "bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 hover:bg-gray-300 dark:hover:bg-gray-600"
|
|
}`}
|
|
style={
|
|
isSelected && tag.color
|
|
? { backgroundColor: tag.color }
|
|
: undefined
|
|
}
|
|
>
|
|
{tag.name}
|
|
</button>
|
|
);
|
|
})
|
|
) : (
|
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
|
No tags available. Create tags first.
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|