calendar and contacts panels keyed (569 -> 564)
Everything except the appRegistryMetas names, which are blocked on a design decision: AppRegistryEntry.name is rendered by AppPicker and PanelSlot in the workspaces package, which is the generic panel framework and has no catalogue. Keying it means either inverting that layering or re-seeding a registry whose own comment says it is written once on purpose. Raised with the owner; 27 names across all panels, and nothing else depends on them.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { CalendarEvent } from './shared';
|
||||
import { CalendarDays, MapPin, Repeat } from 'lucide-react';
|
||||
import { useCalendarEvents, useSelectedCollection } from './useDavData';
|
||||
import { useTranslation } from '../../locales';
|
||||
|
||||
// Right panel of /calendar. Deliberately a grouped agenda list, not a month grid: the sidecar returns
|
||||
// events as they are stored, with RRULE unexpanded, so a grid would have to invent occurrences the server
|
||||
@@ -26,12 +27,13 @@ const formatTime = (ev: CalendarEvent) => {
|
||||
};
|
||||
|
||||
export const CalendarView = () => {
|
||||
const { t } = useTranslation();
|
||||
const { selected, isLoading: loadingCollections } = useSelectedCollection('calendar');
|
||||
const { events, isLoading, error } = useCalendarEvents(selected?.path ?? null);
|
||||
|
||||
if (loadingCollections) return <Placeholder text="Loading calendars…" />;
|
||||
if (!selected) return <Placeholder text="No calendars yet. Create one from a CalDAV client." />;
|
||||
if (error) return <Placeholder text={`Could not read ${selected.displayName}: ${String(error)}`} />;
|
||||
if (error) return <Placeholder text={t('dav.readFailed', { name: selected.displayName, reason: String(error) })} />;
|
||||
if (isLoading) return <Placeholder text="Loading events…" />;
|
||||
if (events.length === 0) return <Placeholder text={`${selected.displayName} has no events.`} />;
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Link, useSearchParams } from 'react-router';
|
||||
import { CalendarDays, Contact as ContactIcon } from 'lucide-react';
|
||||
import { davCollectionPath, COLLECTION_PARAM } from './shared';
|
||||
import { useDavCollections } from './useDavData';
|
||||
import { useTranslation } from '../../locales';
|
||||
|
||||
// Left panel for both /calendar and /contacts: the list of collections belonging to this user.
|
||||
//
|
||||
@@ -22,6 +23,7 @@ type Props = {
|
||||
const ROW = 'group relative flex items-center gap-3 rounded-lg px-3 py-2 text-left text-sm transition-colors';
|
||||
|
||||
const CollectionNav = ({ kind, base, title, icon: Icon }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [params] = useSearchParams();
|
||||
const { collections, isLoading } = useDavCollections(kind);
|
||||
const fromUrl = params.get(COLLECTION_PARAM);
|
||||
@@ -69,19 +71,19 @@ const CollectionNav = ({ kind, base, title, icon: Icon }: Props) => {
|
||||
);
|
||||
})}
|
||||
{!isLoading && collections.length === 0 && (
|
||||
<p className="px-3 py-2 text-xs text-muted-foreground">
|
||||
Nothing here yet. Add one from a phone or desktop client over CalDAV/CardDAV.
|
||||
</p>
|
||||
<p className="px-3 py-2 text-xs text-muted-foreground">{t('dav.empty')}</p>
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const CalendarNav = () => (
|
||||
<CollectionNav kind="calendar" base="/calendar" title="Calendar" icon={CalendarDays} />
|
||||
);
|
||||
export const CalendarNav = () => {
|
||||
const { t } = useTranslation();
|
||||
return <CollectionNav kind="calendar" base="/calendar" title={t('dav.calendar')} icon={CalendarDays} />;
|
||||
};
|
||||
|
||||
export const ContactsNav = () => (
|
||||
<CollectionNav kind="addressbook" base="/contacts" title="Contacts" icon={ContactIcon} />
|
||||
);
|
||||
export const ContactsNav = () => {
|
||||
const { t } = useTranslation();
|
||||
return <CollectionNav kind="addressbook" base="/contacts" title={t('dav.contacts')} icon={ContactIcon} />;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Building2, Mail, Phone, User } from 'lucide-react';
|
||||
import { useDavContacts, useSelectedCollection } from './useDavData';
|
||||
import { useTranslation } from '../../locales';
|
||||
|
||||
// Right panel of /contacts: the selected address book as cards, sorted by name.
|
||||
//
|
||||
@@ -16,12 +17,13 @@ const initials = (name: string) =>
|
||||
.join('') || '?';
|
||||
|
||||
export const ContactsView = () => {
|
||||
const { t } = useTranslation();
|
||||
const { selected, isLoading: loadingCollections } = useSelectedCollection('addressbook');
|
||||
const { contacts, isLoading, error } = useDavContacts(selected?.path ?? null);
|
||||
|
||||
if (loadingCollections) return <Placeholder text="Loading address books…" />;
|
||||
if (!selected) return <Placeholder text="No address books yet. Create one from a CardDAV client." />;
|
||||
if (error) return <Placeholder text={`Could not read ${selected.displayName}: ${String(error)}`} />;
|
||||
if (error) return <Placeholder text={t('dav.readFailed', { name: selected.displayName, reason: String(error) })} />;
|
||||
if (isLoading) return <Placeholder text="Loading contacts…" />;
|
||||
if (contacts.length === 0) return <Placeholder text={`${selected.displayName} has no contacts.`} />;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user