UI: restyle task detail onto the new tokens

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-09-01 22:37:59 +10:00
parent dff9142e2e
commit b183c2849b

View File

@@ -4,11 +4,11 @@ import { Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
import DateField from "../../components/DateField"; import DateField from "../../components/DateField";
import EstimateChips from "../../components/EstimateChips"; import EstimateChips from "../../components/EstimateChips";
import PriorityChips from "../../components/PriorityChips"; import PriorityChips from "../../components/PriorityChips";
import { Button, Chips, Field } from "../../components/ui"; import { Button, Chips, Empty, Field } from "../../components/ui";
import { haptic } from "../../lib/haptics"; import { haptic } from "../../lib/haptics";
import { REPEAT_LABEL, REPEATS } from "../../lib/repeat"; import { REPEAT_LABEL, REPEATS } from "../../lib/repeat";
import { activeProjects, knownContexts, trashTask, updateTask } from "../../lib/store"; import { activeProjects, knownContexts, trashTask, updateTask } from "../../lib/store";
import { C } from "../../lib/theme"; import { C, radius, space, type } from "../../lib/theme";
import { useStore } from "../../lib/useStore"; import { useStore } from "../../lib/useStore";
import type { Repeat, Task, TaskStatus } from "../../lib/types"; import type { Repeat, Task, TaskStatus } from "../../lib/types";
@@ -22,7 +22,7 @@ export default function TaskDetail() {
// Draft is local to the screen; nothing is written until Save. // Draft is local to the screen; nothing is written until Save.
const [draft, setDraft] = useState<Task | null>(original ?? null); const [draft, setDraft] = useState<Task | null>(original ?? null);
if (!draft) return <Text style={{ color: C.muted, margin: 16 }}>Task not found.</Text>; if (!draft) return <Empty>Task not found.</Empty>;
const set = (patch: Partial<Task>) => setDraft({ ...draft, ...patch }); const set = (patch: Partial<Task>) => setDraft({ ...draft, ...patch });
@@ -50,7 +50,7 @@ export default function TaskDetail() {
if (draft.status === "trashed") { if (draft.status === "trashed") {
return ( return (
<ScrollView style={{ flex: 1, backgroundColor: C.bg }} contentContainerStyle={{ padding: 16 }}> <ScrollView style={{ flex: 1, backgroundColor: C.bg }} contentContainerStyle={s.content}>
<Text style={s.trashedTitle}>{draft.title}</Text> <Text style={s.trashedTitle}>{draft.title}</Text>
<Text style={s.trashedMeta}>In the trash.</Text> <Text style={s.trashedMeta}>In the trash.</Text>
<Button <Button
@@ -66,7 +66,12 @@ export default function TaskDetail() {
} }
return ( return (
<ScrollView style={{ flex: 1, backgroundColor: C.bg }} contentContainerStyle={{ padding: 16 }}> <ScrollView
style={{ flex: 1, backgroundColor: C.bg }}
contentContainerStyle={s.content}
keyboardShouldPersistTaps="handled"
showsVerticalScrollIndicator={false}
>
<Field label="Title" value={draft.title} onChangeText={(v) => set({ title: v })} /> <Field label="Title" value={draft.title} onChangeText={(v) => set({ title: v })} />
<PriorityChips value={draft.priority} onChange={(priority) => set({ priority })} /> <PriorityChips value={draft.priority} onChange={(priority) => set({ priority })} />
<EstimateChips value={draft.estimate_min} onChange={(estimate_min) => set({ estimate_min })} /> <EstimateChips value={draft.estimate_min} onChange={(estimate_min) => set({ estimate_min })} />
@@ -87,18 +92,25 @@ export default function TaskDetail() {
/> />
{contexts.length > 0 && ( {contexts.length > 0 && (
<View style={s.contextRow}> <View style={s.contextRow}>
{contexts.map((c) => ( {contexts.map((c) => {
const active = draft.context === c;
return (
<Pressable <Pressable
key={c} key={c}
style={[s.contextChip, draft.context === c && s.contextChipActive]} style={({ pressed }) => [
s.contextChip,
active && s.contextChipActive,
pressed && !active && { backgroundColor: C.surface2 },
]}
onPress={() => { onPress={() => {
haptic.select(); haptic.select();
set({ context: draft.context === c ? null : c }); set({ context: active ? null : c });
}} }}
> >
<Text style={[s.contextText, draft.context === c && { color: C.text }]}>{c}</Text> <Text style={[s.contextText, active && s.contextTextActive]}>{c}</Text>
</Pressable> </Pressable>
))} );
})}
</View> </View>
)} )}
{draft.status === "waiting" && ( {draft.status === "waiting" && (
@@ -126,7 +138,7 @@ export default function TaskDetail() {
value={draft.notes} value={draft.notes}
onChangeText={(v) => set({ notes: v })} onChangeText={(v) => set({ notes: v })}
multiline multiline
style={{ minHeight: 80, textAlignVertical: "top" }} style={{ minHeight: 96, textAlignVertical: "top" }}
/> />
<Button title="Save" onPress={save} /> <Button title="Save" onPress={save} />
<Button <Button
@@ -142,18 +154,26 @@ export default function TaskDetail() {
} }
const s = StyleSheet.create({ const s = StyleSheet.create({
trashedTitle: { color: C.text, fontSize: 18, marginBottom: 6 }, content: { padding: space.lg, paddingBottom: space.xxl },
trashedMeta: { color: C.muted, fontSize: 14, marginBottom: 18 }, trashedTitle: { ...type.title, fontSize: 22, color: C.text, marginBottom: space.xs },
contextRow: { flexDirection: "row", flexWrap: "wrap", gap: 8, marginTop: -6, marginBottom: 14 }, trashedMeta: { ...type.body, color: C.muted, marginBottom: space.xl },
contextRow: {
flexDirection: "row",
flexWrap: "wrap",
gap: space.sm,
marginTop: -space.sm,
marginBottom: space.lg,
},
contextChip: { contextChip: {
paddingVertical: 6, paddingVertical: 7,
paddingHorizontal: 12, paddingHorizontal: space.md + 1,
borderRadius: 16, borderRadius: radius.pill,
backgroundColor: C.surface, backgroundColor: C.surface,
borderWidth: 1, borderWidth: StyleSheet.hairlineWidth,
borderColor: C.border, borderColor: C.border,
}, },
contextChipActive: { backgroundColor: C.surface2, borderColor: C.accent }, contextChipActive: { backgroundColor: C.accentSoft, borderColor: C.accent },
contextText: { color: C.muted, fontSize: 13 }, contextText: { ...type.meta, color: C.textSecondary },
deferHint: { color: C.muted, fontSize: 13, marginTop: -8, marginBottom: 12 }, contextTextActive: { color: C.accent, fontWeight: "600" },
deferHint: { ...type.meta, color: C.muted, marginTop: -space.sm, marginBottom: space.md },
}); });