@ziyarago/ui 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/style.css CHANGED
@@ -541,6 +541,9 @@
541
541
  .zg-ash__media[style*="url("]::after{display:none}
542
542
  .zg-ash--light .zg-ash__media{--ash-acc:oklch(.72 .08 80)}
543
543
 
544
+ /* page templates: sticky region */
545
+ .zg-pg__two--sticky{align-items:stretch}.zg-pg__stick{position:sticky;inset-block-start:16px;align-self:flex-start;width:100%}
546
+
544
547
 
545
548
  /* ./sizes/typography.css */
546
549
  /* size overrides for the typography group. Only [data-size] selectors, see the size scale at the end of tokens.css */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ziyarago/ui",
3
- "version": "0.7.0",
4
- "description": "ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 190 components and 23 page templates.",
3
+ "version": "0.9.0",
4
+ "description": "ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 203 components and 36 page templates.",
5
5
  "keywords": [
6
6
  "ui",
7
7
  "design-system",
package/src/core/pages.js CHANGED
@@ -3,15 +3,15 @@
3
3
  // React: <UiPageDashboard title="Dashboard" kpis={<…/>} />
4
4
  import { cx } from './components.js';
5
5
 
6
- const region = (h, id, kids) => (kids == null || (Array.isArray(kids) && !kids.length)) ? null : h('div', { key: id, class: 'zg-pg__r', 'data-slot': id }, kids);
6
+ const region = (h, id, kids, stick) => (kids == null || (Array.isArray(kids) && !kids.length)) ? null : h('div', { key: id, class: stick ? 'zg-pg__r zg-pg__stick' : 'zg-pg__r', 'data-slot': id }, kids);
7
7
 
8
8
  const draw = (h, node, ctx) => {
9
- if (typeof node === 'string') return node === 'header' ? ctx.header() : region(h, node, ctx.slots[node]);
10
- const [kind, ...a] = node, go = n => draw(h, n, ctx);
9
+ if (typeof node === 'string') return node === 'header' ? ctx.header() : region(h, node, ctx.slots[node], ctx.stick === node);
10
+ const [kind, ...a] = node, opt = kind === 'two' ? a[2] : kind === 'wrap' ? a[3] : null, st = typeof opt === 'string' && opt.startsWith('sticky:') ? opt.slice(7) : null, go = n => draw(h, n, st ? { ...ctx, stick: st } : ctx), cls = st ? 'zg-pg__two zg-pg__two--sticky' : 'zg-pg__two';
11
11
  if (kind === 'col') return h('div', { class: 'zg-pg' }, ...a.map(go));
12
12
  if (kind === 'auto') { const min = a.shift(); return h('div', { class: 'zg-pg__auto', style: { '--min': min + 'px' } }, ...a.map(go)); }
13
- if (kind === 'two') return h('div', { class: 'zg-pg__two' }, h('div', { class: 'zg-pg__main' }, ...a[0].map(go)), h('div', { class: 'zg-pg__side' }, ...a[1].map(go)));
14
- if (kind === 'wrap') return h('div', { class: 'zg-pg__two' }, h('div', { class: 'zg-pg__aside', style: { flexBasis: (a[2] || 300) + 'px' } }, ...a[0].map(go)), h('div', { class: 'zg-pg__main' }, ...a[1].map(go)));
13
+ if (kind === 'two') return h('div', { class: cls }, h('div', { class: 'zg-pg__main' }, ...a[0].map(go)), h('div', { class: 'zg-pg__side' }, ...a[1].map(go)));
14
+ if (kind === 'wrap') return h('div', { class: cls }, h('div', { class: 'zg-pg__aside', style: { flexBasis: (a[2] || 300) + 'px' } }, ...a[0].map(go)), h('div', { class: 'zg-pg__main' }, ...a[1].map(go)));
15
15
  return null;
16
16
  };
17
17
 
@@ -43,7 +43,20 @@ const T = Object.fromEntries([
43
43
  page('PageCheckout', ['header', 'steps', 'items', 'address', 'payment', 'summary'], ['col', 'header', 'steps', ['two', ['items', 'address', 'payment'], ['summary']]]),
44
44
  page('PageInbox', ['header', 'filters', 'list', 'thread', 'composer', 'customer'], ['col', 'header', ['wrap', ['filters', 'list'], [['two', ['thread', 'composer'], ['customer']]], 320]]),
45
45
  page('PageNotifications', ['header', 'filters', 'feed', 'empty'], ['col', 'header', 'filters', 'feed', 'empty']),
46
- page('PageAnalytics', ['header', 'period', 'kpis', 'trend', 'breakdown', 'table'], ['col', 'header', 'period', 'kpis', ['auto', 420, 'trend', 'breakdown'], 'table'])
46
+ page('PageAnalytics', ['header', 'period', 'kpis', 'trend', 'breakdown', 'table'], ['col', 'header', 'period', 'kpis', ['auto', 420, 'trend', 'breakdown'], 'table']),
47
+ page('PageCalendar', ['header', 'toolbar', 'grid', 'mini', 'details'], ['col', 'header', 'toolbar', ['two', ['grid'], ['mini', 'details']]]),
48
+ page('PageKanban', ['header', 'filters', 'board', 'detail'], ['col', 'header', 'filters', ['two', ['board'], ['detail']]]),
49
+ page('PageBilling', ['header', 'plan', 'usage', 'invoices', 'methods', 'upgrade'], ['col', 'header', ['two', ['plan', 'usage', 'invoices'], ['methods', 'upgrade']]]),
50
+ page('PageTeam', ['header', 'stats', 'members', 'roles', 'invite'], ['col', 'header', 'stats', ['two', ['members', 'roles'], ['invite']]]),
51
+ page('PageIntegrations', ['header', 'filters', 'connections', 'keys', 'webhooks'], ['col', 'header', 'filters', 'connections', ['auto', 420, 'keys', 'webhooks']]),
52
+ page('PageSearch', ['header', 'search', 'filters', 'results', 'empty'], ['col', 'header', 'search', ['wrap', ['filters'], ['results', 'empty'], 260]]),
53
+ page('PageArticle', ['header', 'cover', 'body', 'toc', 'share', 'related'], ['col', 'header', 'cover', ['two', ['body', 'share', 'related'], ['toc'], 'sticky:toc']]),
54
+ page('PageChangelog', ['header', 'filters', 'timeline', 'subscribe'], ['col', 'header', ['two', ['filters', 'timeline'], ['subscribe'], 'sticky:subscribe']]),
55
+ page('PageHelp', ['header', 'search', 'categories', 'popular', 'contact'], ['col', 'header', 'search', 'categories', ['auto', 360, 'popular', 'contact']]),
56
+ page('PageStates', ['header', 'empty', 'noresults', 'forbidden', 'offline', 'error', 'loading', 'success'], ['col', 'header', ['auto', 300, 'empty', 'noresults', 'forbidden'], ['auto', 300, 'offline', 'error', 'loading'], 'success']),
57
+ page('PageLegal', ['header', 'meta', 'toc', 'document', 'contact'], ['col', 'header', 'meta', ['wrap', ['toc'], ['document', 'contact'], 260, 'sticky:toc']]),
58
+ page('PageLocations', ['header', 'filters', 'list', 'map'], ['col', 'header', 'filters', ['wrap', ['list'], ['map'], 380, 'sticky:map']]),
59
+ page('PageBookingFlow', ['header', 'steps', 'content', 'nav', 'summary'], ['col', 'header', 'steps', ['two', ['content', 'nav'], ['summary'], 'sticky:summary']])
47
60
  ]);
48
61
 
49
62
  T.PageAuth = { slots: ['background', 'logo', 'aside', 'form', 'footer'], render: ({ C, h, props: p, slots: s }) => {
@@ -10,7 +10,7 @@ export const GROUPS = [
10
10
  { id: 'navigation', title: 'Navigation', blurb: 'Menus, tabs and paging.', names: ['TopNav', 'SideNav', 'SubNav', 'Tabs', 'PillTabs', 'Breadcrumbs', 'Pagination', 'Accordion'] },
11
11
  { id: 'media', title: 'Media and icons', blurb: 'Avatars, images, maps and icons.', names: ['Avatar', 'Icon', 'LazyImage', 'Gallery', 'Carousel', 'Map', 'ProfileHeader', 'ChatAi'] },
12
12
  { id: 'domain', title: 'Domain', blurb: 'Umrah, Hajj, hotel and CRM blocks.', names: ['HotelCard', 'TourCard', 'PrayerTimes', 'RamadanTracker', 'BookingCard', 'GuestCard', 'RoomGrid', 'RoomCalendar', 'LeadCard', 'DealCard', 'PipelineBoard', 'ContactPanel', 'KanbanColumn', 'KanbanCard', 'CallRow', 'CallCard', 'IncomingCall', 'AuthSplit', 'AuthShowcase', 'SocialAuth'] },
13
- { id: 'pages', title: 'Page templates', blurb: 'Ready layouts with named slots.', names: ['PageDashboard', 'PagePatterns', 'PageCrm', 'PageBookings', 'PageCatalog', 'PageDetail', 'PageSettings', 'PageUserList', 'PageProfile', 'PageForm', 'PageOrder', 'PageAccount', 'PagePricing', 'PageFaq', 'PageAnalytics', 'PageNotifications', 'PageInbox', 'PageCheckout', 'PageOnboarding', 'PageLanding', 'PageAuth', 'PageStatus'] },
13
+ { id: 'pages', title: 'Page templates', blurb: 'Ready layouts with named slots.', names: ['PageDashboard', 'PagePatterns', 'PageCrm', 'PageBookings', 'PageCatalog', 'PageDetail', 'PageSettings', 'PageUserList', 'PageProfile', 'PageForm', 'PageOrder', 'PageAccount', 'PagePricing', 'PageFaq', 'PageAnalytics', 'PageCalendar', 'PageKanban', 'PageBilling', 'PageTeam', 'PageIntegrations', 'PageSearch', 'PageArticle', 'PageChangelog', 'PageHelp', 'PageStates', 'PageLegal', 'PageLocations', 'PageBookingFlow', 'PageNotifications', 'PageInbox', 'PageCheckout', 'PageOnboarding', 'PageLanding', 'PageAuth', 'PageStatus'] },
14
14
  ];
15
15
 
16
16
  export const groupOf = name => GROUPS.find(g => g.names.includes(name));
package/src/meta/pages.js CHANGED
@@ -267,6 +267,164 @@ export default {
267
267
  },
268
268
  notes: [hdrNote, "Trend and breakdown share a row and wrap on narrow screens. Put Export in the actions slot."],
269
269
  },
270
+ PageCalendar: {
271
+ description: "Calendar template: view switch, time grid, mini calendar and event details.",
272
+ props: header,
273
+ slots: {
274
+ ...headSlots,
275
+ toolbar: "SegmentedControl, Button, IconButton.",
276
+ grid: "Time grid with events; Card with custom grid, or CalendarView for the month.",
277
+ mini: "Month picker; Calendar.",
278
+ details: "Selected event; Card, Descriptions, Avatar, Button.",
279
+ },
280
+ notes: [hdrNote, "The grid sits beside the mini calendar and details; they stack under 860 px."],
281
+ },
282
+ PageKanban: {
283
+ description: "Kanban template: filters, task board columns and a card detail panel.",
284
+ props: header,
285
+ slots: {
286
+ ...headSlots,
287
+ filters: "SearchInput, FilterChips, Select.",
288
+ board: "Columns with cards; KanbanColumn, KanbanCard.",
289
+ detail: "Selected card; Card, Descriptions, Checkbox, Timeline.",
290
+ },
291
+ notes: [hdrNote, "Board scrolls horizontally inside its area; detail goes below it under 860 px."],
292
+ },
293
+ PageBilling: {
294
+ description: "Billing template: current plan, usage meters, invoices, payment methods and an upgrade card.",
295
+ props: header,
296
+ slots: {
297
+ ...headSlots,
298
+ plan: "Current plan; Card with Badge and Buttons.",
299
+ usage: "Usage meters; Progress.",
300
+ invoices: "Invoices; DataTable.",
301
+ methods: "Saved cards; Card, IconTile, Badge.",
302
+ upgrade: "Upgrade call to action; Card variant=\"inverse\" or PricingCard.",
303
+ },
304
+ notes: [hdrNote, "Plan, usage and invoices share the main column; methods and upgrade form the side column."],
305
+ },
306
+ PageTeam: {
307
+ description: "Team template: member stats, members table, roles and permissions matrix, and an invite form.",
308
+ props: header,
309
+ slots: {
310
+ ...headSlots,
311
+ stats: "Counters; KpiTile, StatsCard.",
312
+ members: "Members; DataTable with UserCell, Select, Badge.",
313
+ roles: "Permissions matrix; DataTable with Checkbox cells.",
314
+ invite: "Invite form; Card, TextField, Select, Button.",
315
+ },
316
+ notes: [hdrNote, "Members and roles share the main column; the invite form is the side column."],
317
+ },
318
+ PageIntegrations: {
319
+ description: "Integrations template: connection cards, API keys and webhooks.",
320
+ props: header,
321
+ slots: {
322
+ ...headSlots,
323
+ filters: "SearchInput, FilterChips.",
324
+ connections: "IntegrationCard grid.",
325
+ keys: "Keys; DataTable with CopyButton and IconButton.",
326
+ webhooks: "Webhooks list; Card, Switch, Chip.",
327
+ },
328
+ notes: [hdrNote, "Keys and webhooks share a row and wrap on narrow screens."],
329
+ },
330
+ PageSearch: {
331
+ description: "Search template: query field, filter sidebar, result groups and an empty state.",
332
+ props: header,
333
+ slots: {
334
+ ...headSlots,
335
+ search: "SearchInput, Tabs.",
336
+ filters: "Filters; Card, Checkbox, Select.",
337
+ results: "Result groups; Card, Chip, Divider.",
338
+ empty: "Shown only when there are no results; EmptyState.",
339
+ },
340
+ notes: [hdrNote, "Filters sit left of the results and stack above them under 860 px. Fill empty only when there are no results."],
341
+ },
342
+ PageArticle: {
343
+ description: "Article template: cover, post body, sticky table of contents, share row and related posts.",
344
+ props: header,
345
+ slots: {
346
+ ...headSlots,
347
+ cover: "Cover image area with title and author line; a gradient Card or LazyImage.",
348
+ body: "Article text; Heading, Text, Code, Alert.",
349
+ toc: "Sticky table of contents; Card with a list of anchor links.",
350
+ share: "Share and reaction row; Button, IconButton, CopyButton.",
351
+ related: "Related posts; Card grid.",
352
+ },
353
+ notes: [hdrNote, "Body, share and related share the main column; the table of contents stays visible on the right while the body scrolls and drops under the body below 860 px."],
354
+ },
355
+ PageChangelog: {
356
+ description: "Changelog template: release timeline grouped by version with new, fix and improved tags, a filter and a subscribe card.",
357
+ props: header,
358
+ slots: {
359
+ ...headSlots,
360
+ filters: "Tag filter; FilterChips, SearchInput.",
361
+ timeline: "Releases grouped by version; Card, Chip, Divider.",
362
+ subscribe: "Sticky subscribe card; Card, TextField, Button.",
363
+ },
364
+ notes: [hdrNote, "Filters and timeline share the main column; the subscribe card is a sticky side column."],
365
+ },
366
+ PageHelp: {
367
+ description: "Help center home: search, category grid, popular articles and a contact card.",
368
+ props: header,
369
+ slots: {
370
+ ...headSlots,
371
+ search: "Large search field; SearchInput.",
372
+ categories: "Category tiles; Card with IconTile.",
373
+ popular: "Popular articles list; Card.",
374
+ contact: "Contact options; Card, Button.",
375
+ },
376
+ notes: [hdrNote, "Popular articles and contact share a row and wrap on narrow screens. For a single question list use PageFaq."],
377
+ },
378
+ PageStates: {
379
+ description: "State gallery: empty list, no results, no permission, offline, error with retry, loading and success on one page.",
380
+ props: header,
381
+ slots: {
382
+ ...headSlots,
383
+ empty: "Empty list; EmptyState with a primary action.",
384
+ noresults: "No search results; EmptyState with a reset action.",
385
+ forbidden: "No permission; EmptyState with a request-access action.",
386
+ offline: "Offline; DataState state=\"offline\".",
387
+ error: "Error with retry; DataState state=\"error\".",
388
+ loading: "Loading; Skeleton or DataState state=\"loading\".",
389
+ success: "Success confirmation; Alert tone=\"success\" or EmptyState.",
390
+ },
391
+ notes: [hdrNote, "The first six slots sit in two rows of auto-fit cards; success spans the full width."],
392
+ },
393
+ PageLegal: {
394
+ description: "Legal document template: last-updated line, sticky table of contents, numbered sections and a contact card.",
395
+ props: header,
396
+ slots: {
397
+ ...headSlots,
398
+ meta: "Version, last-updated date and print or download buttons; Chip, Button.",
399
+ toc: "Sticky table of contents; Card with anchor links.",
400
+ document: "Document sections; Card, Heading, Text.",
401
+ contact: "Questions card; Card, Button.",
402
+ },
403
+ notes: [hdrNote, "The table of contents sits left of the document and stacks above it under 860 px."],
404
+ },
405
+ PageLocations: {
406
+ description: "Locations template: filters, a scrollable list of places and a sticky map panel.",
407
+ props: header,
408
+ slots: {
409
+ ...headSlots,
410
+ filters: "Search and category filters; SearchInput, FilterChips.",
411
+ list: "Places list; Card rows.",
412
+ map: "Map panel; Map, or a gradient placeholder.",
413
+ },
414
+ notes: [hdrNote, "The list is a fixed-width column left of the map; under 860 px the map goes below the list."],
415
+ },
416
+ PageBookingFlow: {
417
+ description: "Booking flow template: stepper, the active step content, back and continue buttons and a sticky summary card.",
418
+ props: header,
419
+ slots: {
420
+ ...headSlots,
421
+ steps: "Progress; Stepper.",
422
+ content: "Content of the active step (search, pick, guests, confirm); Card, DatePicker, OptionCards, NumberInput.",
423
+ nav: "Back and Continue buttons.",
424
+ summary: "Booking summary; Card, Descriptions.",
425
+ },
426
+ notes: [hdrNote, "Render only the active step in content. The summary stays visible on the right and goes below the step under 860 px."],
427
+ },
270
428
  PageAuth: {
271
429
  description: 'Sign-in page template without the app shell, as a centered card or a split layout.',
272
430
  props: {