feat: add demo data for emails, files, filters, identities, mailboxes, vacation responses, and JMAP client interface
- Created demo emails with various states (inbox, sent, drafts, trash, etc.) in `emails.ts`. - Added demo file nodes representing directories and files in `files.ts`. - Implemented demo Sieve capabilities and scripts in `filters.ts`. - Defined demo identities for users in `identities.ts`. - Established demo mailboxes with permissions and counts in `mailboxes.ts`. - Created a demo vacation response in `vacation.ts`. - Introduced a comprehensive JMAP client interface in `client-interface.ts` to standardize interactions with the JMAP API.
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
export interface TourStep {
|
||||
id: string;
|
||||
target: string;
|
||||
titleKey: string;
|
||||
descriptionKey: string;
|
||||
placement: "top" | "bottom" | "left" | "right";
|
||||
interactive?: boolean;
|
||||
spotlight?: "rect" | "circle";
|
||||
page?: string;
|
||||
demoOnly?: boolean;
|
||||
beforeAction?: () => void;
|
||||
}
|
||||
|
||||
export const BASE_TOUR_STEPS: TourStep[] = [
|
||||
{
|
||||
id: "sidebar",
|
||||
target: '[data-tour="sidebar"]',
|
||||
titleKey: "tour.sidebar_title",
|
||||
descriptionKey: "tour.sidebar_desc",
|
||||
placement: "right",
|
||||
},
|
||||
{
|
||||
id: "compose",
|
||||
target: '[data-tour="compose-button"]',
|
||||
titleKey: "tour.compose_title",
|
||||
descriptionKey: "tour.compose_desc",
|
||||
placement: "right",
|
||||
interactive: true,
|
||||
},
|
||||
{
|
||||
id: "search",
|
||||
target: '[data-tour="search-input"]',
|
||||
titleKey: "tour.search_title",
|
||||
descriptionKey: "tour.search_desc",
|
||||
placement: "bottom",
|
||||
interactive: true,
|
||||
},
|
||||
{
|
||||
id: "email-list",
|
||||
target: '[data-tour="email-list"]',
|
||||
titleKey: "tour.email_list_title",
|
||||
descriptionKey: "tour.email_list_desc",
|
||||
placement: "right",
|
||||
},
|
||||
{
|
||||
id: "email-viewer",
|
||||
target: '[data-tour="email-viewer"]',
|
||||
titleKey: "tour.email_viewer_title",
|
||||
descriptionKey: "tour.email_viewer_desc",
|
||||
placement: "left",
|
||||
beforeAction: () => {
|
||||
// Click the "Welcome to Bulwark Mail!" email (or the first email) to open the viewer
|
||||
const emailList = document.querySelector('[data-tour="email-list"]');
|
||||
if (!emailList) return;
|
||||
// Try to find the welcome email by subject text
|
||||
const items = emailList.querySelectorAll('.cursor-pointer');
|
||||
let target: HTMLElement | null = null;
|
||||
for (const item of items) {
|
||||
if (item.textContent?.includes("Welcome to Bulwark Mail")) {
|
||||
target = item as HTMLElement;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Fallback to first email if welcome email not found
|
||||
if (!target) target = emailList.querySelector('.cursor-pointer') as HTMLElement | null;
|
||||
if (target) target.click();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "keywords",
|
||||
target: '[data-tour="keyword-tags"]',
|
||||
titleKey: "tour.keywords_title",
|
||||
descriptionKey: "tour.keywords_desc",
|
||||
placement: "right",
|
||||
},
|
||||
{
|
||||
id: "nav-calendar",
|
||||
target: '[data-tour="nav-calendar"]',
|
||||
titleKey: "tour.calendar_title",
|
||||
descriptionKey: "tour.calendar_desc",
|
||||
placement: "right",
|
||||
},
|
||||
{
|
||||
id: "nav-contacts",
|
||||
target: '[data-tour="nav-contacts"]',
|
||||
titleKey: "tour.contacts_title",
|
||||
descriptionKey: "tour.contacts_desc",
|
||||
placement: "right",
|
||||
},
|
||||
{
|
||||
id: "nav-settings",
|
||||
target: '[data-tour="nav-settings"]',
|
||||
titleKey: "tour.settings_title",
|
||||
descriptionKey: "tour.settings_desc",
|
||||
placement: "right",
|
||||
},
|
||||
{
|
||||
id: "shortcuts",
|
||||
target: '[data-tour="nav-shortcuts"]',
|
||||
titleKey: "tour.shortcuts_title",
|
||||
descriptionKey: "tour.shortcuts_desc",
|
||||
placement: "right",
|
||||
interactive: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const DEMO_TOUR_STEPS: TourStep[] = [
|
||||
{
|
||||
id: "compose-open",
|
||||
target: '[data-tour="composer"]',
|
||||
titleKey: "tour.compose_open_title",
|
||||
descriptionKey: "tour.compose_open_desc",
|
||||
placement: "left",
|
||||
demoOnly: true,
|
||||
beforeAction: () => {
|
||||
// Click the compose button to open the composer
|
||||
const btn = document.querySelector('[data-tour="compose-button"]') as HTMLElement | null;
|
||||
if (btn) btn.click();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "calendar-view",
|
||||
target: '[data-tour="calendar-view"]',
|
||||
titleKey: "tour.calendar_view_title",
|
||||
descriptionKey: "tour.calendar_view_desc",
|
||||
placement: "bottom",
|
||||
page: "/calendar",
|
||||
demoOnly: true,
|
||||
},
|
||||
{
|
||||
id: "create-event",
|
||||
target: '[data-tour="create-event-button"]',
|
||||
titleKey: "tour.create_event_title",
|
||||
descriptionKey: "tour.create_event_desc",
|
||||
placement: "bottom",
|
||||
page: "/calendar",
|
||||
interactive: true,
|
||||
demoOnly: true,
|
||||
},
|
||||
{
|
||||
id: "event-modal",
|
||||
target: '[data-tour="event-modal"]',
|
||||
titleKey: "tour.event_modal_title",
|
||||
descriptionKey: "tour.event_modal_desc",
|
||||
placement: "left",
|
||||
page: "/calendar",
|
||||
interactive: true,
|
||||
demoOnly: true,
|
||||
beforeAction: () => {
|
||||
// Click the create event button to open the modal
|
||||
const btn = document.querySelector('[data-tour="create-event-button"]') as HTMLElement | null;
|
||||
if (btn) btn.click();
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "contacts-list",
|
||||
target: '[data-tour="contacts-list"]',
|
||||
titleKey: "tour.contacts_list_title",
|
||||
descriptionKey: "tour.contacts_list_desc",
|
||||
placement: "right",
|
||||
page: "/contacts",
|
||||
demoOnly: true,
|
||||
},
|
||||
{
|
||||
id: "settings-tabs",
|
||||
target: '[data-tour="settings-tabs"]',
|
||||
titleKey: "tour.settings_tabs_title",
|
||||
descriptionKey: "tour.settings_tabs_desc",
|
||||
placement: "right",
|
||||
page: "/settings",
|
||||
demoOnly: true,
|
||||
},
|
||||
{
|
||||
id: "nav-files",
|
||||
target: '[data-tour="nav-files"]',
|
||||
titleKey: "tour.files_title",
|
||||
descriptionKey: "tour.files_desc",
|
||||
placement: "right",
|
||||
demoOnly: true,
|
||||
},
|
||||
{
|
||||
id: "demo-banner",
|
||||
target: '[data-tour="demo-banner"]',
|
||||
titleKey: "tour.demo_banner_title",
|
||||
descriptionKey: "tour.demo_banner_desc",
|
||||
placement: "bottom",
|
||||
page: "/",
|
||||
demoOnly: true,
|
||||
},
|
||||
{
|
||||
id: "quota",
|
||||
target: '[data-tour="storage-quota"]',
|
||||
titleKey: "tour.quota_title",
|
||||
descriptionKey: "tour.quota_desc",
|
||||
placement: "right",
|
||||
demoOnly: true,
|
||||
},
|
||||
];
|
||||
|
||||
export function getTourSteps(options: {
|
||||
isDemoMode: boolean;
|
||||
supportsCalendar: boolean;
|
||||
supportsWebDAV: boolean;
|
||||
}): TourStep[] {
|
||||
let steps = [...BASE_TOUR_STEPS];
|
||||
|
||||
if (!options.supportsCalendar) {
|
||||
steps = steps.filter((s) => s.id !== "nav-calendar");
|
||||
}
|
||||
|
||||
if (options.isDemoMode) {
|
||||
const demoSteps = DEMO_TOUR_STEPS.filter((s) => {
|
||||
if (s.id === "nav-files" && !options.supportsWebDAV) return false;
|
||||
if ((s.id === "calendar-view" || s.id === "create-event" || s.id === "event-modal") && !options.supportsCalendar) return false;
|
||||
return true;
|
||||
});
|
||||
steps = [...steps, ...demoSteps];
|
||||
}
|
||||
|
||||
return steps;
|
||||
}
|
||||
Reference in New Issue
Block a user