pre-launch hardening: Address Book type sort, Hot Desk proportions, TVA calculator, ROADMAP Phase 4B
- Address Book: type dropdown always sorted alphabetically (ro locale), including custom types - Hot Desk: window ~half height (top-[35%] bottom-[35%]), door ~double height (h-16) - Mini Utilities: TVA calculator (19%) with add/extract modes, RON formatting, copy buttons - ROADMAP: new Phase 4B Pre-Launch Hardening with 10 structured tasks - CLAUDE.md: bumped versions (Address Book 0.1.1, Mini Utilities 0.1.1, Hot Desk 0.1.1), Visual Copilot separate repo note
This commit is contained in:
@@ -80,15 +80,22 @@ export function AddressBookModule() {
|
||||
null,
|
||||
);
|
||||
|
||||
// Collect all contact types (defaults + custom ones from existing contacts)
|
||||
// Collect all contact types (defaults + custom ones from existing contacts), sorted alphabetically by label
|
||||
const allTypes = useMemo(() => {
|
||||
const types = { ...DEFAULT_TYPE_LABELS };
|
||||
const types: Record<string, string> = { ...DEFAULT_TYPE_LABELS };
|
||||
for (const c of allContacts) {
|
||||
if (c.type && !types[c.type]) {
|
||||
types[c.type] = c.type; // custom type — label is the type itself
|
||||
}
|
||||
}
|
||||
return types;
|
||||
// Sort entries alphabetically by label
|
||||
const sorted: Record<string, string> = {};
|
||||
for (const [k, v] of Object.entries(types).sort((a, b) =>
|
||||
a[1].localeCompare(b[1], "ro"),
|
||||
)) {
|
||||
sorted[k] = v;
|
||||
}
|
||||
return sorted;
|
||||
}, [allContacts]);
|
||||
|
||||
const handleSubmit = async (
|
||||
@@ -652,15 +659,16 @@ function CreatableTypeSelect({
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{Object.entries(DEFAULT_TYPE_LABELS).map(([k, label]) => (
|
||||
<SelectItem key={k} value={k}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
{/* Show current custom value if not in defaults */}
|
||||
{value && !DEFAULT_TYPE_LABELS[value] && (
|
||||
<SelectItem value={value}>{value}</SelectItem>
|
||||
)}
|
||||
{Object.entries(DEFAULT_TYPE_LABELS)
|
||||
.concat(
|
||||
value && !DEFAULT_TYPE_LABELS[value] ? [[value, value]] : [],
|
||||
)
|
||||
.sort((a, b) => a[1].localeCompare(b[1], "ro"))
|
||||
.map(([k, label]) => (
|
||||
<SelectItem key={k} value={k}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user