Dev #5
No files matched your search
@@ -1034,9 +1034,11 @@ export const App: React.FC = () => {
|
|||||||
<div className="flex items-center justify-between pb-3 border-b border-border mb-3">
|
<div className="flex items-center justify-between pb-3 border-b border-border mb-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className="w-6 h-6 rounded-btn bg-accent/15 text-accent flex items-center justify-center">
|
<div className="w-6 h-6 rounded-btn bg-accent/15 text-accent flex items-center justify-center">
|
||||||
<Plus className="w-4 h-4" />
|
{activeTab === 'triage' ? <Layers className="w-4 h-4" /> : <Plus className="w-4 h-4" />}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-sm font-semibold text-main">Schnell erfassen</h3>
|
<h3 className="text-sm font-semibold text-main">
|
||||||
|
{activeTab === 'triage' ? 'Quick Dump erfassen' : 'Schnell erfassen'}
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -1052,6 +1054,8 @@ export const App: React.FC = () => {
|
|||||||
<InstantCaptureBar
|
<InstantCaptureBar
|
||||||
inlineOptions={true}
|
inlineOptions={true}
|
||||||
defaultShowOptions={true}
|
defaultShowOptions={true}
|
||||||
|
hideTargetPicker={activeTab === 'triage'}
|
||||||
|
fixedTarget={activeTab === 'triage' ? 'inbox' : undefined}
|
||||||
onCaptured={(thought, target) => {
|
onCaptured={(thought, target) => {
|
||||||
handleCaptured(thought, target);
|
handleCaptured(thought, target);
|
||||||
setShowMobileCapture(false);
|
setShowMobileCapture(false);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import {
|
|||||||
FileText,
|
FileText,
|
||||||
Layers,
|
Layers,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
|
AlertTriangle,
|
||||||
|
Flame,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { PriorityLevel, SharedList, Thought } from '../../lib/types';
|
import { PriorityLevel, SharedList, Thought } from '../../lib/types';
|
||||||
import { api, triggerHaptic } from '../../lib/api';
|
import { api, triggerHaptic } from '../../lib/api';
|
||||||
@@ -23,6 +25,8 @@ interface InstantCaptureBarProps {
|
|||||||
autoFocusTrigger?: number;
|
autoFocusTrigger?: number;
|
||||||
inlineOptions?: boolean;
|
inlineOptions?: boolean;
|
||||||
defaultShowOptions?: boolean;
|
defaultShowOptions?: boolean;
|
||||||
|
hideTargetPicker?: boolean;
|
||||||
|
fixedTarget?: CaptureTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
||||||
@@ -31,13 +35,15 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
autoFocusTrigger = 0,
|
autoFocusTrigger = 0,
|
||||||
inlineOptions = false,
|
inlineOptions = false,
|
||||||
defaultShowOptions = false,
|
defaultShowOptions = false,
|
||||||
|
hideTargetPicker = false,
|
||||||
|
fixedTarget,
|
||||||
}) => {
|
}) => {
|
||||||
const [content, setContent] = useState('');
|
const [content, setContent] = useState('');
|
||||||
const [priority, setPriority] = useState<PriorityLevel>('normal');
|
const [priority, setPriority] = useState<PriorityLevel>('normal');
|
||||||
const [dueDate, setDueDate] = useState('');
|
const [dueDate, setDueDate] = useState('');
|
||||||
const [target, setTarget] = useState<CaptureTarget>('inbox');
|
const [target, setTarget] = useState<CaptureTarget>(fixedTarget || 'inbox');
|
||||||
const [targetListId, setTargetListId] = useState<string>('');
|
const [targetListId, setTargetListId] = useState<string>('');
|
||||||
const [showOptions, setShowOptions] = useState(defaultShowOptions);
|
const [showOptions, setShowOptions] = useState(defaultShowOptions || hideTargetPicker);
|
||||||
const [isListening, setIsListening] = useState(false);
|
const [isListening, setIsListening] = useState(false);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [justSavedLabel, setJustSavedLabel] = useState<string | null>(null);
|
const [justSavedLabel, setJustSavedLabel] = useState<string | null>(null);
|
||||||
@@ -169,7 +175,7 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
const trimmed = content.trim();
|
const trimmed = content.trim();
|
||||||
if (!trimmed || isSubmitting) return;
|
if (!trimmed || isSubmitting) return;
|
||||||
|
|
||||||
const effectiveTarget = overrideTarget || target;
|
const effectiveTarget = fixedTarget || overrideTarget || target;
|
||||||
const effectiveListId =
|
const effectiveListId =
|
||||||
overrideListId || targetListId || (lists.length > 0 ? lists[0].id : '');
|
overrideListId || targetListId || (lists.length > 0 ? lists[0].id : '');
|
||||||
const capturedPriority = priority;
|
const capturedPriority = priority;
|
||||||
@@ -181,8 +187,8 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
setIsMultiline(false);
|
setIsMultiline(false);
|
||||||
setPriority('normal');
|
setPriority('normal');
|
||||||
setDueDate('');
|
setDueDate('');
|
||||||
setTarget('inbox');
|
setTarget(fixedTarget || 'inbox');
|
||||||
setShowOptions(false);
|
setShowOptions(defaultShowOptions || hideTargetPicker);
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
triggerHaptic(15);
|
triggerHaptic(15);
|
||||||
if (inputRef.current) {
|
if (inputRef.current) {
|
||||||
@@ -196,7 +202,7 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
? 'Auf Liste!'
|
? 'Auf Liste!'
|
||||||
: effectiveTarget === 'document'
|
: effectiveTarget === 'document'
|
||||||
? 'Als Notiz!'
|
? 'Als Notiz!'
|
||||||
: 'Im Dump!';
|
: 'In Triage!';
|
||||||
setJustSavedLabel(savedMsg);
|
setJustSavedLabel(savedMsg);
|
||||||
setTimeout(() => setJustSavedLabel(null), 1600);
|
setTimeout(() => setJustSavedLabel(null), 1600);
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
@@ -275,6 +281,8 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
placeholder={
|
placeholder={
|
||||||
isListening
|
isListening
|
||||||
? 'Ich höre zu…'
|
? 'Ich höre zu…'
|
||||||
|
: hideTargetPicker || fixedTarget === 'inbox'
|
||||||
|
? 'Quick Dump erfassen… (Enter zum Speichern)'
|
||||||
: target === 'task'
|
: target === 'task'
|
||||||
? 'Neue Aufgabe direkt anlegen… (Enter / Shift+Enter für Mehrzeiler)'
|
? 'Neue Aufgabe direkt anlegen… (Enter / Shift+Enter für Mehrzeiler)'
|
||||||
: target === 'list_item'
|
: target === 'list_item'
|
||||||
@@ -293,7 +301,8 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
isMultiline ? 'self-end mb-0.5' : ''
|
isMultiline ? 'self-end mb-0.5' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{/* Target & Options Toggle Pill */}
|
{/* Target & Options Toggle Pill (Hidden when target picker is disabled) */}
|
||||||
|
{!hideTargetPicker && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowOptions((prev) => !prev)}
|
onClick={() => setShowOptions((prev) => !prev)}
|
||||||
@@ -319,6 +328,7 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
{dueDate && <span className="hidden lg:inline text-[10px] opacity-80">• {dueDate.slice(5)}</span>}
|
{dueDate && <span className="hidden lg:inline text-[10px] opacity-80">• {dueDate.slice(5)}</span>}
|
||||||
<ChevronDown className={`w-3 h-3 opacity-70 transition-transform ${showOptions ? 'rotate-180' : ''}`} />
|
<ChevronDown className={`w-3 h-3 opacity-70 transition-transform ${showOptions ? 'rotate-180' : ''}`} />
|
||||||
</button>
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Voice Dictation Button */}
|
{/* Voice Dictation Button */}
|
||||||
<button
|
<button
|
||||||
@@ -347,13 +357,15 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
{justSavedLabel ? (
|
{justSavedLabel ? (
|
||||||
<>
|
<>
|
||||||
<Check className="w-3 h-3" />
|
<Check className="w-3 h-3" />
|
||||||
<span className="hidden sm:inline">{justSavedLabel}</span>
|
<span className="inline">{justSavedLabel}</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<ArrowUp className="w-3 h-3" />
|
<ArrowUp className="w-3 h-3" />
|
||||||
<span className="hidden sm:inline">
|
<span className="inline">
|
||||||
{target === 'task'
|
{hideTargetPicker || (fixedTarget || target) === 'inbox'
|
||||||
|
? 'Quick Dump'
|
||||||
|
: target === 'task'
|
||||||
? 'Als Aufgabe'
|
? 'Als Aufgabe'
|
||||||
: target === 'list_item'
|
: target === 'list_item'
|
||||||
? 'Auf Liste'
|
? 'Auf Liste'
|
||||||
@@ -376,7 +388,9 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
: 'absolute top-full left-0 right-0 mt-1.5 z-50 p-3 panel-surface shadow-panel space-y-3 text-xs'
|
: 'absolute top-full left-0 right-0 mt-1.5 z-50 p-3 panel-surface shadow-panel space-y-3 text-xs'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* Row 1: Where should this entry go? */}
|
{/* Row 1: Where should this entry go? (Omitted when hideTargetPicker is true) */}
|
||||||
|
{!hideTargetPicker && (
|
||||||
|
<>
|
||||||
<div>
|
<div>
|
||||||
<div className="flex items-center justify-between mb-1.5">
|
<div className="flex items-center justify-between mb-1.5">
|
||||||
<span className="text-[11px] font-semibold uppercase tracking-wider text-muted">
|
<span className="text-[11px] font-semibold uppercase tracking-wider text-muted">
|
||||||
@@ -499,39 +513,46 @@ export const InstantCaptureBar: React.FC<InstantCaptureBarProps> = ({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Row 2: Priority & Due Date */}
|
{/* Row 2: Priority & Due Date */}
|
||||||
<div className="pt-2 border-t border-border flex flex-wrap items-center justify-between gap-2">
|
<div className={`${!hideTargetPicker ? 'pt-2 border-t border-border' : ''} flex flex-wrap items-center justify-between gap-2.5`}>
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
<span className="text-muted mr-1">Priorität:</span>
|
<span className="text-muted text-[11px] font-semibold mr-1">Priorität:</span>
|
||||||
{(['low', 'normal', 'high', 'urgent'] as PriorityLevel[]).map((p) => {
|
{(['low', 'normal', 'high', 'urgent'] as PriorityLevel[]).map((p) => {
|
||||||
const labels: Record<PriorityLevel, string> = {
|
const config: Record<PriorityLevel, { label: string; icon?: React.ReactNode; activeClass: string }> = {
|
||||||
low: 'Niedrig',
|
low: { label: 'Niedrig', activeClass: 'bg-canvas border-strong text-main font-semibold shadow-xs' },
|
||||||
normal: 'Normal',
|
normal: { label: 'Normal', activeClass: 'bg-accent/15 border-accent text-accent font-semibold shadow-xs' },
|
||||||
high: 'Hoch',
|
high: { label: 'Wichtig', icon: <AlertTriangle className="w-3 h-3 text-status-warn" />, activeClass: 'bg-status-warn/15 border-status-warn text-status-warn font-semibold shadow-xs' },
|
||||||
urgent: 'Dringend',
|
urgent: { label: 'Dringend', icon: <Flame className="w-3 h-3 text-status-err" />, activeClass: 'bg-status-err/15 border-status-err text-status-err font-semibold shadow-xs' },
|
||||||
};
|
};
|
||||||
const active = priority === p;
|
const active = priority === p;
|
||||||
|
const item = config[p];
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={p}
|
key={p}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setPriority(p)}
|
onClick={() => {
|
||||||
className={`min-h-[30px] px-2.5 py-1 border rounded-btn transition-colors text-xs cursor-pointer ${
|
triggerHaptic(10);
|
||||||
|
setPriority(p);
|
||||||
|
}}
|
||||||
|
className={`min-h-[30px] px-2.5 py-1 border rounded-btn text-xs flex items-center gap-1 transition-colors cursor-pointer ${
|
||||||
active
|
active
|
||||||
? 'bg-accent text-on-accent border-accent font-medium'
|
? item.activeClass
|
||||||
: 'bg-canvas text-muted hover:text-main border-border'
|
: 'bg-canvas text-muted hover:text-main border-border'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{labels[p]}
|
{item.icon}
|
||||||
|
<span>{item.label}</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-1.5">
|
||||||
<span className="text-muted flex items-center gap-1">
|
<span className="text-muted text-[11px] font-semibold flex items-center gap-1">
|
||||||
<Calendar className="w-3 h-3 text-accent" />
|
<Calendar className="w-3.5 h-3.5 text-accent" />
|
||||||
Fällig am:
|
Fällig am:
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -335,29 +335,49 @@ export const TaskDetailModal: React.FC<TaskDetailModalProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Priority Buttons */}
|
{/* Priority Buttons (4 Buttons) */}
|
||||||
<div className="space-y-1.5 pt-1 border-t border-border">
|
<div className="space-y-1.5 pt-1 border-t border-border">
|
||||||
<label className="block text-xs font-semibold text-main">
|
<label className="block text-xs font-semibold text-main">
|
||||||
Priorität:
|
Priorität:
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-wrap items-center gap-1.5">
|
<div className="grid grid-cols-2 sm:grid-cols-4 gap-1.5">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onUpdatePriority(task, 'normal')}
|
onClick={() => {
|
||||||
className={`h-7 px-3 text-xs rounded-btn font-medium transition-colors border ${
|
triggerHaptic(10);
|
||||||
!task.priority || task.priority === 'normal' || task.priority === 'low'
|
onUpdatePriority(task, 'low');
|
||||||
? 'bg-panel border-accent text-main font-semibold'
|
}}
|
||||||
|
className={`h-8 px-2 text-xs rounded-btn font-medium transition-colors border flex items-center justify-center gap-1 cursor-pointer ${
|
||||||
|
task.priority === 'low'
|
||||||
|
? 'bg-canvas border-strong text-main font-semibold shadow-xs'
|
||||||
: 'bg-canvas border-border text-muted hover:text-main'
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Normal / Keine
|
<span>Niedrig</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onUpdatePriority(task, 'high')}
|
onClick={() => {
|
||||||
className={`h-7 px-3 text-xs rounded-btn font-medium transition-colors border flex items-center gap-1 ${
|
triggerHaptic(10);
|
||||||
|
onUpdatePriority(task, 'normal');
|
||||||
|
}}
|
||||||
|
className={`h-8 px-2 text-xs rounded-btn font-medium transition-colors border flex items-center justify-center gap-1 cursor-pointer ${
|
||||||
|
!task.priority || task.priority === 'normal'
|
||||||
|
? 'bg-accent/15 border-accent text-accent font-semibold shadow-xs'
|
||||||
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span>Normal</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
triggerHaptic(10);
|
||||||
|
onUpdatePriority(task, 'high');
|
||||||
|
}}
|
||||||
|
className={`h-8 px-2 text-xs rounded-btn font-medium transition-colors border flex items-center justify-center gap-1 cursor-pointer ${
|
||||||
task.priority === 'high'
|
task.priority === 'high'
|
||||||
? 'bg-status-warn/15 border-status-warn text-status-warn font-semibold'
|
? 'bg-status-warn/15 border-status-warn text-status-warn font-semibold shadow-xs'
|
||||||
: 'bg-canvas border-border text-muted hover:text-main'
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -366,10 +386,13 @@ export const TaskDetailModal: React.FC<TaskDetailModalProps> = ({
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onUpdatePriority(task, 'urgent')}
|
onClick={() => {
|
||||||
className={`h-7 px-3 text-xs rounded-btn font-medium transition-colors border flex items-center gap-1 ${
|
triggerHaptic(10);
|
||||||
|
onUpdatePriority(task, 'urgent');
|
||||||
|
}}
|
||||||
|
className={`h-8 px-2 text-xs rounded-btn font-medium transition-colors border flex items-center justify-center gap-1 cursor-pointer ${
|
||||||
task.priority === 'urgent'
|
task.priority === 'urgent'
|
||||||
? 'bg-status-err/15 border-status-err text-status-err font-semibold'
|
? 'bg-status-err/15 border-status-err text-status-err font-semibold shadow-xs'
|
||||||
: 'bg-canvas border-border text-muted hover:text-main'
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1660,32 +1660,54 @@ export const TasksView: React.FC<TasksViewProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Priority & Due Date */}
|
{/* Priority - 4 Buttons */}
|
||||||
<div className="grid grid-cols-2 gap-2 pt-1">
|
<div className="space-y-1.5 pt-1">
|
||||||
<div>
|
<label className="text-[11px] font-semibold text-muted block">Priorität</label>
|
||||||
<label className="text-[11px] font-semibold text-muted block mb-1">Priorität</label>
|
<div className="grid grid-cols-4 gap-1.5">
|
||||||
<select
|
{(['low', 'normal', 'high', 'urgent'] as PriorityLevel[]).map((p) => {
|
||||||
value={mobileCreatePriority}
|
const config: Record<PriorityLevel, { label: string; icon?: React.ReactNode; activeClass: string }> = {
|
||||||
onChange={(e) => setMobileCreatePriority(e.target.value as PriorityLevel)}
|
low: { label: 'Niedrig', activeClass: 'bg-canvas border-strong text-main font-semibold shadow-xs' },
|
||||||
className="w-full input-field px-2 py-2 text-xs bg-panel"
|
normal: { label: 'Normal', activeClass: 'bg-accent/15 border-accent text-accent font-semibold shadow-xs' },
|
||||||
|
high: { label: 'Wichtig', icon: <AlertTriangle className="w-3 h-3 text-status-warn" />, activeClass: 'bg-status-warn/15 border-status-warn text-status-warn font-semibold shadow-xs' },
|
||||||
|
urgent: { label: 'Dringend', icon: <Flame className="w-3 h-3 text-status-err" />, activeClass: 'bg-status-err/15 border-status-err text-status-err font-semibold shadow-xs' },
|
||||||
|
};
|
||||||
|
const active = mobileCreatePriority === p;
|
||||||
|
const item = config[p];
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={p}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
triggerHaptic(10);
|
||||||
|
setMobileCreatePriority(p);
|
||||||
|
}}
|
||||||
|
className={`h-9 px-1 text-xs rounded-btn font-medium transition-colors border flex items-center justify-center gap-1 cursor-pointer ${
|
||||||
|
active
|
||||||
|
? item.activeClass
|
||||||
|
: 'bg-canvas border-border text-muted hover:text-main'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<option value="normal">Normal</option>
|
{item.icon}
|
||||||
<option value="high">⚠️ Wichtig</option>
|
<span className="truncate">{item.label}</span>
|
||||||
<option value="urgent">🔥 Dringend</option>
|
</button>
|
||||||
<option value="low">Niedrig</option>
|
);
|
||||||
</select>
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
{/* Due Date */}
|
||||||
<label className="text-[11px] font-semibold text-muted block mb-1">Fällig am</label>
|
<div className="space-y-1 pt-1">
|
||||||
|
<label className="text-[11px] font-semibold text-muted flex items-center gap-1">
|
||||||
|
<Calendar className="w-3.5 h-3.5 text-accent" />
|
||||||
|
<span>Fällig am</span>
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
value={mobileCreateDueDate}
|
value={mobileCreateDueDate}
|
||||||
onChange={(e) => setMobileCreateDueDate(e.target.value)}
|
onChange={(e) => setMobileCreateDueDate(e.target.value)}
|
||||||
className="w-full input-field px-2 py-2 text-xs"
|
className="w-full input-field px-3 py-2 text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="pt-2 flex justify-end gap-2">
|
<div className="pt-2 flex justify-end gap-2">
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in new issue
Block a user