@ziyarago/ui 0.8.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.8.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, 196 components and 29 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
 
@@ -49,7 +49,14 @@ const T = Object.fromEntries([
49
49
  page('PageBilling', ['header', 'plan', 'usage', 'invoices', 'methods', 'upgrade'], ['col', 'header', ['two', ['plan', 'usage', 'invoices'], ['methods', 'upgrade']]]),
50
50
  page('PageTeam', ['header', 'stats', 'members', 'roles', 'invite'], ['col', 'header', 'stats', ['two', ['members', 'roles'], ['invite']]]),
51
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]])
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']])
53
60
  ]);
54
61
 
55
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', 'PageCalendar', 'PageKanban', 'PageBilling', 'PageTeam', 'PageIntegrations', 'PageSearch', '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
@@ -339,6 +339,92 @@ export default {
339
339
  },
340
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
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
+ },
342
428
  PageAuth: {
343
429
  description: 'Sign-in page template without the app shell, as a centered card or a split layout.',
344
430
  props: {