mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 04:59:41 +02:00
Add new @manacore/wallpaper-generator package for creating device wallpapers from QR codes and images. Features: - 30 device presets (phones, tablets, desktops) - 3 layout types (center, corner, pattern) - 5 gradient presets + solid color backgrounds - Browser (Canvas) and Node.js (Sharp) renderers - Svelte WallpaperModal UI component Integrations: - @manacore/qr-export: toWallpaper() function - @manacore/spiral-db: toWallpaper() function - QRExportModal: "Als Wallpaper" button Also includes the full @manacore/qr-export package which was previously untracked. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
247 lines
4.6 KiB
TypeScript
247 lines
4.6 KiB
TypeScript
/**
|
|
* ManaQR Export Builder
|
|
*
|
|
* Fluent API for building QR exports easily.
|
|
*/
|
|
|
|
import type {
|
|
ManaQRExport,
|
|
ManaQRUserContext,
|
|
ManaQRContact,
|
|
ManaQREvent,
|
|
ManaQRTodo,
|
|
EncodeResult,
|
|
ContactRelation,
|
|
TodoPriority,
|
|
} from './types';
|
|
import { MANA_QR_LIMITS } from './types';
|
|
import { encode, estimateSize } from './encoder';
|
|
import {
|
|
selectTopContacts,
|
|
selectUpcomingEvents,
|
|
selectPriorityTodos,
|
|
type ContactInput,
|
|
type EventInput,
|
|
type TodoInput,
|
|
} from './selectors';
|
|
|
|
/**
|
|
* Builder for creating ManaQR exports
|
|
*
|
|
* @example
|
|
* ```ts
|
|
* const result = createManaQRExport()
|
|
* .user({ n: 'Till', z: 'Europe/Berlin', l: 'de' })
|
|
* .addContact({ n: 'Mama', p: '+491701234567', r: 1 })
|
|
* .addContact({ n: 'Papa', p: '+491707654321', r: 1 })
|
|
* .addEvent({ t: 'Zahnarzt', s: Date.now() + 86400000, d: 60 })
|
|
* .addTodo({ t: 'Steuererklärung', p: 1, d: 14 })
|
|
* .encode();
|
|
* ```
|
|
*/
|
|
export class ManaQRExportBuilder {
|
|
private _user: ManaQRUserContext = { n: '' };
|
|
private _contacts: ManaQRContact[] = [];
|
|
private _events: ManaQREvent[] = [];
|
|
private _todos: ManaQRTodo[] = [];
|
|
private _timestamp: number = Math.floor(Date.now() / 1000);
|
|
|
|
/**
|
|
* Set user context
|
|
*/
|
|
user(context: ManaQRUserContext): this {
|
|
this._user = context;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set user name (shorthand)
|
|
*/
|
|
userName(name: string): this {
|
|
this._user.n = name;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set user timezone
|
|
*/
|
|
timezone(tz: string): this {
|
|
this._user.z = tz;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set user language
|
|
*/
|
|
language(lang: string): this {
|
|
this._user.l = lang;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set user location
|
|
*/
|
|
location(loc: string): this {
|
|
this._user.w = loc;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a single contact
|
|
*/
|
|
addContact(contact: ManaQRContact): this {
|
|
this._contacts.push(contact);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add multiple contacts
|
|
*/
|
|
contacts(contacts: ManaQRContact[]): this {
|
|
this._contacts.push(...contacts);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add contacts from input format (auto-selects top contacts)
|
|
*/
|
|
contactsFrom(inputs: ContactInput[], limit: number = MANA_QR_LIMITS.MAX_CONTACTS): this {
|
|
this._contacts = selectTopContacts(inputs, limit);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a single event
|
|
*/
|
|
addEvent(event: ManaQREvent): this {
|
|
this._events.push(event);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add multiple events
|
|
*/
|
|
events(events: ManaQREvent[]): this {
|
|
this._events.push(...events);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add events from input format (auto-selects upcoming)
|
|
*/
|
|
eventsFrom(inputs: EventInput[], limit: number = MANA_QR_LIMITS.MAX_EVENTS): this {
|
|
this._events = selectUpcomingEvents(inputs, limit);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add a single todo
|
|
*/
|
|
addTodo(todo: ManaQRTodo): this {
|
|
this._todos.push(todo);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add multiple todos
|
|
*/
|
|
todos(todos: ManaQRTodo[]): this {
|
|
this._todos.push(...todos);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Add todos from input format (auto-selects by priority)
|
|
*/
|
|
todosFrom(inputs: TodoInput[], limit: number = MANA_QR_LIMITS.MAX_TODOS): this {
|
|
this._todos = selectPriorityTodos(inputs, limit);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Set custom timestamp (Unix seconds)
|
|
*/
|
|
timestamp(ts: number): this {
|
|
this._timestamp = ts;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Build the export data (without encoding)
|
|
*/
|
|
build(): ManaQRExport {
|
|
return {
|
|
v: 1,
|
|
ts: this._timestamp,
|
|
u: this._user,
|
|
c: this._contacts,
|
|
e: this._events,
|
|
t: this._todos,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Estimate encoded size in bytes
|
|
*/
|
|
estimateSize(): number {
|
|
return estimateSize(this.build());
|
|
}
|
|
|
|
/**
|
|
* Check if current data will fit in a QR code
|
|
*/
|
|
willFit(): boolean {
|
|
return this.estimateSize() <= MANA_QR_LIMITS.MAX_QR_BYTES;
|
|
}
|
|
|
|
/**
|
|
* Encode to QR-ready string
|
|
*/
|
|
encode(): EncodeResult {
|
|
return encode(this.build());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new ManaQR export builder
|
|
*/
|
|
export function createManaQRExport(): ManaQRExportBuilder {
|
|
return new ManaQRExportBuilder();
|
|
}
|
|
|
|
// --- Quick helpers for common formats ---
|
|
|
|
/**
|
|
* Create a contact in compact format
|
|
*/
|
|
export function contact(
|
|
name: string,
|
|
phone?: string,
|
|
relation: ContactRelation = 3
|
|
): ManaQRContact {
|
|
return { n: name, p: phone, r: relation };
|
|
}
|
|
|
|
/**
|
|
* Create an event in compact format
|
|
*/
|
|
export function event(
|
|
title: string,
|
|
startDate: Date,
|
|
durationMinutes = 60,
|
|
location?: string
|
|
): ManaQREvent {
|
|
return {
|
|
t: title,
|
|
s: Math.floor(startDate.getTime() / 1000),
|
|
d: durationMinutes,
|
|
l: location,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create a todo in compact format
|
|
*/
|
|
export function todo(title: string, priority: TodoPriority = 2, dueDays?: number): ManaQRTodo {
|
|
return { t: title, p: priority, d: dueDays };
|
|
}
|