@sqrzro/admin 2.1.0-bz.15 → 2.1.0-bz.17

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.
@@ -1,10 +1,9 @@
1
1
  /// <reference types="react" />
2
2
  export interface AppLayoutProps {
3
3
  children: React.ReactNode;
4
- layout?: string;
5
4
  user?: {
6
5
  name: string;
7
6
  } | null;
8
7
  }
9
- declare function AppLayout({ children, layout, user }: Readonly<AppLayoutProps>): React.ReactElement;
8
+ declare function AppLayout({ children, user }: Readonly<AppLayoutProps>): Promise<JSX.Element>;
10
9
  export default AppLayout;
@@ -1,10 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Container, Link, tw } from '@sqrzro/components';
3
3
  import { getConfig } from '../../services/ConfigService';
4
+ import { getLayout } from '../../services/LayoutService';
4
5
  import AppNavigation from '../AppNavigation';
5
6
  import MePanel from '../MePanel';
6
- function AppLayout({ children, layout, user }) {
7
+ async function AppLayout({ children, user }) {
7
8
  const config = getConfig();
8
- return (_jsxs("div", { className: tw('', layout === 'sidebar' ? 'grid grid-cols-[12rem_1fr]' : null), children: [_jsx("header", { className: "bg-slate-800", children: _jsx(Container, { isFullWidth: true, children: _jsxs("div", { className: tw('flex h-16 items-center border-b border-slate-700', layout === 'sidebar' ? 'h-screen flex-col' : null), children: [_jsxs(Link, { className: "h-9 w-9", href: "/", children: [config.logo?.(), _jsx("span", { className: "sr-only", children: config.app.name })] }), _jsx(AppNavigation, {}), _jsx(MePanel, { user: user })] }) }) }), _jsx("main", { className: "mb-10 block", children: children })] }));
9
+ const layout = await getLayout();
10
+ return (_jsxs("div", { className: tw('', layout === 'sidebar' ? 'grid grid-cols-[12rem_1fr]' : null), children: [_jsx("header", { className: "bg-slate-800", children: _jsx(Container, { isFullWidth: true, children: _jsxs("div", { className: tw('flex items-center', layout === 'sidebar'
11
+ ? 'h-screen flex-col py-4'
12
+ : 'h-16 border-b border-slate-700'), children: [_jsxs(Link, { className: tw(layout === 'sidebar' ? 'h-12 w-12' : 'h-9 w-9'), href: "/", children: [config.logo?.(), _jsx("span", { className: "sr-only", children: config.app.name })] }), _jsx(AppNavigation, { layout: layout }), _jsx(MePanel, { user: user })] }) }) }), _jsx("main", { className: "mb-10 block", children: children })] }));
9
13
  }
10
14
  export default AppLayout;
@@ -1,3 +1,6 @@
1
1
  /// <reference types="react" />
2
- declare function AppNavigation(): React.ReactElement;
2
+ interface AppNavigationProps {
3
+ layout: string;
4
+ }
5
+ declare function AppNavigation({ layout }: Readonly<AppNavigationProps>): React.ReactElement;
3
6
  export default AppNavigation;
@@ -7,9 +7,9 @@ function getNavigation() {
7
7
  const { navigation } = getConfig();
8
8
  return Object.entries(navigation).map(([href, label]) => ({ href, label }));
9
9
  }
10
- function AppNavigation() {
10
+ function AppNavigation({ layout }) {
11
11
  const navigation = useNavigation(getNavigation());
12
- return (_jsx("nav", { className: "h-full pl-6", children: _jsx("ul", { className: "flex h-full items-center gap-2", children: navigation.map(({ href, isActive, label }) => (_jsx("li", { className: "h-full", children: _jsx(Link, { className: tw('relative flex h-full items-center px-1 font-semibold', isActive
12
+ return (_jsx("nav", { className: "h-full pl-6", children: _jsx("ul", { className: tw('flex h-full gap-2', layout === 'sidebar' ? 'flex-col items-start' : 'items-center'), children: navigation.map(({ href, isActive, label }) => (_jsx("li", { className: tw(layout === 'sidebar' ? null : 'h-full'), children: _jsx(Link, { className: tw('relative flex h-full items-center px-1 font-semibold', isActive
13
13
  ? 'before:bg-primary text-white before:absolute before:bottom-0 before:left-0 before:right-0 before:h-1'
14
14
  : 'text-white/80 hover:text-white'), href: href, children: label }) }, href))) }) }));
15
15
  }
@@ -1,11 +1,20 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { tw } from '@sqrzro/components';
3
- const variantMap = {
4
- info: 'bg-sky-100 border-sky-300 text-sky-700',
5
- warning: 'bg-yellow-100 border-yellow-300 text-yellow-700',
6
- success: 'bg-emerald-100 border-emerald-300 text-emerald-600',
3
+ const classMap = {
4
+ danger: 'bg-red-100 text-red-700',
5
+ error: 'bg-red-100 text-red-700',
6
+ info: 'bg-sky-100 text-sky-700',
7
+ warning: 'bg-yellow-100 text-yellow-700',
8
+ success: 'bg-green-100 text-green-700',
9
+ };
10
+ const dotMap = {
11
+ danger: 'fill-red-500',
12
+ error: 'fill-red-500',
13
+ info: 'fill-sky-500',
14
+ warning: 'fill-yellow-500',
15
+ success: 'fill-green-500',
7
16
  };
8
17
  function Badge({ children, variant }) {
9
- return (_jsx("strong", { className: tw('block rounded border px-2 py-1 text-xs', variantMap[variant]), children: children }));
18
+ return (_jsxs("strong", { className: tw('inline-flex items-center gap-1.5 rounded-full px-2 py-1 text-xs font-medium', classMap[variant]), children: [_jsx("svg", { "aria-hidden": "true", className: tw('h-1.5 w-1.5', dotMap[variant]), viewBox: "0 0 6 6", children: _jsx("circle", { cx: "3", cy: "3", r: "3" }) }), children] }));
10
19
  }
11
20
  export default Badge;
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState } from 'react';
4
+ import { TextInput } from '@sqrzro/components';
4
5
  import { useFilters } from '@sqrzro/hooks';
5
6
  import { useRouter } from 'next/navigation';
6
7
  import FilterBarItem from '../FilterBarItem';
@@ -12,10 +13,14 @@ function FilterBar({ hasSearch, map }) {
12
13
  setFilter(name, value);
13
14
  router.refresh();
14
15
  }
15
- return (_jsxs("ul", { className: "relative flex gap-2 before:absolute before:left-[calc(50%-50vw)] before:top-full before:h-24 before:w-screen before:bg-slate-800", children: [hasSearch ? (_jsx("li", { children: _jsx("input", { name: "search", onChange: (event) => setSearch(event.currentTarget.value), onKeyDown: (event) => {
16
- if (event.key === 'Enter') {
17
- setFilter('search', event.currentTarget.value);
18
- }
19
- }, value: search }) })) : null, (map || []).map((filter) => (_jsx(FilterBarItem, { onChange: handleChange, value: filters.get(filter.name) || '', ...filter }, filter.name)))] }));
16
+ function handleSearchChange(event) {
17
+ setSearch(event.target.value || '');
18
+ }
19
+ function handleSearchKeyDown(event) {
20
+ if (event.key === 'Enter') {
21
+ setFilter('search', event.currentTarget.value);
22
+ }
23
+ }
24
+ return (_jsxs("ul", { className: "relative flex gap-2 before:absolute before:left-[calc(50%-50vw)] before:top-full before:h-24 before:w-screen before:bg-slate-800", children: [hasSearch ? (_jsx("li", { children: _jsx(TextInput, { name: "search", onChange: handleSearchChange, onKeyDown: handleSearchKeyDown, value: search }) })) : null, (map || []).map((filter) => (_jsx(FilterBarItem, { onChange: handleChange, value: filters.get(filter.name) || '', ...filter }, filter.name)))] }));
20
25
  }
21
26
  export default FilterBar;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
2
  import type { ListProps } from '../List';
3
- export type GridListProps<Item> = Omit<ListProps<Item>, 'renderItem'>;
4
- declare function GridList<Item extends object>(props: GridListProps<Item>): React.ReactElement;
3
+ export type GridListProps<Item, Params> = Omit<ListProps<Item, Params>, 'renderItem'>;
4
+ declare function GridList<Item extends object, Params>(props: GridListProps<Item, Params>): React.ReactElement;
5
5
  export default GridList;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- export type IconType = 'error' | 'info' | 'success' | 'warning';
2
+ export type IconType = 'danger' | 'error' | 'info' | 'success' | 'warning';
3
3
  declare const icons: Record<IconType, () => React.ReactElement>;
4
4
  export interface IconProps {
5
5
  type?: keyof typeof icons;
@@ -4,6 +4,7 @@ import InfoIcon from '../../icons/InfoIcon';
4
4
  import SuccessIcon from '../../icons/SuccessIcon';
5
5
  import WarningIcon from '../../icons/WarningIcon';
6
6
  const icons = {
7
+ danger: ErrorIcon,
7
8
  error: ErrorIcon,
8
9
  info: InfoIcon,
9
10
  success: SuccessIcon,
@@ -1,10 +1,22 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { tw } from '@sqrzro/components';
3
- const variantMap = {
4
- info: 'bg-sky-50 border-sky-200 text-sky-700',
5
- warning: 'bg-yellow-50 border-yellow-100 text-yellow-700',
3
+ import Icon from '../Icon';
4
+ const iconTypeMap = {
5
+ danger: 'danger',
6
+ info: 'info',
7
+ success: 'success',
8
+ warning: 'warning',
6
9
  };
10
+ const classMap = {
11
+ danger: 'bg-red-50 text-red-700',
12
+ info: 'bg-sky-50 text-sky-700',
13
+ success: 'bg-green-50 text-green-700',
14
+ warning: 'bg-yellow-50 text-yellow-700',
15
+ };
16
+ function mapVariantToIconType(variant) {
17
+ return iconTypeMap[variant] || 'info';
18
+ }
7
19
  function InfoPanel({ children, variant = 'info' }) {
8
- return (_jsx("aside", { className: tw('rounded border px-3 py-2', variantMap[variant]), children: children }));
20
+ return (_jsxs("aside", { className: tw('grid grid-cols-[1rem_auto] gap-4 rounded p-4', classMap[variant]), children: [_jsx(Icon, { type: mapVariantToIconType(variant) }), _jsx("div", { children: children })] }));
9
21
  }
10
22
  export default InfoPanel;
@@ -7,18 +7,19 @@ export interface ListComponentProps {
7
7
  params?: Record<string, string>;
8
8
  searchParams?: Record<string, string>;
9
9
  }
10
- export interface ListProps<Item> {
10
+ export interface ListProps<Item, Params> {
11
11
  actions?: ({ id }: {
12
12
  readonly id: number;
13
13
  }) => React.ReactElement;
14
14
  columns?: number;
15
15
  emptyMessageProps?: EmptyMessageProps;
16
16
  filters?: FilterObject[];
17
- fn: (params: Record<string, string>, searchParams: URLSearchParams) => Promise<Errorable<Item[]>>;
17
+ fn: (params?: Params, searchParams?: URLSearchParams) => Promise<Errorable<Item[]>>;
18
18
  hasSearch?: boolean;
19
+ isMinimal?: boolean;
19
20
  renderItem?: (props: ListObject) => React.ReactElement;
20
- params?: Record<string, string>;
21
+ params?: Params;
21
22
  transformer?: (item: Item) => ListObject;
22
23
  }
23
- declare function List<Item extends object>({ actions, columns, emptyMessageProps, filters, fn, hasSearch, params, renderItem, transformer, }: Readonly<ListProps<Item>>): Promise<React.ReactElement>;
24
+ declare function List<Item extends object, Params>({ actions, columns, emptyMessageProps, filters, fn, hasSearch, isMinimal, params, renderItem, transformer, }: Readonly<ListProps<Item, Params>>): Promise<React.ReactElement>;
24
25
  export default List;
@@ -9,7 +9,11 @@ function defaultTransformer() {
9
9
  title: '',
10
10
  };
11
11
  }
12
- async function List({ actions, columns, emptyMessageProps, filters, fn, hasSearch, params, renderItem = ListItem, transformer, }) {
12
+ const reservedSearchParams = ['action'];
13
+ function checkHasFilters(searchParams) {
14
+ return Array.from(searchParams.entries()).some(([key, value]) => !reservedSearchParams.includes(key) && Boolean(value));
15
+ }
16
+ async function List({ actions, columns, emptyMessageProps, filters, fn, hasSearch, isMinimal, params, renderItem = ListItem, transformer, }) {
13
17
  let searchParams;
14
18
  try {
15
19
  const { headers } = await import('next/headers');
@@ -18,12 +22,18 @@ async function List({ actions, columns, emptyMessageProps, filters, fn, hasSearc
18
22
  catch (err) {
19
23
  searchParams = new URLSearchParams();
20
24
  }
21
- const [response, error] = await fn(params || {}, searchParams);
25
+ const [response, error] = await fn(params, searchParams);
22
26
  if (error) {
23
27
  return _jsx("div", { children: "Error" });
24
28
  }
25
29
  const data = response.map(transformer || defaultTransformer);
26
- const hasFilters = Boolean(Object.keys(searchParams || []).length);
27
- return (_jsxs(Fragment, { children: [(filters || hasSearch) && (data.length || hasFilters) ? (_jsx(FilterBar, { hasSearch: hasSearch, map: filters })) : null, data.length ? (_jsx("ul", { className: tw('relative', columns ? 'grid grid-cols-3 gap-6' : 'flex flex-col gap-4'), children: data.map((item) => renderItem({ actions, ...item })) })) : (_jsx(EmptyMessage, { ...emptyMessageProps }))] }));
30
+ const hasFilters = checkHasFilters(searchParams);
31
+ const componentEmptyMessageProps = hasFilters
32
+ ? {
33
+ children: 'Try adjusting the filters above. If you think this is a mistake, please contact your site administrator.',
34
+ title: 'No results match the current filters',
35
+ }
36
+ : emptyMessageProps;
37
+ return (_jsxs(Fragment, { children: [(filters || hasSearch) && (data.length || hasFilters) ? (_jsx(FilterBar, { hasSearch: hasSearch, map: filters })) : null, data.length ? (_jsx("ul", { className: tw('relative', columns ? 'grid grid-cols-3 gap-6' : 'flex flex-col gap-4'), children: data.map((item) => renderItem({ actions, ...item })) })) : (_jsx(EmptyMessage, { ...componentEmptyMessageProps, classNameProps: { isMinimal } }))] }));
28
38
  }
29
39
  export default List;
@@ -3,15 +3,16 @@ export interface ListObject {
3
3
  actions?: ({ id }: {
4
4
  id: number | string;
5
5
  }) => React.ReactElement;
6
+ description?: React.ReactNode | null;
6
7
  href?: string;
7
8
  id: number | string;
8
9
  image?: string | null;
9
10
  imageHref?: string | null;
10
11
  meta?: React.ReactNode[] | Record<string, React.ReactNode>;
11
12
  subtitle?: React.ReactNode | null;
12
- title: string;
13
+ title?: string;
13
14
  }
14
15
  export declare function renderMeta(meta: ListObject['meta']): React.ReactElement | null;
15
16
  declare function ListItem({ actions: Actions, // eslint-disable-line @typescript-eslint/naming-convention
16
- href, id, meta, title, }: Readonly<ListObject>): React.ReactElement;
17
+ description, href, id, meta, title, }: Readonly<ListObject>): React.ReactElement;
17
18
  export default ListItem;
@@ -5,12 +5,12 @@ export function renderMeta(meta) {
5
5
  return null;
6
6
  }
7
7
  if (Array.isArray(meta)) {
8
- return (_jsx("ul", { className: "flex items-center gap-4 text-xs text-slate-600", children: meta.map((item) => (_jsx("li", { children: item }, item?.toString()))) }));
8
+ return (_jsx("ul", { className: "flex items-center gap-4 text-xs text-slate-600", children: meta.map((item, index) => (_jsx("li", { children: item }, index))) }));
9
9
  }
10
10
  return (_jsx("table", { className: "w-full text-xs", children: _jsx("tbody", { children: Object.entries(meta).map(([key, value]) => (_jsxs("tr", { className: "odd:bg-slate-100", children: [_jsx("th", { className: "p-2 font-semibold", children: key }), _jsx("td", { className: "p-2 text-right", children: value || '-' })] }, key))) }) }));
11
11
  }
12
12
  function ListItem({ actions: Actions, // eslint-disable-line @typescript-eslint/naming-convention
13
- href, id, meta, title, }) {
14
- return (_jsx("li", { children: _jsxs("article", { className: "bg-panel overflow-hidden rounded p-4 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]", children: [_jsx("h2", { className: "border-b border-slate-200 pb-3 text-lg font-semibold", children: href ? _jsx(Link, { href: href, children: title }) : title }), _jsxs("div", { className: "mt-4 flex items-center justify-between", children: [meta ? renderMeta(meta) : null, Actions ? _jsx(Actions, { id: id }) : null] })] }) }));
13
+ description, href, id, meta, title, }) {
14
+ return (_jsx("li", { children: _jsxs("article", { className: "bg-panel overflow-hidden rounded p-4 shadow-[0px_0px_0px_1px_rgba(9,9,11,0.07),0px_2px_2px_0px_rgba(9,9,11,0.05)]", children: [title ? (_jsx("h2", { className: "border-b border-slate-200 pb-3 text-lg font-semibold", children: href ? _jsx(Link, { href: href, children: title }) : title })) : null, description ? (_jsx("div", { className: "border-b border-slate-200 pb-3 ", children: description })) : null, _jsxs("div", { className: "mt-4 flex items-center justify-between", children: [meta ? renderMeta(meta) : null, Actions ? _jsx(Actions, { id: id }) : null] })] }) }));
15
15
  }
16
16
  export default ListItem;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import MeActions from '../MeActions';
3
3
  function MePanel({ user }) {
4
- return (_jsxs("div", { className: "ml-auto flex items-center gap-3", children: [_jsxs("div", { className: "flex flex-col gap-0.5 items-end text-white", children: [_jsx("strong", { children: user?.name }), _jsx(MeActions, {})] }), _jsx("div", { className: "h-9 w-9 rounded-full border-4 border-slate-500" })] }));
4
+ return (_jsxs("div", { className: "ml-auto flex items-center gap-3", children: [_jsxs("div", { className: "flex flex-col items-end gap-0.5 text-white", children: [_jsx("strong", { children: user?.name }), _jsx(MeActions, {})] }), _jsx("div", { className: "h-9 w-9 flex-none rounded-full border-4 border-slate-500" })] }));
5
5
  }
6
6
  export default MePanel;
@@ -8,5 +8,5 @@ export interface PageProps {
8
8
  tabs?: LinkableAction[];
9
9
  title: string;
10
10
  }
11
- declare function Page({ basePath, children, isFullWidth, tabs, title, }: Readonly<PageProps>): React.ReactElement;
11
+ declare function Page({ basePath, children, isFullWidth, tabs, title, }: Readonly<PageProps>): Promise<React.ReactElement>;
12
12
  export default Page;
@@ -1,8 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Fragment } from 'react';
3
- import { Container } from '@sqrzro/components';
3
+ import { Container, tw } from '@sqrzro/components';
4
+ import { getLayout } from '../../services/LayoutService';
4
5
  import Tabs from '../Tabs';
5
- function Page({ basePath, children, isFullWidth, tabs, title, }) {
6
- return (_jsxs(Fragment, { children: [_jsx("header", { className: "bg-slate-800 pb-16 text-white", children: _jsxs(Container, { isFullWidth: isFullWidth, children: [_jsxs("div", { className: "flex items-center justify-between py-10", children: [_jsx("h1", { className: "min-h-10 text-3xl font-semibold", children: title }), _jsx("div", { id: "page-actions" })] }), tabs ? (_jsx("div", { className: "-mt-4 mb-8", children: _jsx(Tabs, { basePath: basePath, data: tabs }) })) : null] }) }), _jsx(Container, { isFullWidth: isFullWidth, children: _jsx("div", { className: "-mt-16 flex flex-col gap-8", children: children }) })] }));
6
+ async function Page({ basePath, children, isFullWidth, tabs, title, }) {
7
+ const layout = await getLayout();
8
+ return (_jsxs(Fragment, { children: [_jsx("header", { className: tw('', layout === 'sidebar'
9
+ ? 'border-b border-slate-200 bg-white'
10
+ : 'bg-slate-800 pb-16 text-white'), children: _jsxs(Container, { isFullWidth: layout === 'sidebar' || isFullWidth, children: [_jsxs("div", { className: "flex items-center justify-between py-10", children: [_jsx("h1", { className: "min-h-10 text-3xl font-semibold", children: title }), _jsx("div", { className: "flex gap-2", id: "page-actions" })] }), tabs ? (_jsx("div", { className: "-mt-4 mb-8", children: _jsx(Tabs, { basePath: basePath, data: tabs }) })) : null] }) }), _jsx(Container, { isFullWidth: layout === 'sidebar' || isFullWidth, children: _jsx("div", { className: tw('flex flex-col gap-8', layout === 'sidebar' ? 'mt-8' : '-mt-16'), children: children }) })] }));
7
11
  }
8
12
  export default Page;
@@ -1,2 +1,9 @@
1
- declare function SettingsForm(): import("react/jsx-runtime").JSX.Element;
1
+ /// <reference types="react" />
2
+ interface SettingsFormFields {
3
+ layout: string;
4
+ }
5
+ interface SettingsFormProps {
6
+ defaults: Partial<SettingsFormFields>;
7
+ }
8
+ declare function SettingsForm({ defaults }: Readonly<SettingsFormProps>): JSX.Element;
2
9
  export default SettingsForm;
@@ -1,9 +1,14 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { EditableForm } from '@sqrzro/components';
3
+ import { EditableForm, EditableRadioFormField } from '@sqrzro/components';
4
4
  import { useEditableForm } from '@sqrzro/hooks';
5
- function SettingsForm() {
6
- const { formProps } = useEditableForm({});
7
- return (_jsx(EditableForm, { title: "Appearance", ...formProps, children: "Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, aperiam modi. Atque, nemo qui! Quae consectetur tempora beatae, ducimus reprehenderit, et aliquam quod est, quidem fugiat impedit sit nihil cum!" }));
5
+ import { submitLayoutForm } from '../../services/LayoutService';
6
+ const options = { sidebar: 'Side bar', topbar: 'Top bar' };
7
+ function SettingsForm({ defaults }) {
8
+ const { fieldProps, formProps } = useEditableForm({
9
+ defaults,
10
+ onSubmit: submitLayoutForm,
11
+ });
12
+ return (_jsx(EditableForm, { title: "Appearance", ...formProps, children: _jsx(EditableRadioFormField, { ...fieldProps('layout'), options: options, renderValue: (value) => (value ? options[value] || '-' : '-') }) }));
8
13
  }
9
14
  export default SettingsForm;
@@ -1,2 +1,3 @@
1
- declare function SettingsPage(): import("react/jsx-runtime").JSX.Element;
1
+ /// <reference types="react" />
2
+ declare function SettingsPage(): Promise<JSX.Element>;
2
3
  export default SettingsPage;
@@ -1,7 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { getLayout } from '../../services/LayoutService';
2
3
  import Page from '../Page';
3
4
  import SettingsForm from '../SettingsForm';
4
- function SettingsPage() {
5
- return (_jsx(Page, { title: "Settings", children: _jsx(SettingsForm, {}) }));
5
+ async function SettingsPage() {
6
+ const layout = await getLayout();
7
+ return (_jsx(Page, { title: "Settings", children: _jsx(SettingsForm, { defaults: { layout } }) }));
6
8
  }
7
9
  export default SettingsPage;
@@ -7,18 +7,5 @@ function Tabs({ basePath = '', data }) {
7
7
  return (_jsx("nav", { className: "border-b border-slate-700", children: _jsx("ul", { className: "flex gap-4", children: navigation.map(({ href, isActive, label }) => (_jsx("li", { children: _jsx(Link, { className: tw('block px-1 pb-2 font-semibold', isActive
8
8
  ? 'border-primary border-b-4 text-white'
9
9
  : 'text-white/80 hover:text-white'), href: href, children: label }) }, href))) }) }));
10
- // return (
11
- // <nav className="border-y border-slate-700">
12
- // <ul className="flex gap-4 font-semibold">
13
- // {data.map(({ href, label }) => (
14
- // <li key={href}>
15
- // <Link className="block py-2 text-white" href={`${basePath}${href || ''}`}>
16
- // {label}
17
- // </Link>
18
- // </li>
19
- // ))}
20
- // </ul>
21
- // </nav>
22
- // );
23
10
  }
24
11
  export default Tabs;
@@ -1,4 +1,5 @@
1
- export { Button, CalendarInput, ConnectedDropdown, DateFormField, DateInput, Dropdown, DropdownFormField, EditableDateFormField, EditableDropdownFormField, EditableForm, EditableFormField, EditableMultiFormField, EditableNumberFormField, EditableSwitchFormField, EditableTextFormField, Fieldset, Form, FormField, FormSubmit, ImageInput, ImageFormField, Link, ModalForm, MultiFormField, NumberFormField, NumberInput, Switch, SwitchFormField, TextFormField, TextInput, Toaster, } from '@sqrzro/components';
1
+ export { Autocomplete, AutocompleteFormField, Button, CalendarInput, ConnectedDropdown, ConfirmableButton, DateFormField, DateInput, Dropdown, DropdownFormField, EditableDateFormField, EditableDropdownFormField, EditableForm, EditableFormField, EditableMultiFormField, EditableNumberFormField, EditableSwitchFormField, EditableTextAreaFormField, EditableTextFormField, EmptyMessage, Fieldset, Form, FormField, FormSubmit, ImageInput, ImageFormField, Link, ModalForm, MultiFormField, NumberFormField, NumberInput, RadioInput, Switch, SwitchFormField, TextArea, TextAreaFormField, TextFormField, TextInput, Toaster, } from '@sqrzro/components';
2
+ export type { DropdownItem } from '@sqrzro/components';
2
3
  export type { AppLayoutProps } from './AppLayout';
3
4
  export { default as AppLayout } from './AppLayout';
4
5
  export type { AuthProps } from './Auth';
@@ -1,5 +1,5 @@
1
1
  // Exported from @sqrzro/components
2
- export { Button, CalendarInput, ConnectedDropdown, DateFormField, DateInput, Dropdown, DropdownFormField, EditableDateFormField, EditableDropdownFormField, EditableForm, EditableFormField, EditableMultiFormField, EditableNumberFormField, EditableSwitchFormField, EditableTextFormField, Fieldset, Form, FormField, FormSubmit, ImageInput, ImageFormField, Link, ModalForm, MultiFormField, NumberFormField, NumberInput, Switch, SwitchFormField, TextFormField, TextInput, Toaster, } from '@sqrzro/components';
2
+ export { Autocomplete, AutocompleteFormField, Button, CalendarInput, ConnectedDropdown, ConfirmableButton, DateFormField, DateInput, Dropdown, DropdownFormField, EditableDateFormField, EditableDropdownFormField, EditableForm, EditableFormField, EditableMultiFormField, EditableNumberFormField, EditableSwitchFormField, EditableTextAreaFormField, EditableTextFormField, EmptyMessage, Fieldset, Form, FormField, FormSubmit, ImageInput, ImageFormField, Link, ModalForm, MultiFormField, NumberFormField, NumberInput, RadioInput, Switch, SwitchFormField, TextArea, TextAreaFormField, TextFormField, TextInput, Toaster, } from '@sqrzro/components';
3
3
  export { default as AppLayout } from './AppLayout';
4
4
  export { default as Auth } from './Auth';
5
5
  export { default as Badge } from './Badge';
@@ -0,0 +1,7 @@
1
+ import type { SerializedErrorable } from '@sqrzro/interfaces';
2
+ type Layout = 'sidebar' | 'topbar';
3
+ export declare function getLayout(): Promise<string>;
4
+ export declare function submitLayoutForm(formData: {
5
+ layout: Layout;
6
+ }): Promise<SerializedErrorable<boolean>>;
7
+ export {};
@@ -0,0 +1,9 @@
1
+ 'use server';
2
+ import { cookies } from 'next/headers';
3
+ export async function getLayout() {
4
+ return Promise.resolve(cookies().get('layout')?.value || 'topbar');
5
+ }
6
+ export async function submitLayoutForm(formData) {
7
+ cookies().set('layout', formData.layout);
8
+ return Promise.resolve([true, null]);
9
+ }
@@ -34,8 +34,9 @@ const classNames = twx({
34
34
  },
35
35
  }),
36
36
  editableFieldset: () => ({
37
- root: 'bg-panel grid grid-cols-[30%_1fr] rounded p-8 shadow',
37
+ root: 'bg-panel grid grid-cols-[30%_1fr] gap-8 rounded p-8 shadow',
38
38
  title: 'mb-8 text-lg font-semibold leading-none text-slate-700',
39
+ description: 'text-slate-600',
39
40
  actions: 'flex justify-end gap-2 border-t border-slate-200 pt-4',
40
41
  }),
41
42
  editableFormField: () => ({
@@ -43,9 +44,12 @@ const classNames = twx({
43
44
  label: 'flex items-center font-semibold leading-none',
44
45
  field: 'flex min-h-10 items-center',
45
46
  }),
46
- emptyMessage: () => ({
47
- root: 'relative mx-auto mt-4 w-full max-w-xl rounded bg-white py-16 text-center text-slate-500 shadow before:pointer-events-none before:absolute before:inset-2 before:border-2 before:border-dashed',
48
- title: 'mb-2 text-xl font-semibold leading-none',
47
+ emptyMessage: (props) => ({
48
+ root: tw('relative mx-auto mt-4 w-full max-w-2xl p-16 text-center text-slate-500', props?.isMinimal
49
+ ? null
50
+ : 'rounded bg-white shadow before:pointer-events-none before:absolute before:inset-2 before:border-2 before:border-dashed'),
51
+ title: 'mb-2 text-pretty text-xl font-semibold leading-tight',
52
+ description: 'text-pretty',
49
53
  action: 'mt-6 flex justify-center',
50
54
  }),
51
55
  dropdown: () => ({
@@ -69,7 +73,7 @@ const classNames = twx({
69
73
  label: tw('flex font-semibold leading-none', props?.isEditable ? 'items-center' : 'mb-2 justify-between'),
70
74
  details: 'mb-2 text-xs font-normal leading-none text-slate-500',
71
75
  optional: 'pl-2 text-xs font-normal leading-none text-slate-500',
72
- error: 'mt-2 flex items-center gap-2 text-red-700 before:h-4 before:w-4 before:rounded-full before:bg-[url(/admin/images/error.svg)]',
76
+ error: tw('mt-2 flex items-center gap-2 text-red-700 before:h-4 before:w-4 before:rounded-full before:bg-[url(/admin/images/error.svg)]', props?.isEditable ? 'col-start-2' : ''),
73
77
  }),
74
78
  imageInput: () => ({
75
79
  root: 'h-64 rounded border border-slate-300 bg-slate-50 p-8',
@@ -90,6 +94,9 @@ const classNames = twx({
90
94
  root: 'flex flex-col gap-2',
91
95
  row: 'grid grid-cols-[1fr_auto] has-[>_button]:gap-2',
92
96
  }),
97
+ objectInput: () => ({
98
+ root: 'flex flex-col gap-2',
99
+ }),
93
100
  passwordInput: () => ({
94
101
  action: {
95
102
  default: 'mr-2 h-6 w-6 overflow-hidden bg-[url(/admin/images/eye.svg)] bg-no-repeat indent-12',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqrzro/admin",
3
- "version": "2.1.0-bz.15",
3
+ "version": "2.1.0-bz.17",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "ISC",