@revenexx/studio-shared 0.4.0 → 0.4.2
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/module.d.mts +5 -3
- package/dist/module.json +2 -2
- package/dist/module.mjs +7 -3
- package/dist/runtime/components/Dashboard/DashboardConfirmDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardGrid.vue +45 -1
- package/dist/runtime/components/Dashboard/DashboardNameDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardPickerDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardShareDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetConfigDialog.vue +1 -1
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.d.vue.ts +2 -2
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.vue +14 -3
- package/dist/runtime/components/Dashboard/DashboardWidgetFrame.vue.d.ts +2 -2
- package/dist/runtime/components/DataTable/DataTable.d.vue.ts +73 -34
- package/dist/runtime/components/DataTable/DataTable.vue +352 -52
- package/dist/runtime/components/DataTable/DataTable.vue.d.ts +73 -34
- package/dist/runtime/components/DataTable/FacetPanel.vue +57 -8
- package/dist/runtime/components/DataTable/FilterMenu.vue +5 -5
- package/dist/runtime/components/DataTable/SavedViewsMenu.vue +61 -12
- package/dist/runtime/components/DataTable/SortMenu.vue +4 -1
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.d.vue.ts +23 -0
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.vue +29 -0
- package/dist/runtime/components/DataTable/ToolbarLabelTrigger.vue.d.ts +23 -0
- package/dist/runtime/components/DataTable/types.d.ts +17 -0
- package/dist/runtime/components/Form/FieldGrid.vue +1 -1
- package/dist/runtime/components/Form/SaveBar.d.vue.ts +1 -1
- package/dist/runtime/components/Form/SaveBar.vue.d.ts +1 -1
- package/dist/runtime/components/Media/MediaFolderTree.d.vue.ts +4 -4
- package/dist/runtime/components/Media/MediaFolderTree.vue +1 -2
- package/dist/runtime/components/Media/MediaFolderTree.vue.d.ts +4 -4
- package/dist/runtime/components/Media/MediaPickerDialog.d.vue.ts +11 -0
- package/dist/runtime/components/Media/MediaPickerDialog.vue +206 -54
- package/dist/runtime/components/Media/MediaPickerDialog.vue.d.ts +11 -0
- package/dist/runtime/components/Media/MediaUploader.vue +1 -1
- package/dist/runtime/components/Shared/AppIcon.d.vue.ts +1 -1
- package/dist/runtime/components/Shared/AppIcon.vue.d.ts +1 -1
- package/dist/runtime/components/Shared/CardSizeToggle.d.vue.ts +11 -0
- package/dist/runtime/components/Shared/CardSizeToggle.vue +19 -0
- package/dist/runtime/components/Shared/CardSizeToggle.vue.d.ts +11 -0
- package/dist/runtime/components/Shared/DetailSheet.d.vue.ts +1 -1
- package/dist/runtime/components/Shared/DetailSheet.vue +9 -5
- package/dist/runtime/components/Shared/DetailSheet.vue.d.ts +1 -1
- package/dist/runtime/components/Shared/EmptyNote.d.vue.ts +19 -0
- package/dist/runtime/components/Shared/EmptyNote.vue +25 -0
- package/dist/runtime/components/Shared/EmptyNote.vue.d.ts +19 -0
- package/dist/runtime/components/Shared/KpiTile.d.vue.ts +6 -0
- package/dist/runtime/components/Shared/KpiTile.vue +10 -9
- package/dist/runtime/components/Shared/KpiTile.vue.d.ts +6 -0
- package/dist/runtime/components/Shared/PageHeader.vue +15 -4
- package/dist/runtime/components/Shared/RecordLayout.vue +1 -2
- package/dist/runtime/components/Shared/RecordRailCard.vue +3 -3
- package/dist/runtime/components/Shared/SelectionBar.d.vue.ts +22 -0
- package/dist/runtime/components/Shared/SelectionBar.vue +40 -0
- package/dist/runtime/components/Shared/SelectionBar.vue.d.ts +22 -0
- package/dist/runtime/components/Shared/SidebarNav.d.vue.ts +36 -2
- package/dist/runtime/components/Shared/SidebarNav.vue +74 -25
- package/dist/runtime/components/Shared/SidebarNav.vue.d.ts +36 -2
- package/dist/runtime/components/Shared/SidebarNavAreas.d.vue.ts +7 -0
- package/dist/runtime/components/Shared/SidebarNavAreas.vue +291 -0
- package/dist/runtime/components/Shared/SidebarNavAreas.vue.d.ts +7 -0
- package/dist/runtime/components/Shared/SidebarNavLink.d.vue.ts +1 -9
- package/dist/runtime/components/Shared/SidebarNavLink.vue +31 -5
- package/dist/runtime/components/Shared/SidebarNavLink.vue.d.ts +1 -9
- package/dist/runtime/components/Shared/SortHeader.vue +6 -2
- package/dist/runtime/components/Shared/StateCard.vue +1 -1
- package/dist/runtime/components/Shared/TabBar.vue +6 -7
- package/dist/runtime/components/Shared/Wizard.d.vue.ts +11 -1
- package/dist/runtime/components/Shared/Wizard.vue +9 -5
- package/dist/runtime/components/Shared/Wizard.vue.d.ts +11 -1
- package/dist/runtime/composables/useMediaLibrary.d.ts +12 -0
- package/dist/runtime/composables/useSavedViews.d.ts +11 -1
- package/dist/runtime/composables/useSavedViews.js +4 -4
- package/dist/runtime/composables/useWidgetFigures.d.ts +12 -0
- package/dist/runtime/composables/useWidgetFigures.js +24 -0
- package/dist/runtime/composables/useWidgetHeader.d.ts +15 -0
- package/dist/runtime/composables/useWidgetHeader.js +15 -0
- package/dist/runtime/lib/auditEnvelope.d.ts +43 -0
- package/dist/runtime/lib/auditEnvelope.js +55 -0
- package/dist/runtime/lib/cardSize.d.ts +13 -0
- package/dist/runtime/lib/cardSize.js +20 -0
- package/dist/runtime/lib/dashboardIcons.js +2 -0
- package/dist/runtime/lib/dataTableFilters.d.ts +22 -0
- package/dist/runtime/lib/dataTableFilters.js +5 -0
- package/dist/runtime/lib/facets.d.ts +13 -0
- package/dist/runtime/lib/formLayout.d.ts +74 -4
- package/dist/runtime/lib/formLayout.js +53 -6
- package/dist/runtime/lib/gridTracks.d.ts +14 -1
- package/dist/runtime/lib/gridTracks.js +13 -2
- package/dist/runtime/lib/isoLists.d.ts +37 -2
- package/dist/runtime/lib/isoLists.js +54 -1
- package/dist/runtime/lib/notice.d.ts +14 -0
- package/dist/runtime/lib/notice.js +19 -0
- package/dist/runtime/lib/pageSize.d.ts +15 -0
- package/dist/runtime/lib/pageSize.js +26 -0
- package/dist/runtime/lib/sidebarAreas.d.ts +46 -0
- package/dist/runtime/lib/sidebarAreas.js +25 -0
- package/dist/runtime/lib/sidebarNav.d.ts +39 -2
- package/dist/runtime/lib/sidebarNav.js +30 -4
- package/dist/runtime/lib/solarIconMap.d.ts +2 -1
- package/dist/runtime/lib/solarIconMap.js +50 -4
- package/dist/runtime/lib/swipeToClose.d.ts +25 -0
- package/dist/runtime/lib/swipeToClose.js +118 -0
- package/dist/runtime/lib/tableExport.d.ts +31 -0
- package/dist/runtime/lib/tableExport.js +143 -0
- package/dist/runtime/lib/talkback.d.ts +5 -0
- package/dist/runtime/lib/talkback.js +8 -0
- package/dist/runtime/lib/talkbackTokenBatch.d.ts +35 -0
- package/dist/runtime/lib/talkbackTokenBatch.js +101 -0
- package/dist/runtime/types/nav.d.ts +9 -0
- package/dist/types.d.mts +4 -0
- package/package.json +4 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const ABBREVIATIONS = /* @__PURE__ */ new Set(["bzw", "usw", "ggf", "inkl", "zzgl", "evtl", "etc", "vgl", "ca", "nr", "max", "min", "abs", "gem", "sog", "e.g", "i.e", "vs"]);
|
|
2
|
+
export function splitNotice(text) {
|
|
3
|
+
const source = (text ?? "").trim();
|
|
4
|
+
if (!source) return { title: "", description: null };
|
|
5
|
+
const pattern = /([.!?])\s+(?=[A-ZÄÖÜ„"(])/g;
|
|
6
|
+
let match;
|
|
7
|
+
while (match = pattern.exec(source)) {
|
|
8
|
+
const end = match.index;
|
|
9
|
+
if (match[1] === ".") {
|
|
10
|
+
const word = /([\p{L}.]+)$/u.exec(source.slice(0, end))?.[1] ?? "";
|
|
11
|
+
const bare = word.replace(/\.$/, "");
|
|
12
|
+
if (bare.length <= 2 || ABBREVIATIONS.has(bare.toLowerCase())) continue;
|
|
13
|
+
}
|
|
14
|
+
const title = source.slice(0, end + 1).trim();
|
|
15
|
+
const description = source.slice(pattern.lastIndex).trim();
|
|
16
|
+
return { title, description: description || null };
|
|
17
|
+
}
|
|
18
|
+
return { title: source, description: null };
|
|
19
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rows per page (PE-1052, Michael 15.10.): 50 by default, 25 / 50 / 100 / 200
|
|
3
|
+
* to choose from, remembered per user and table. The dummy keeps the choice in
|
|
4
|
+
* localStorage; the cockpit's `user_preferences` row is where it goes on
|
|
5
|
+
* transfer (same split as the density toggle).
|
|
6
|
+
*/
|
|
7
|
+
export declare const PAGE_SIZE_OPTIONS: readonly [25, 50, 100, 200];
|
|
8
|
+
export declare const DEFAULT_PAGE_SIZE = 50;
|
|
9
|
+
/** The storage key for one table's page size. */
|
|
10
|
+
export declare function pageSizeStorageKey(table: string): string;
|
|
11
|
+
/** The remembered size for a table, if it is one of the offered sizes. */
|
|
12
|
+
export declare function readPageSize(table: string | null | undefined): number | null;
|
|
13
|
+
export declare function writePageSize(table: string | null | undefined, size: number): void;
|
|
14
|
+
/** The sizes the footer offers — the standard four, plus a surface's own if it set another. */
|
|
15
|
+
export declare function pageSizeOptions(current: number): number[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const PAGE_SIZE_OPTIONS = [25, 50, 100, 200];
|
|
2
|
+
export const DEFAULT_PAGE_SIZE = 50;
|
|
3
|
+
export function pageSizeStorageKey(table) {
|
|
4
|
+
return `cockpit.datatable.pageSize:${table}`;
|
|
5
|
+
}
|
|
6
|
+
export function readPageSize(table) {
|
|
7
|
+
if (!table) return null;
|
|
8
|
+
try {
|
|
9
|
+
if (typeof window === "undefined") return null;
|
|
10
|
+
const n = Number(window.localStorage.getItem(pageSizeStorageKey(table)));
|
|
11
|
+
return PAGE_SIZE_OPTIONS.includes(n) ? n : null;
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function writePageSize(table, size) {
|
|
17
|
+
if (!table) return;
|
|
18
|
+
try {
|
|
19
|
+
if (typeof window === "undefined") return;
|
|
20
|
+
window.localStorage.setItem(pageSizeStorageKey(table), String(size));
|
|
21
|
+
} catch {
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function pageSizeOptions(current) {
|
|
25
|
+
return [.../* @__PURE__ */ new Set([...PAGE_SIZE_OPTIONS, current])].sort((a, b) => a - b);
|
|
26
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { SidebarNavSection } from '../types/nav.js';
|
|
2
|
+
/**
|
|
3
|
+
* Area mode of the studio sidebar (Commerce Studio, click dummy variant C3).
|
|
4
|
+
*
|
|
5
|
+
* The section the route is in shows its rows as before. Every other section
|
|
6
|
+
* shrinks to a single "area" row; resting on it (or
|
|
7
|
+
* clicking it) lays a panel with that section's rows next to the sidebar.
|
|
8
|
+
* Nothing folds: which section is open follows the route, not a toggle.
|
|
9
|
+
*/
|
|
10
|
+
export type SidebarAreaBlock = {
|
|
11
|
+
kind: 'section';
|
|
12
|
+
section: SidebarNavSection;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'area';
|
|
15
|
+
section: SidebarNavSection;
|
|
16
|
+
};
|
|
17
|
+
/** True when one of the section's rows (or their tabs) holds `path`. */
|
|
18
|
+
export declare function sectionHoldsActive(section: SidebarNavSection, path: string, best?: number): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* A section whose one entry carries the section's own name (Konfiguration →
|
|
21
|
+
* Konfiguration) is that entry: a plain link row, never an area with a panel
|
|
22
|
+
* of one (Michael 17.10.).
|
|
23
|
+
*/
|
|
24
|
+
export declare function isSelfNamed(section: SidebarNavSection): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Which sections render as rows and which as area rows. Only a section without
|
|
27
|
+
* a label (the pinned Dashboard row) and the route's own section show rows;
|
|
28
|
+
* a one-row section is an area too, so every section reads the same way
|
|
29
|
+
* (Michael 17.10.). With `best`, only the section of the closest match opens.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sidebarAreaBlocks(sections: SidebarNavSection[], path: string, best?: number): SidebarAreaBlock[];
|
|
32
|
+
export interface Point {
|
|
33
|
+
x: number;
|
|
34
|
+
y: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Safe triangle: is `p` inside the triangle spanned by where the pointer last
|
|
38
|
+
* rested on the open area row (`apex`) and the panel's near edge (`top`,
|
|
39
|
+
* `bottom`)? Then the pointer is on its way into the panel and crossing other
|
|
40
|
+
* area rows must not switch the panel (Tog's Apple menus, Amazon's menu-aim).
|
|
41
|
+
*/
|
|
42
|
+
export declare function inSafeTriangle(p: Point, apex: Point, top: Point, bottom: Point): boolean;
|
|
43
|
+
/** Timings, in ms. Opening waits for a rest; switching an open panel does not. */
|
|
44
|
+
export declare const AREA_OPEN_DELAY = 150;
|
|
45
|
+
export declare const AREA_AIM_DELAY = 180;
|
|
46
|
+
export declare const AREA_CLOSE_DELAY = 300;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { sidebarItemHoldsActive, sidebarItemMatchLength } from "./sidebarNav.js";
|
|
2
|
+
export function sectionHoldsActive(section, path, best) {
|
|
3
|
+
if (best === void 0) return section.items.some((item) => sidebarItemHoldsActive(item, path));
|
|
4
|
+
return best >= 0 && section.items.some((item) => sidebarItemMatchLength(item, path) === best);
|
|
5
|
+
}
|
|
6
|
+
export function isSelfNamed(section) {
|
|
7
|
+
return section.items.length === 1 && section.items[0].label === section.label;
|
|
8
|
+
}
|
|
9
|
+
export function sidebarAreaBlocks(sections, path, best) {
|
|
10
|
+
return sections.map(
|
|
11
|
+
(section) => !section.label || isSelfNamed(section) || sectionHoldsActive(section, path, best) ? { kind: "section", section } : { kind: "area", section }
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
export function inSafeTriangle(p, apex, top, bottom) {
|
|
15
|
+
const side = (a, b, c) => (a.x - c.x) * (b.y - c.y) - (b.x - c.x) * (a.y - c.y);
|
|
16
|
+
const d1 = side(p, apex, top);
|
|
17
|
+
const d2 = side(p, top, bottom);
|
|
18
|
+
const d3 = side(p, bottom, apex);
|
|
19
|
+
const neg = d1 < 0 || d2 < 0 || d3 < 0;
|
|
20
|
+
const pos = d1 > 0 || d2 > 0 || d3 > 0;
|
|
21
|
+
return !(neg && pos);
|
|
22
|
+
}
|
|
23
|
+
export const AREA_OPEN_DELAY = 150;
|
|
24
|
+
export const AREA_AIM_DELAY = 180;
|
|
25
|
+
export const AREA_CLOSE_DELAY = 300;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InjectionKey, Ref } from 'vue';
|
|
1
2
|
import type { SidebarNavItem } from '../types/nav.js';
|
|
2
3
|
/**
|
|
3
4
|
* Pure helpers behind `SidebarNav` / `SidebarNavLink`. They live outside the
|
|
@@ -12,16 +13,34 @@ import type { SidebarNavItem } from '../types/nav.js';
|
|
|
12
13
|
*/
|
|
13
14
|
/** Stable identity for `v-for` keys — `to` is unique where it exists. */
|
|
14
15
|
export declare function sidebarItemKey(item: SidebarNavItem): string;
|
|
15
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* True when `path` is the item's own route, or sits below it. `path` may carry
|
|
18
|
+
* a query: an item whose `to` names one (`/configuration?tab=markets`) is the
|
|
19
|
+
* page with exactly those parameters (an empty value: the parameter is
|
|
20
|
+
* absent); every other item ignores the query.
|
|
21
|
+
*/
|
|
16
22
|
export declare function sidebarItemIsActive(item: SidebarNavItem, path: string): boolean;
|
|
17
23
|
/** True when the item, or any of its tabs, matches `path`. */
|
|
18
24
|
export declare function sidebarItemHoldsActive(item: SidebarNavItem, path: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* How closely the item (or one of its tabs) matches `path`: the length of the
|
|
27
|
+
* longest matching route, -1 when none does. Two rows can both hold a path —
|
|
28
|
+
* Konfiguration's Zahlung owns `/payments/providers`, Auftragsabwicklung's
|
|
29
|
+
* Zahlungen owns `/payments` — and only the closer one is where you are.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sidebarItemMatchLength(item: SidebarNavItem, path: string): number;
|
|
32
|
+
/** The closest match any row of the sidebar has for `path` (-1: none). */
|
|
33
|
+
export declare function sidebarBestMatch(sections: ReadonlyArray<{
|
|
34
|
+
items: SidebarNavItem[];
|
|
35
|
+
}>, path: string): number;
|
|
36
|
+
/** Injected by `SidebarNav`: the closest match of the whole sidebar for the route. */
|
|
37
|
+
export declare const SIDEBAR_BEST_MATCH: InjectionKey<Ref<number>>;
|
|
19
38
|
/**
|
|
20
39
|
* Which row gets the highlight. The tabs of a group are not rows of their own,
|
|
21
40
|
* so the group stays lit for every one of them — an operator on *Carriers*
|
|
22
41
|
* still sees where they are, which is **Shipping**.
|
|
23
42
|
*/
|
|
24
|
-
export declare function sidebarItemIsCurrent(item: SidebarNavItem, path: string): boolean;
|
|
43
|
+
export declare function sidebarItemIsCurrent(item: SidebarNavItem, path: string, best?: number): boolean;
|
|
25
44
|
/**
|
|
26
45
|
* Where the row links. A group with a route of its own opens that (it is the
|
|
27
46
|
* default tab); a pure container — a heading several apps contribute to, where
|
|
@@ -32,3 +51,21 @@ export declare function sidebarItemIsCurrent(item: SidebarNavItem, path: string)
|
|
|
32
51
|
* section (Settings, Apps, …) from rendering a dead row.
|
|
33
52
|
*/
|
|
34
53
|
export declare function sidebarItemTarget(item: SidebarNavItem): string | undefined;
|
|
54
|
+
/** A box on screen, as `getBoundingClientRect` reports it — only what the sum needs. */
|
|
55
|
+
interface VerticalBox {
|
|
56
|
+
top: number;
|
|
57
|
+
height: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Where the sidebar's scroller has to stand for the current row to be in sight,
|
|
61
|
+
* moving as little as possible: the row's top edge when it sits above the view,
|
|
62
|
+
* its bottom edge when below, and nowhere when it is already visible.
|
|
63
|
+
*
|
|
64
|
+
* This is `scrollIntoView({ block: 'nearest' })` done by hand. The call itself is
|
|
65
|
+
* not usable here: Chrome also moves the point the next Tab starts from to the row
|
|
66
|
+
* it scrolled to, so after a page load the first Tab skipped the host's
|
|
67
|
+
* *Skip to content* and everything before the current row (IN-55). Setting the
|
|
68
|
+
* scroller's `scrollTop` moves the list and leaves the keyboard where it was.
|
|
69
|
+
*/
|
|
70
|
+
export declare function sidebarRevealScrollTop(view: VerticalBox, row: VerticalBox, scrollTop: number): number;
|
|
71
|
+
export {};
|
|
@@ -3,14 +3,33 @@ export function sidebarItemKey(item) {
|
|
|
3
3
|
}
|
|
4
4
|
export function sidebarItemIsActive(item, path) {
|
|
5
5
|
if (!item.to) return false;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const [bare, query = ""] = path.split("?");
|
|
7
|
+
const [to, wanted] = item.to.split("?");
|
|
8
|
+
if (wanted !== void 0) {
|
|
9
|
+
const have = new URLSearchParams(query);
|
|
10
|
+
return bare === to && [...new URLSearchParams(wanted)].every(([k, v]) => (have.get(k) ?? "") === v);
|
|
11
|
+
}
|
|
12
|
+
if (item.exact) return bare === to;
|
|
13
|
+
return bare === to || bare.startsWith(`${to}/`);
|
|
8
14
|
}
|
|
9
15
|
export function sidebarItemHoldsActive(item, path) {
|
|
10
16
|
return sidebarItemIsActive(item, path) || (item.children ?? []).some((child) => sidebarItemHoldsActive(child, path));
|
|
11
17
|
}
|
|
12
|
-
export function
|
|
13
|
-
|
|
18
|
+
export function sidebarItemMatchLength(item, path) {
|
|
19
|
+
const own = sidebarItemIsActive(item, path) ? item.to.length + 0.5 : -1;
|
|
20
|
+
return Math.max(own, ...(item.children ?? []).map((child) => tabMatchLength(child, path)));
|
|
21
|
+
}
|
|
22
|
+
function tabMatchLength(item, path) {
|
|
23
|
+
const own = sidebarItemIsActive(item, path) ? item.to.length : -1;
|
|
24
|
+
return Math.max(own, ...(item.children ?? []).map((child) => tabMatchLength(child, path)));
|
|
25
|
+
}
|
|
26
|
+
export function sidebarBestMatch(sections, path) {
|
|
27
|
+
return Math.max(-1, ...sections.flatMap((section) => section.items.map((item) => sidebarItemMatchLength(item, path))));
|
|
28
|
+
}
|
|
29
|
+
export const SIDEBAR_BEST_MATCH = Symbol("sidebar-best-match");
|
|
30
|
+
export function sidebarItemIsCurrent(item, path, best) {
|
|
31
|
+
if (best === void 0) return sidebarItemHoldsActive(item, path);
|
|
32
|
+
return best >= 0 && sidebarItemMatchLength(item, path) === best;
|
|
14
33
|
}
|
|
15
34
|
export function sidebarItemTarget(item) {
|
|
16
35
|
if (item.to) return item.to;
|
|
@@ -20,3 +39,10 @@ export function sidebarItemTarget(item) {
|
|
|
20
39
|
}
|
|
21
40
|
return void 0;
|
|
22
41
|
}
|
|
42
|
+
export function sidebarRevealScrollTop(view, row, scrollTop) {
|
|
43
|
+
const top = row.top - view.top + scrollTop;
|
|
44
|
+
const bottom = top + row.height;
|
|
45
|
+
if (top < scrollTop) return top;
|
|
46
|
+
if (bottom > scrollTop + view.height) return Math.min(top, bottom - view.height);
|
|
47
|
+
return scrollTop;
|
|
48
|
+
}
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The closed set of Solar icons the cockpit resolves by name: every icon the
|
|
5
5
|
* app manifests, this repo's code and the curated picker set ask for. Named
|
|
6
|
-
* imports, so the bundle carries these
|
|
6
|
+
* imports, so the bundle carries these 150 instead of all 1,413
|
|
7
7
|
* (PE-985). A name outside the set renders the fallback glyph; run
|
|
8
8
|
* `pnpm icons` after adding one, and `pnpm icons:check` to verify.
|
|
9
9
|
*/
|
|
10
10
|
import type { Component } from 'vue';
|
|
11
|
+
import { Record } from '#solar-icons';
|
|
11
12
|
export declare const SOLAR_ICON_MAP: Readonly<Record<string, Component>>;
|
|
12
13
|
/** Manifest names Solar does not have → the glyph drawn for them. */
|
|
13
14
|
export declare const SOLAR_ICON_ALIASES: Readonly<Record<string, string>>;
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
AddSquare,
|
|
4
4
|
Alarm,
|
|
5
5
|
Archive,
|
|
6
|
+
ArrowLeft,
|
|
6
7
|
ArrowRight,
|
|
7
8
|
Atom,
|
|
8
9
|
Backspace,
|
|
@@ -16,13 +17,15 @@ import {
|
|
|
16
17
|
Bookmark,
|
|
17
18
|
Box,
|
|
18
19
|
BranchingPathsUp,
|
|
19
|
-
Broom,
|
|
20
20
|
Buildings,
|
|
21
|
+
Calculator,
|
|
21
22
|
Calendar,
|
|
23
|
+
CalendarAdd,
|
|
24
|
+
CalendarMark,
|
|
22
25
|
CalendarMinimalistic,
|
|
23
26
|
Card,
|
|
24
|
-
CardTransfer,
|
|
25
27
|
Cart,
|
|
28
|
+
CartCheck,
|
|
26
29
|
CartLarge,
|
|
27
30
|
CartPlus,
|
|
28
31
|
Chart,
|
|
@@ -32,6 +35,7 @@ import {
|
|
|
32
35
|
ChatRoundLine,
|
|
33
36
|
CheckCircle,
|
|
34
37
|
CheckRead,
|
|
38
|
+
CheckSquare,
|
|
35
39
|
ChecklistMinimalistic,
|
|
36
40
|
Clipboard,
|
|
37
41
|
ClipboardList,
|
|
@@ -48,9 +52,11 @@ import {
|
|
|
48
52
|
Download,
|
|
49
53
|
DownloadMinimalistic,
|
|
50
54
|
Earth,
|
|
55
|
+
Euro,
|
|
51
56
|
Eye,
|
|
52
57
|
File,
|
|
53
58
|
FileText,
|
|
59
|
+
Flag,
|
|
54
60
|
Folder,
|
|
55
61
|
FolderOpen,
|
|
56
62
|
FolderPathConnect,
|
|
@@ -64,6 +70,7 @@ import {
|
|
|
64
70
|
Heart,
|
|
65
71
|
Help,
|
|
66
72
|
Home,
|
|
73
|
+
Hourglass,
|
|
67
74
|
Import,
|
|
68
75
|
Inbox,
|
|
69
76
|
InboxIn,
|
|
@@ -72,12 +79,17 @@ import {
|
|
|
72
79
|
Letter,
|
|
73
80
|
Lightbulb,
|
|
74
81
|
Link,
|
|
82
|
+
LinkBroken,
|
|
83
|
+
LinkBrokenMinimalistic,
|
|
75
84
|
LinkRound,
|
|
76
85
|
List,
|
|
77
86
|
ListCheck,
|
|
78
87
|
Lock,
|
|
88
|
+
LockKeyhole,
|
|
89
|
+
Logout,
|
|
79
90
|
MagicStick,
|
|
80
91
|
Magnifer,
|
|
92
|
+
Mailbox,
|
|
81
93
|
Map,
|
|
82
94
|
MapPoint,
|
|
83
95
|
MedalRibbon,
|
|
@@ -92,6 +104,7 @@ import {
|
|
|
92
104
|
PlugCircle,
|
|
93
105
|
Pulse,
|
|
94
106
|
Radar,
|
|
107
|
+
Record,
|
|
95
108
|
Refresh,
|
|
96
109
|
RefreshCircle,
|
|
97
110
|
Restart,
|
|
@@ -107,20 +120,30 @@ import {
|
|
|
107
120
|
ShieldUser,
|
|
108
121
|
Shop,
|
|
109
122
|
Shuffle,
|
|
123
|
+
Snowflake,
|
|
110
124
|
Star,
|
|
111
125
|
Stars,
|
|
126
|
+
StopCircle,
|
|
112
127
|
Tag,
|
|
113
128
|
TagPrice,
|
|
129
|
+
TextField,
|
|
114
130
|
Ticket,
|
|
131
|
+
TransferHorizontal,
|
|
115
132
|
TrashBinMinimalistic,
|
|
116
133
|
TrashBinTrash,
|
|
134
|
+
UndoLeft,
|
|
117
135
|
UndoLeftRound,
|
|
118
136
|
Upload,
|
|
119
137
|
User,
|
|
120
138
|
UserBlock,
|
|
121
139
|
UserCheck,
|
|
140
|
+
UserCrossRounded,
|
|
141
|
+
UserHandUp,
|
|
122
142
|
UserId,
|
|
143
|
+
UserPlus,
|
|
144
|
+
UserPlusRounded,
|
|
123
145
|
UsersGroupRounded,
|
|
146
|
+
UsersGroupTwoRounded,
|
|
124
147
|
Wallet,
|
|
125
148
|
WalletMoney,
|
|
126
149
|
Weigher,
|
|
@@ -132,6 +155,7 @@ export const SOLAR_ICON_MAP = {
|
|
|
132
155
|
AddSquare,
|
|
133
156
|
Alarm,
|
|
134
157
|
Archive,
|
|
158
|
+
ArrowLeft,
|
|
135
159
|
ArrowRight,
|
|
136
160
|
Atom,
|
|
137
161
|
Backspace,
|
|
@@ -145,13 +169,15 @@ export const SOLAR_ICON_MAP = {
|
|
|
145
169
|
Bookmark,
|
|
146
170
|
Box,
|
|
147
171
|
BranchingPathsUp,
|
|
148
|
-
Broom,
|
|
149
172
|
Buildings,
|
|
173
|
+
Calculator,
|
|
150
174
|
Calendar,
|
|
175
|
+
CalendarAdd,
|
|
176
|
+
CalendarMark,
|
|
151
177
|
CalendarMinimalistic,
|
|
152
178
|
Card,
|
|
153
|
-
CardTransfer,
|
|
154
179
|
Cart,
|
|
180
|
+
CartCheck,
|
|
155
181
|
CartLarge,
|
|
156
182
|
CartPlus,
|
|
157
183
|
Chart,
|
|
@@ -161,6 +187,7 @@ export const SOLAR_ICON_MAP = {
|
|
|
161
187
|
ChatRoundLine,
|
|
162
188
|
CheckCircle,
|
|
163
189
|
CheckRead,
|
|
190
|
+
CheckSquare,
|
|
164
191
|
ChecklistMinimalistic,
|
|
165
192
|
Clipboard,
|
|
166
193
|
ClipboardList,
|
|
@@ -177,9 +204,11 @@ export const SOLAR_ICON_MAP = {
|
|
|
177
204
|
Download,
|
|
178
205
|
DownloadMinimalistic,
|
|
179
206
|
Earth,
|
|
207
|
+
Euro,
|
|
180
208
|
Eye,
|
|
181
209
|
File,
|
|
182
210
|
FileText,
|
|
211
|
+
Flag,
|
|
183
212
|
Folder,
|
|
184
213
|
FolderOpen,
|
|
185
214
|
FolderPathConnect,
|
|
@@ -193,6 +222,7 @@ export const SOLAR_ICON_MAP = {
|
|
|
193
222
|
Heart,
|
|
194
223
|
Help,
|
|
195
224
|
Home,
|
|
225
|
+
Hourglass,
|
|
196
226
|
Import,
|
|
197
227
|
Inbox,
|
|
198
228
|
InboxIn,
|
|
@@ -201,12 +231,17 @@ export const SOLAR_ICON_MAP = {
|
|
|
201
231
|
Letter,
|
|
202
232
|
Lightbulb,
|
|
203
233
|
Link,
|
|
234
|
+
LinkBroken,
|
|
235
|
+
LinkBrokenMinimalistic,
|
|
204
236
|
LinkRound,
|
|
205
237
|
List,
|
|
206
238
|
ListCheck,
|
|
207
239
|
Lock,
|
|
240
|
+
LockKeyhole,
|
|
241
|
+
Logout,
|
|
208
242
|
MagicStick,
|
|
209
243
|
Magnifer,
|
|
244
|
+
Mailbox,
|
|
210
245
|
Map,
|
|
211
246
|
MapPoint,
|
|
212
247
|
MedalRibbon,
|
|
@@ -221,6 +256,7 @@ export const SOLAR_ICON_MAP = {
|
|
|
221
256
|
PlugCircle,
|
|
222
257
|
Pulse,
|
|
223
258
|
Radar,
|
|
259
|
+
Record,
|
|
224
260
|
Refresh,
|
|
225
261
|
RefreshCircle,
|
|
226
262
|
Restart,
|
|
@@ -236,20 +272,30 @@ export const SOLAR_ICON_MAP = {
|
|
|
236
272
|
ShieldUser,
|
|
237
273
|
Shop,
|
|
238
274
|
Shuffle,
|
|
275
|
+
Snowflake,
|
|
239
276
|
Star,
|
|
240
277
|
Stars,
|
|
278
|
+
StopCircle,
|
|
241
279
|
Tag,
|
|
242
280
|
TagPrice,
|
|
281
|
+
TextField,
|
|
243
282
|
Ticket,
|
|
283
|
+
TransferHorizontal,
|
|
244
284
|
TrashBinMinimalistic,
|
|
245
285
|
TrashBinTrash,
|
|
286
|
+
UndoLeft,
|
|
246
287
|
UndoLeftRound,
|
|
247
288
|
Upload,
|
|
248
289
|
User,
|
|
249
290
|
UserBlock,
|
|
250
291
|
UserCheck,
|
|
292
|
+
UserCrossRounded,
|
|
293
|
+
UserHandUp,
|
|
251
294
|
UserId,
|
|
295
|
+
UserPlus,
|
|
296
|
+
UserPlusRounded,
|
|
252
297
|
UsersGroupRounded,
|
|
298
|
+
UsersGroupTwoRounded,
|
|
253
299
|
Wallet,
|
|
254
300
|
WalletMoney,
|
|
255
301
|
Weigher,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swipe down to close a bottom sheet on the phone (Charge 2, Michael 12.10.).
|
|
3
|
+
*
|
|
4
|
+
* `v-swipe-close="close"` on any element inside a sheet: the sheet (the
|
|
5
|
+
* element marked `data-swipe-sheet`, else the nearest `role="dialog"`, else
|
|
6
|
+
* the element itself) follows the finger downwards; released past a quarter of
|
|
7
|
+
* its height — or flicked — it slides out and `close` runs, otherwise it snaps
|
|
8
|
+
* back. A drag only starts while the scroller under the finger is at its top,
|
|
9
|
+
* so it never fights the sheet's own scrolling. Phone widths only; on a wider
|
|
10
|
+
* screen the listeners do nothing.
|
|
11
|
+
*/
|
|
12
|
+
import type { Directive } from 'vue';
|
|
13
|
+
export interface SwipeState {
|
|
14
|
+
cleanup: () => void;
|
|
15
|
+
}
|
|
16
|
+
/** Pure decision, exported for tests: does a drag of `dy` px in `ms` close? */
|
|
17
|
+
export declare function shouldClose(dy: number, ms: number, height: number): boolean;
|
|
18
|
+
export declare function attachSwipeToClose(el: HTMLElement, onClose: () => void): SwipeState;
|
|
19
|
+
type SwipeEl = HTMLElement & {
|
|
20
|
+
__swipeClose?: SwipeState;
|
|
21
|
+
__swipeHandler?: () => void;
|
|
22
|
+
};
|
|
23
|
+
/** `v-swipe-close="handler"` — see the module comment. */
|
|
24
|
+
export declare const vSwipeClose: Directive<SwipeEl, (() => void) | undefined>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const PHONE = "(max-width: 767.98px)";
|
|
2
|
+
const CLOSE_RATIO = 0.25;
|
|
3
|
+
const FLICK_VELOCITY = 0.6;
|
|
4
|
+
function sheetOf(el) {
|
|
5
|
+
return el.closest("[data-swipe-sheet]") ?? el.closest('[role="dialog"]') ?? el;
|
|
6
|
+
}
|
|
7
|
+
function scrollerAt(target, sheet) {
|
|
8
|
+
let node = target instanceof HTMLElement ? target : null;
|
|
9
|
+
while (node) {
|
|
10
|
+
const style = getComputedStyle(node);
|
|
11
|
+
if (/(auto|scroll)/.test(style.overflowY) && node.scrollHeight > node.clientHeight) return node;
|
|
12
|
+
if (node === sheet) break;
|
|
13
|
+
node = node.parentElement;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
export function shouldClose(dy, ms, height) {
|
|
18
|
+
if (dy <= 0) return false;
|
|
19
|
+
if (dy > height * CLOSE_RATIO) return true;
|
|
20
|
+
return ms > 0 && dy / ms > FLICK_VELOCITY && dy > 24;
|
|
21
|
+
}
|
|
22
|
+
export function attachSwipeToClose(el, onClose) {
|
|
23
|
+
let sheet = null;
|
|
24
|
+
let startY = 0;
|
|
25
|
+
let startT = 0;
|
|
26
|
+
let dy = 0;
|
|
27
|
+
let dragging = false;
|
|
28
|
+
let armed = false;
|
|
29
|
+
const reset = (animate) => {
|
|
30
|
+
if (!sheet) return;
|
|
31
|
+
sheet.style.transition = animate ? "transform 200ms ease-out" : "";
|
|
32
|
+
sheet.style.transform = "";
|
|
33
|
+
};
|
|
34
|
+
const onStart = (e) => {
|
|
35
|
+
if (!window.matchMedia(PHONE).matches || e.touches.length !== 1) return;
|
|
36
|
+
sheet = sheetOf(el);
|
|
37
|
+
const scroller = scrollerAt(e.target, sheet);
|
|
38
|
+
armed = !scroller || scroller.scrollTop <= 0;
|
|
39
|
+
if (!armed) return;
|
|
40
|
+
startY = e.touches[0].clientY;
|
|
41
|
+
startT = performance.now();
|
|
42
|
+
dy = 0;
|
|
43
|
+
dragging = false;
|
|
44
|
+
};
|
|
45
|
+
const onMove = (e) => {
|
|
46
|
+
if (!armed || !sheet) return;
|
|
47
|
+
const delta = e.touches[0].clientY - startY;
|
|
48
|
+
if (!dragging) {
|
|
49
|
+
if (delta < 6) {
|
|
50
|
+
if (delta < -6) armed = false;
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
dragging = true;
|
|
54
|
+
sheet.style.transition = "none";
|
|
55
|
+
}
|
|
56
|
+
dy = Math.max(0, delta);
|
|
57
|
+
sheet.style.transform = `translateY(${dy}px)`;
|
|
58
|
+
if (e.cancelable) e.preventDefault();
|
|
59
|
+
};
|
|
60
|
+
const onEnd = () => {
|
|
61
|
+
if (!armed || !sheet || !dragging) {
|
|
62
|
+
armed = false;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
armed = false;
|
|
66
|
+
dragging = false;
|
|
67
|
+
const height = sheet.getBoundingClientRect().height || window.innerHeight;
|
|
68
|
+
if (shouldClose(dy, performance.now() - startT, height)) {
|
|
69
|
+
const s = sheet;
|
|
70
|
+
s.style.transition = "transform 180ms ease-in";
|
|
71
|
+
s.style.transform = "translateY(100%)";
|
|
72
|
+
window.setTimeout(() => {
|
|
73
|
+
onClose();
|
|
74
|
+
window.setTimeout(() => {
|
|
75
|
+
s.style.transition = "";
|
|
76
|
+
s.style.transform = "";
|
|
77
|
+
}, 350);
|
|
78
|
+
}, 170);
|
|
79
|
+
} else {
|
|
80
|
+
reset(true);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
const host = () => sheetOf(el);
|
|
84
|
+
let bound = null;
|
|
85
|
+
const bind = () => {
|
|
86
|
+
bound = host();
|
|
87
|
+
bound.addEventListener("touchstart", onStart, { passive: true });
|
|
88
|
+
bound.addEventListener("touchmove", onMove, { passive: false });
|
|
89
|
+
bound.addEventListener("touchend", onEnd);
|
|
90
|
+
bound.addEventListener("touchcancel", onEnd);
|
|
91
|
+
};
|
|
92
|
+
bind();
|
|
93
|
+
return {
|
|
94
|
+
cleanup() {
|
|
95
|
+
if (!bound) return;
|
|
96
|
+
bound.removeEventListener("touchstart", onStart);
|
|
97
|
+
bound.removeEventListener("touchmove", onMove);
|
|
98
|
+
bound.removeEventListener("touchend", onEnd);
|
|
99
|
+
bound.removeEventListener("touchcancel", onEnd);
|
|
100
|
+
bound = null;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export const vSwipeClose = {
|
|
105
|
+
mounted(el, binding) {
|
|
106
|
+
el.__swipeHandler = binding.value;
|
|
107
|
+
requestAnimationFrame(() => {
|
|
108
|
+
el.__swipeClose = attachSwipeToClose(el, () => el.__swipeHandler?.());
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
updated(el, binding) {
|
|
112
|
+
el.__swipeHandler = binding.value;
|
|
113
|
+
},
|
|
114
|
+
beforeUnmount(el) {
|
|
115
|
+
el.__swipeClose?.cleanup();
|
|
116
|
+
delete el.__swipeClose;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XLSX and CSV writer for the list export (PE-1052, Michael 15.10.). Used where
|
|
3
|
+
* the app declares no Baseline IO export: the header's and the bulk bar's
|
|
4
|
+
* „Exportieren“ then write the file here — current view, all, or the
|
|
5
|
+
* selection, the visible columns in their order.
|
|
6
|
+
*
|
|
7
|
+
* No dependency. XLSX is a zip of five small XML files; a stored (uncompressed)
|
|
8
|
+
* zip is a valid one, and every spreadsheet program reads it. Pulling SheetJS
|
|
9
|
+
* into the shared package for one sheet of text would add 400 KB to every host
|
|
10
|
+
* that renders a DataTable.
|
|
11
|
+
*/
|
|
12
|
+
export type ExportCell = string | number | null | undefined;
|
|
13
|
+
export interface ExportSheet {
|
|
14
|
+
headers: string[];
|
|
15
|
+
rows: ExportCell[][];
|
|
16
|
+
/** Sheet tab name, cut to Excel's 31 characters. */
|
|
17
|
+
sheetName?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Semicolon-separated with a UTF-8 BOM: what German Excel opens by double
|
|
21
|
+
* click with umlauts and decimal commas intact. A comma-separated file opens
|
|
22
|
+
* there as one column.
|
|
23
|
+
*/
|
|
24
|
+
export declare function toCsv(sheet: ExportSheet, sep?: string): string;
|
|
25
|
+
/** A1-style column letters: 0 → A, 25 → Z, 26 → AA. */
|
|
26
|
+
export declare function columnLetter(index: number): string;
|
|
27
|
+
export declare function crc32(bytes: Uint8Array): number;
|
|
28
|
+
export declare function toXlsx(sheet: ExportSheet): Uint8Array;
|
|
29
|
+
/** „Produkte 2026-10-15“ → `Produkte-2026-10-15`: safe on every file system. */
|
|
30
|
+
export declare function exportFileName(base: string, ext: 'csv' | 'xlsx', now?: Date): string;
|
|
31
|
+
export declare function downloadExport(sheet: ExportSheet, format: 'csv' | 'xlsx', fileBase: string): void;
|