@dou-ui/dashboard 0.1.0-alpha.3 → 0.1.0-alpha.4
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/core/document.js +10 -1
- package/dist/core/document.js.map +1 -1
- package/dist/core/history.js +23 -0
- package/dist/core/history.js.map +1 -1
- package/dist/core/transaction.js +8 -2
- package/dist/core/transaction.js.map +1 -1
- package/dist/dashboard/comment-button.js +6 -0
- package/dist/dashboard/comment-button.js.map +1 -0
- package/dist/dashboard/comment-button.vue_vue_type_script_setup_true_lang.js +59 -0
- package/dist/dashboard/comment-button.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/comment-card.js +6 -0
- package/dist/dashboard/comment-card.js.map +1 -0
- package/dist/dashboard/comment-card.vue_vue_type_script_setup_true_lang.js +128 -0
- package/dist/dashboard/comment-card.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/dashboard/comments.js +144 -0
- package/dist/dashboard/comments.js.map +1 -0
- package/dist/dashboard/dashboard.js.map +1 -1
- package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js +107 -18
- package/dist/dashboard/dashboard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/dashboard/frame-context.js.map +1 -1
- package/dist/dashboard/widget-frame.js.map +1 -1
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js +10 -0
- package/dist/dashboard/widget-frame.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/locale.js +6 -0
- package/dist/locale.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/style.js +2 -3
- package/dist/types/core/document.d.ts +3 -2
- package/dist/types/core/history.d.ts +7 -1
- package/dist/types/core/transaction.d.ts +10 -1
- package/dist/types/core/types.d.ts +5 -0
- package/dist/types/dashboard/comment-button.vue.d.ts +15 -0
- package/dist/types/dashboard/comment-card.vue.d.ts +13 -0
- package/dist/types/dashboard/comments.d.ts +44 -0
- package/dist/types/dashboard/dashboard.vue.d.ts +10 -0
- package/dist/types/dashboard/frame-context.d.ts +2 -0
- package/dist/types/dashboard/types.d.ts +30 -0
- package/dist/types/index.d.ts +20 -1
- package/dist/types/locale.d.ts +4 -0
- package/package.json +8 -8
package/dist/locale.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface DashboardMessages {\n /** The grid layout's accessible name. */\n layout: string\n /** What an item of the grid is called by a screen reader. */\n item: string\n /** Read after an item's name while the layout can be edited. */\n itemHint: string\n /** An item that can't be moved: `{item}`. */\n locked: string\n /** An item's place: `{x}` `{y}` (from 1), `{w}` `{h}` (in columns and rows). */\n position: string\n /** An item's place when the grid has one column: `{n}` of `{count}` (from 1). */\n order: string\n /** An item picked up with the keyboard: `{item}` and `{position}`. */\n grabbed: string\n /** An item put down, with the keyboard or the pointer: `{item}` and `{position}`. */\n dropped: string\n /** A move or resize undone with Escape (or a drop outside the grid): `{item}`. */\n cancelled: string\n /** The handle in an item's corner. */\n resize: string\n /** The dashboard's accessible name. */\n dashboard: string\n /** The menu button in a widget's title bar. */\n widgetMenu: string\n /** Menu items. */\n settings: string\n fullscreen: string\n /** The menu of file types a widget's content can be exported as. */\n export: string\n /** A failed export, over the widget's content: `{name}` (the file), `{reason}`. */\n exportFailed: string\n /** Read out once the file is saved: `{name}`. */\n exported: string\n /** Why a widget can't be exported: it has no data, such as a chart without its fields. */\n nothingToExport: string\n duplicate: string\n remove: string\n /** The settings drawer's title: `{title}`. */\n settingsTitle: string\n /** The title field in the settings drawer. */\n titleField: string\n /** Read when a widget is added, copied or removed: `{item}`. */\n added: string\n removed: string\n /** A widget whose type isn't registered: `{type}`. */\n unknownType: string\n /** A widget's status. */\n loading: string\n error: string\n empty: string\n retry: string\n /** A dashboard without widgets, while editing. */\n emptyTitle: string\n emptyHint: string\n /** The list of widgets to add. */\n palette: string\n /** A widget in that list: `{label}`. */\n paletteItem: string\n /** In the title bar of a widget that set a filter: `{value}`. */\n filteredBy: string\n peerMoving: string\n peerResizing: string\n peerSettings: string\n /** The button clearing that filter: `{value}`. */\n clearFilter: string\n /** The filter bar's accessible name. */\n filterBar: string\n /** A filter set by a widget, in the filter bar: `{title}` and `{value}`. */\n linkedFilter: string\n /** Clears every filter. */\n clearFilters: string\n /** Settings of the built-in widgets. */\n source: string\n noSource: string\n field: string\n value: string\n prefix: string\n suffix: string\n precision: string\n trend: string\n delta: string\n /** The change under a number: `{value}`, e.g. `+12.5%`. */\n deltaText: string\n text: string\n textSize: string\n sizeSmall: string\n sizeMedium: string\n sizeLarge: string\n columns: string\n /** The title of a table column, while it has none: `{field}`. */\n columnTitle: string\n chartKind: string\n chartLine: string\n chartArea: string\n chartBar: string\n chartPie: string\n xField: string\n yFields: string\n stacked: string\n horizontal: string\n /** The filter set by clicking a chart. */\n chartFilter: string\n chartFilterHint: string\n /** Whether clicking a pivot table's cell filters the other widgets. */\n pivotFilter: string\n}\n\nconst zhCN: DashboardMessages = {\n layout: '网格布局',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向键移动、Shift 加方向键调整大小',\n locked: '{item} 已锁定,不能移动',\n position: '第 {x} 列第 {y} 行,宽 {w} 列,高 {h} 行',\n order: '第 {n} 个,共 {count} 个',\n grabbed: '已拿起 {item},{position}。方向键移动,Shift 加方向键调整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原处',\n resize: '调整大小',\n dashboard: '仪表盘',\n widgetMenu: '格子操作',\n settings: '设置',\n fullscreen: '全屏查看',\n export: '导出',\n exportFailed: '无法导出 {name}:{reason}',\n exported: '已导出 {name}',\n nothingToExport: '没有可导出的数据',\n duplicate: '复制一份',\n remove: '删除',\n settingsTitle: '{title}的设置',\n titleField: '标题',\n added: '已添加 {item}',\n removed: '已删除 {item}',\n unknownType: '没有注册类型为 {type} 的格子',\n loading: '加载中',\n error: '加载失败',\n empty: '暂无数据',\n retry: '重试',\n emptyTitle: '还没有格子',\n emptyHint: '从列表里拖进来,或点一下添加',\n palette: '添加格子',\n paletteItem: '添加{label}',\n filteredBy: '已按 {value} 筛选',\n peerMoving: '{name} 正在移动',\n peerResizing: '{name} 正在调整大小',\n peerSettings: '{name} 正在修改设置',\n clearFilter: '清除筛选:{value}',\n filterBar: '筛选',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除筛选',\n source: '数据源',\n noSource: '不使用数据源',\n field: '字段',\n value: '数值',\n prefix: '前缀',\n suffix: '后缀',\n precision: '小数位数',\n trend: '迷你图字段',\n delta: '变化率字段',\n deltaText: '较上期 {value}',\n text: '文字',\n textSize: '字号',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '列',\n columnTitle: '{field} 的标题',\n chartKind: '图表',\n chartLine: '折线图',\n chartArea: '面积图',\n chartBar: '柱状图',\n chartPie: '饼图',\n xField: '分类或时间',\n yFields: '数值',\n stacked: '堆叠',\n horizontal: '横向',\n chartFilter: '点击时筛选',\n chartFilterHint: '点图表里的一项时,用这个名字筛选其他格子;留空则不筛选',\n pivotFilter: '点击单元格时,按它所在的分组筛选其他格子',\n}\n\nconst zhTW: DashboardMessages = {\n layout: '網格版面',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向鍵移動、Shift 加方向鍵調整大小',\n locked: '{item} 已鎖定,無法移動',\n position: '第 {x} 欄第 {y} 列,寬 {w} 欄,高 {h} 列',\n order: '第 {n} 個,共 {count} 個',\n grabbed: '已拿起 {item},{position}。方向鍵移動,Shift 加方向鍵調整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原處',\n resize: '調整大小',\n dashboard: '儀表板',\n widgetMenu: '格子操作',\n settings: '設定',\n fullscreen: '全螢幕檢視',\n export: '匯出',\n exportFailed: '無法匯出 {name}:{reason}',\n exported: '已匯出 {name}',\n nothingToExport: '沒有可匯出的資料',\n duplicate: '複製一份',\n remove: '刪除',\n settingsTitle: '{title}的設定',\n titleField: '標題',\n added: '已新增 {item}',\n removed: '已刪除 {item}',\n unknownType: '沒有註冊類型為 {type} 的格子',\n loading: '載入中',\n error: '載入失敗',\n empty: '暫無資料',\n retry: '重試',\n emptyTitle: '還沒有格子',\n emptyHint: '從清單拖進來,或點一下新增',\n palette: '新增格子',\n paletteItem: '新增{label}',\n filteredBy: '已按 {value} 篩選',\n peerMoving: '{name} 正在移動',\n peerResizing: '{name} 正在調整大小',\n peerSettings: '{name} 正在修改設定',\n clearFilter: '清除篩選:{value}',\n filterBar: '篩選',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除篩選',\n source: '資料來源',\n noSource: '不使用資料來源',\n field: '欄位',\n value: '數值',\n prefix: '前綴',\n suffix: '後綴',\n precision: '小數位數',\n trend: '迷你圖欄位',\n delta: '變化率欄位',\n deltaText: '較上期 {value}',\n text: '文字',\n textSize: '字號',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '欄',\n columnTitle: '{field} 的標題',\n chartKind: '圖表',\n chartLine: '折線圖',\n chartArea: '面積圖',\n chartBar: '長條圖',\n chartPie: '圓餅圖',\n xField: '分類或時間',\n yFields: '數值',\n stacked: '堆疊',\n horizontal: '橫向',\n chartFilter: '點擊時篩選',\n chartFilterHint: '點圖表裡的一項時,用這個名字篩選其他格子;留空則不篩選',\n pivotFilter: '點擊儲存格時,依其所在的分組篩選其他格子',\n}\n\nconst en: DashboardMessages = {\n layout: 'Grid layout',\n item: 'tile',\n itemHint: 'Press Enter to pick up, then arrow keys to move and Shift with arrow keys to resize',\n locked: '{item} is locked and can’t be moved',\n position: 'column {x}, row {y}, {w} columns wide, {h} rows high',\n order: '{n} of {count}',\n grabbed:\n 'Picked up {item}, {position}. Arrow keys move, Shift with arrow keys resizes, Enter puts down, Escape cancels',\n dropped: 'Put down {item}, {position}',\n cancelled: 'Cancelled, {item} is back where it was',\n resize: 'Resize',\n dashboard: 'Dashboard',\n widgetMenu: 'Widget actions',\n settings: 'Settings',\n fullscreen: 'View full screen',\n export: 'Export',\n exportFailed: \"Couldn't export {name}: {reason}\",\n exported: 'Exported {name}',\n nothingToExport: 'There is no data to export',\n duplicate: 'Duplicate',\n remove: 'Remove',\n settingsTitle: '{title} settings',\n titleField: 'Title',\n added: 'Added {item}',\n removed: 'Removed {item}',\n unknownType: 'No widget type “{type}” is registered',\n loading: 'Loading',\n error: 'Couldn’t load',\n empty: 'No data',\n retry: 'Retry',\n emptyTitle: 'No widgets yet',\n emptyHint: 'Drag one in from the list, or click to add it',\n palette: 'Add widget',\n paletteItem: 'Add {label}',\n filteredBy: 'Filtered by {value}',\n peerMoving: '{name} is moving it',\n peerResizing: '{name} is resizing it',\n peerSettings: '{name} is changing its settings',\n clearFilter: 'Clear filter: {value}',\n filterBar: 'Filters',\n linkedFilter: '{title}: {value}',\n clearFilters: 'Clear filters',\n source: 'Source',\n noSource: 'No source',\n field: 'Field',\n value: 'Value',\n prefix: 'Prefix',\n suffix: 'Suffix',\n precision: 'Decimal places',\n trend: 'Sparkline field',\n delta: 'Change field',\n deltaText: '{value} vs. last period',\n text: 'Text',\n textSize: 'Size',\n sizeSmall: 'Small',\n sizeMedium: 'Medium',\n sizeLarge: 'Large',\n columns: 'Columns',\n columnTitle: 'Title of {field}',\n chartKind: 'Chart',\n chartLine: 'Line',\n chartArea: 'Area',\n chartBar: 'Bar',\n chartPie: 'Pie',\n xField: 'Category or time',\n yFields: 'Values',\n stacked: 'Stacked',\n horizontal: 'Horizontal',\n chartFilter: 'Filter on click',\n chartFilterHint:\n 'Clicking an item filters the other widgets by this name; leave empty to not filter',\n pivotFilter: 'Clicking a cell filters the other widgets by its groups',\n}\n\nexport const dashboardLocales: Record<string, DashboardMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type DashboardMessagesOverride = Partial<DashboardMessages>\n\n/**\n * The dashboard's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useDashboardMessages(\n override?: MaybeRefOrGetter<DashboardMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<DashboardMessages>(() => {\n const name = locale.value.name\n const base =\n dashboardLocales[name] ??\n dashboardLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface DashboardMessages {\n /** The grid layout's accessible name. */\n layout: string\n /** What an item of the grid is called by a screen reader. */\n item: string\n /** Read after an item's name while the layout can be edited. */\n itemHint: string\n /** An item that can't be moved: `{item}`. */\n locked: string\n /** An item's place: `{x}` `{y}` (from 1), `{w}` `{h}` (in columns and rows). */\n position: string\n /** An item's place when the grid has one column: `{n}` of `{count}` (from 1). */\n order: string\n /** An item picked up with the keyboard: `{item}` and `{position}`. */\n grabbed: string\n /** An item put down, with the keyboard or the pointer: `{item}` and `{position}`. */\n dropped: string\n /** A move or resize undone with Escape (or a drop outside the grid): `{item}`. */\n cancelled: string\n /** The handle in an item's corner. */\n resize: string\n /** The dashboard's accessible name. */\n dashboard: string\n /** The menu button in a widget's title bar. */\n widgetMenu: string\n /** Menu items. */\n settings: string\n fullscreen: string\n /** The menu of file types a widget's content can be exported as. */\n export: string\n /** A failed export, over the widget's content: `{name}` (the file), `{reason}`. */\n exportFailed: string\n /** Read out once the file is saved: `{name}`. */\n exported: string\n /** Why a widget can't be exported: it has no data, such as a chart without its fields. */\n nothingToExport: string\n duplicate: string\n remove: string\n /** The comment button and the card of a widget's discussions. */\n comment: string\n /** The comment button of a widget with discussions; `{count}` is how many are open. */\n comments: string\n /** The settings drawer's title: `{title}`. */\n settingsTitle: string\n /** The title field in the settings drawer. */\n titleField: string\n /** Read when a widget is added, copied or removed: `{item}`. */\n added: string\n removed: string\n /** A widget whose type isn't registered: `{type}`. */\n unknownType: string\n /** A widget's status. */\n loading: string\n error: string\n empty: string\n retry: string\n /** A dashboard without widgets, while editing. */\n emptyTitle: string\n emptyHint: string\n /** The list of widgets to add. */\n palette: string\n /** A widget in that list: `{label}`. */\n paletteItem: string\n /** In the title bar of a widget that set a filter: `{value}`. */\n filteredBy: string\n peerMoving: string\n peerResizing: string\n peerSettings: string\n /** The button clearing that filter: `{value}`. */\n clearFilter: string\n /** The filter bar's accessible name. */\n filterBar: string\n /** A filter set by a widget, in the filter bar: `{title}` and `{value}`. */\n linkedFilter: string\n /** Clears every filter. */\n clearFilters: string\n /** Settings of the built-in widgets. */\n source: string\n noSource: string\n field: string\n value: string\n prefix: string\n suffix: string\n precision: string\n trend: string\n delta: string\n /** The change under a number: `{value}`, e.g. `+12.5%`. */\n deltaText: string\n text: string\n textSize: string\n sizeSmall: string\n sizeMedium: string\n sizeLarge: string\n columns: string\n /** The title of a table column, while it has none: `{field}`. */\n columnTitle: string\n chartKind: string\n chartLine: string\n chartArea: string\n chartBar: string\n chartPie: string\n xField: string\n yFields: string\n stacked: string\n horizontal: string\n /** The filter set by clicking a chart. */\n chartFilter: string\n chartFilterHint: string\n /** Whether clicking a pivot table's cell filters the other widgets. */\n pivotFilter: string\n}\n\nconst zhCN: DashboardMessages = {\n layout: '网格布局',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向键移动、Shift 加方向键调整大小',\n locked: '{item} 已锁定,不能移动',\n position: '第 {x} 列第 {y} 行,宽 {w} 列,高 {h} 行',\n order: '第 {n} 个,共 {count} 个',\n grabbed: '已拿起 {item},{position}。方向键移动,Shift 加方向键调整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原处',\n resize: '调整大小',\n dashboard: '仪表盘',\n widgetMenu: '格子操作',\n settings: '设置',\n fullscreen: '全屏查看',\n export: '导出',\n exportFailed: '无法导出 {name}:{reason}',\n exported: '已导出 {name}',\n nothingToExport: '没有可导出的数据',\n duplicate: '复制一份',\n remove: '删除',\n comment: '评论',\n comments: '{count} 条评论',\n settingsTitle: '{title}的设置',\n titleField: '标题',\n added: '已添加 {item}',\n removed: '已删除 {item}',\n unknownType: '没有注册类型为 {type} 的格子',\n loading: '加载中',\n error: '加载失败',\n empty: '暂无数据',\n retry: '重试',\n emptyTitle: '还没有格子',\n emptyHint: '从列表里拖进来,或点一下添加',\n palette: '添加格子',\n paletteItem: '添加{label}',\n filteredBy: '已按 {value} 筛选',\n peerMoving: '{name} 正在移动',\n peerResizing: '{name} 正在调整大小',\n peerSettings: '{name} 正在修改设置',\n clearFilter: '清除筛选:{value}',\n filterBar: '筛选',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除筛选',\n source: '数据源',\n noSource: '不使用数据源',\n field: '字段',\n value: '数值',\n prefix: '前缀',\n suffix: '后缀',\n precision: '小数位数',\n trend: '迷你图字段',\n delta: '变化率字段',\n deltaText: '较上期 {value}',\n text: '文字',\n textSize: '字号',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '列',\n columnTitle: '{field} 的标题',\n chartKind: '图表',\n chartLine: '折线图',\n chartArea: '面积图',\n chartBar: '柱状图',\n chartPie: '饼图',\n xField: '分类或时间',\n yFields: '数值',\n stacked: '堆叠',\n horizontal: '横向',\n chartFilter: '点击时筛选',\n chartFilterHint: '点图表里的一项时,用这个名字筛选其他格子;留空则不筛选',\n pivotFilter: '点击单元格时,按它所在的分组筛选其他格子',\n}\n\nconst zhTW: DashboardMessages = {\n layout: '網格版面',\n item: '格子',\n itemHint: '按 Enter 拿起,再用方向鍵移動、Shift 加方向鍵調整大小',\n locked: '{item} 已鎖定,無法移動',\n position: '第 {x} 欄第 {y} 列,寬 {w} 欄,高 {h} 列',\n order: '第 {n} 個,共 {count} 個',\n grabbed: '已拿起 {item},{position}。方向鍵移動,Shift 加方向鍵調整大小,Enter 放下,Esc 取消',\n dropped: '已放下 {item},{position}',\n cancelled: '已取消,{item} 回到原處',\n resize: '調整大小',\n dashboard: '儀表板',\n widgetMenu: '格子操作',\n settings: '設定',\n fullscreen: '全螢幕檢視',\n export: '匯出',\n exportFailed: '無法匯出 {name}:{reason}',\n exported: '已匯出 {name}',\n nothingToExport: '沒有可匯出的資料',\n duplicate: '複製一份',\n remove: '刪除',\n comment: '評論',\n comments: '{count} 則評論',\n settingsTitle: '{title}的設定',\n titleField: '標題',\n added: '已新增 {item}',\n removed: '已刪除 {item}',\n unknownType: '沒有註冊類型為 {type} 的格子',\n loading: '載入中',\n error: '載入失敗',\n empty: '暫無資料',\n retry: '重試',\n emptyTitle: '還沒有格子',\n emptyHint: '從清單拖進來,或點一下新增',\n palette: '新增格子',\n paletteItem: '新增{label}',\n filteredBy: '已按 {value} 篩選',\n peerMoving: '{name} 正在移動',\n peerResizing: '{name} 正在調整大小',\n peerSettings: '{name} 正在修改設定',\n clearFilter: '清除篩選:{value}',\n filterBar: '篩選',\n linkedFilter: '{title}:{value}',\n clearFilters: '清除篩選',\n source: '資料來源',\n noSource: '不使用資料來源',\n field: '欄位',\n value: '數值',\n prefix: '前綴',\n suffix: '後綴',\n precision: '小數位數',\n trend: '迷你圖欄位',\n delta: '變化率欄位',\n deltaText: '較上期 {value}',\n text: '文字',\n textSize: '字號',\n sizeSmall: '小',\n sizeMedium: '中',\n sizeLarge: '大',\n columns: '欄',\n columnTitle: '{field} 的標題',\n chartKind: '圖表',\n chartLine: '折線圖',\n chartArea: '面積圖',\n chartBar: '長條圖',\n chartPie: '圓餅圖',\n xField: '分類或時間',\n yFields: '數值',\n stacked: '堆疊',\n horizontal: '橫向',\n chartFilter: '點擊時篩選',\n chartFilterHint: '點圖表裡的一項時,用這個名字篩選其他格子;留空則不篩選',\n pivotFilter: '點擊儲存格時,依其所在的分組篩選其他格子',\n}\n\nconst en: DashboardMessages = {\n layout: 'Grid layout',\n item: 'tile',\n itemHint: 'Press Enter to pick up, then arrow keys to move and Shift with arrow keys to resize',\n locked: '{item} is locked and can’t be moved',\n position: 'column {x}, row {y}, {w} columns wide, {h} rows high',\n order: '{n} of {count}',\n grabbed:\n 'Picked up {item}, {position}. Arrow keys move, Shift with arrow keys resizes, Enter puts down, Escape cancels',\n dropped: 'Put down {item}, {position}',\n cancelled: 'Cancelled, {item} is back where it was',\n resize: 'Resize',\n dashboard: 'Dashboard',\n widgetMenu: 'Widget actions',\n settings: 'Settings',\n fullscreen: 'View full screen',\n export: 'Export',\n exportFailed: \"Couldn't export {name}: {reason}\",\n exported: 'Exported {name}',\n nothingToExport: 'There is no data to export',\n duplicate: 'Duplicate',\n remove: 'Remove',\n comment: 'Comment',\n comments: '{count} comments',\n settingsTitle: '{title} settings',\n titleField: 'Title',\n added: 'Added {item}',\n removed: 'Removed {item}',\n unknownType: 'No widget type “{type}” is registered',\n loading: 'Loading',\n error: 'Couldn’t load',\n empty: 'No data',\n retry: 'Retry',\n emptyTitle: 'No widgets yet',\n emptyHint: 'Drag one in from the list, or click to add it',\n palette: 'Add widget',\n paletteItem: 'Add {label}',\n filteredBy: 'Filtered by {value}',\n peerMoving: '{name} is moving it',\n peerResizing: '{name} is resizing it',\n peerSettings: '{name} is changing its settings',\n clearFilter: 'Clear filter: {value}',\n filterBar: 'Filters',\n linkedFilter: '{title}: {value}',\n clearFilters: 'Clear filters',\n source: 'Source',\n noSource: 'No source',\n field: 'Field',\n value: 'Value',\n prefix: 'Prefix',\n suffix: 'Suffix',\n precision: 'Decimal places',\n trend: 'Sparkline field',\n delta: 'Change field',\n deltaText: '{value} vs. last period',\n text: 'Text',\n textSize: 'Size',\n sizeSmall: 'Small',\n sizeMedium: 'Medium',\n sizeLarge: 'Large',\n columns: 'Columns',\n columnTitle: 'Title of {field}',\n chartKind: 'Chart',\n chartLine: 'Line',\n chartArea: 'Area',\n chartBar: 'Bar',\n chartPie: 'Pie',\n xField: 'Category or time',\n yFields: 'Values',\n stacked: 'Stacked',\n horizontal: 'Horizontal',\n chartFilter: 'Filter on click',\n chartFilterHint:\n 'Clicking an item filters the other widgets by this name; leave empty to not filter',\n pivotFilter: 'Clicking a cell filters the other widgets by its groups',\n}\n\nexport const dashboardLocales: Record<string, DashboardMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type DashboardMessagesOverride = Partial<DashboardMessages>\n\n/**\n * The dashboard's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useDashboardMessages(\n override?: MaybeRefOrGetter<DashboardMessagesOverride | undefined>,\n) {\n const { locale } = useLocale()\n return computed<DashboardMessages>(() => {\n const name = locale.value.name\n const base =\n dashboardLocales[name] ??\n dashboardLocales[name.split('-')[0]!] ??\n (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":"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"}
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
@layer dou.components{.dou-grid-layout{--dou-grid-item-radius:var(--dou-radius-container);--dou-grid-col:calc((100cqw - (var(--dou-grid-columns) - 1)*var(--dou-grid-gap-x))/var(--dou-grid-columns));position:relative;box-sizing:border-box;height:calc(var(--dou-grid-rows)*var(--dou-grid-row) + max(var(--dou-grid-rows) - 1,0)*var(--dou-grid-gap-y));container-type:inline-size;width:100%;min-width:0}.dou-grid-layout.is-pointer-dragging{cursor:grabbing}.dou-grid-layout.is-resizing{cursor:nwse-resize}.dou-grid-layout__item,.dou-grid-layout__placeholder{position:absolute;box-sizing:border-box;width:calc(var(--dou-grid-w)*var(--dou-grid-col) + (var(--dou-grid-w) - 1)*var(--dou-grid-gap-x) + var(--dou-grid-dw,0px));height:calc(var(--dou-grid-h)*var(--dou-grid-row) + (var(--dou-grid-h) - 1)*var(--dou-grid-gap-y) + var(--dou-grid-dh,0px));border-radius:var(--dou-grid-item-radius);transform:translate(calc(var(--dou-grid-x)*(var(--dou-grid-col) + var(--dou-grid-gap-x)) + var(--dou-grid-dx,0px)),calc(var(--dou-grid-y)*(var(--dou-grid-row) + var(--dou-grid-gap-y)) + var(--dou-grid-dy,0px)));top:0;left:0}.dou-grid-layout__item{display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);outline:none;min-width:0}.dou-grid-layout__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-grid-layout.is-editable .dou-grid-layout__item.is-movable{user-select:none;-webkit-touch-callout:none}.dou-grid-layout.is-editable:not(:-webkit-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:-moz-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:is(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-arranging .dou-grid-layout__item{transition:transform var(--dou-motion-duration-normal)var(--dou-motion-easing)}.dou-grid-layout__item.is-dragging,.dou-grid-layout__item.is-resizing{z-index:2;box-shadow:var(--dou-shadow-lg)}.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-dragging,.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-resizing{transition:none}.dou-grid-layout__placeholder{z-index:1;border:1px dashed var(--dou-color-border-strong);background-color:color-mix(in oklab,var(--dou-color-text)4%,transparent);pointer-events:none}.dou-grid-layout.is-arranging .dou-grid-layout__placeholder{transition:transform var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-grid-layout__resize{position:absolute;z-index:1;touch-action:none}.dou-grid-layout__resize.is-e{cursor:ew-resize;width:8px;top:8px;bottom:16px;right:-4px}.dou-grid-layout__resize.is-s{cursor:ns-resize;height:8px;bottom:-4px;left:8px;right:16px}.dou-grid-layout__resize.is-se{cursor:nwse-resize;opacity:0;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing);width:20px;height:20px;bottom:0;right:0}.dou-grid-layout__resize.is-se:after{position:absolute;box-sizing:border-box;border-right:2px solid var(--dou-color-text-tertiary);border-bottom:2px solid var(--dou-color-text-tertiary);content:"";border-bottom-right-radius:4px;width:8px;height:8px;bottom:5px;right:5px}.dou-grid-layout__item:hover>.dou-grid-layout__resize.is-se,.dou-grid-layout__item.is-resizing>.dou-grid-layout__resize.is-se{opacity:1}.dou-grid-layout__item:focus-visible>.dou-grid-layout__resize.is-se{opacity:1}@media (pointer:coarse){.dou-grid-layout__resize.is-se{opacity:1;width:32px;height:32px}}.dou-grid-layout__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}}@layer dou.components{.dou-dashboard{position:relative;outline:none;min-width:0}.dou-dashboard__widget{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:inherit;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);overflow:hidden;flex-direction:column;min-width:0;min-height:0}.dou-grid-layout__item.is-dragging>.dou-dashboard__widget,.dou-grid-layout__item.is-resizing>.dou-dashboard__widget{border-color:var(--dou-color-border-strong)}.dou-dashboard__widget.has-peers{outline:1.5px solid var(--dou-dashboard-peer-color);outline-offset:2px}.dou-dashboard__peers{position:absolute;z-index:1;display:flex;overflow:hidden;pointer-events:none;gap:4px;max-width:calc(100% - 24px);margin-bottom:-10px;bottom:100%;left:12px}.dou-dashboard__peer{background-color:var(--dou-dashboard-peer-color);color:oklch(from var(--dou-dashboard-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;flex:none;padding:0 6px;line-height:18px}.dou-dashboard__peer.is-focus{animation:dou-dashboard-peer-name var(--dou-motion-duration-fast)var(--dou-motion-easing)3s forwards}.dou-dashboard__header{display:flex;flex:none;align-items: center;gap:8px;height:40px;padding:0 8px 0 16px}.dou-dashboard__title{overflow:hidden;color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:min(6em,40%)}.dou-dashboard__title .dou-editable__view{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:inherit}.dou-dashboard__links{display:flex;overflow:hidden;flex:0 auto;gap:4px;min-width:0;max-width:60%}.dou-dashboard__links .dou-tag{min-width:0;max-width:100%}.dou-dashboard__links .dou-tag__label{overflow-x:clip;white-space:nowrap;text-overflow:ellipsis;min-width:0}.dou-dashboard__actions{display:flex;color:var(--dou-color-text-tertiary);flex:none;align-items: center;gap:2px}.dou-dashboard__export-error{flex:none;padding:0 8px 8px}.dou-dashboard__export-error .dou-alert__description{overflow-y:auto;max-height:4.5lh}.dou-dashboard__body{position:relative;flex:auto;min-width:0;min-height:0;padding:0 16px 16px}.dou-dashboard__body.is-fullscreen{height:100%;padding:0}.dou-dashboard__content{min-width:0;height:100%}.dou-dashboard__notice{display:grid;color:var(--dou-color-text-tertiary);text-align:center;place-items: center;height:100%}.dou-dashboard__status{position:absolute;display:flex;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:8px;padding:0 16px 16px;inset:0}.dou-dashboard__status.is-loading{background-color:color-mix(in oklab,var(--dou-color-bg-surface)72%,transparent);animation:dou-dashboard-fade-in var(--dou-motion-duration-fast)var(--dou-motion-easing).12s both}.dou-dashboard__status-icon{color:var(--dou-color-danger);width:20px;height:20px}.dou-dashboard__empty{position:absolute;display:grid;border:1px dashed var(--dou-color-border);border-radius:var(--dou-radius-container);pointer-events:none;place-items: center;inset:0}.dou-dashboard__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-dashboard__settings{display:flex;flex-direction:column;gap:16px}.dou-dashboard__field{display:flex;flex-direction:column;gap:8px}.dou-dashboard__field-hint{color:var(--dou-color-text-tertiary);font-size:var(--dou-font-size-sm)}.dou-dashboard__field-row{display:flex;flex-wrap:wrap;gap:16px}.dou-dashboard__field-row>.dou-dashboard__field{flex:120px;min-width:0}.dou-dashboard__columns{display:flex;flex-direction:column;gap:8px}.dou-dashboard__column{display:grid;grid-template-columns:minmax(0,1fr)minmax(0,1fr);align-items: center;gap:8px}.dou-dashboard__field-label{color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium)}@keyframes dou-dashboard-fade-in{0%{opacity:0}}.dou-dashboard-palette{display:flex;list-style:none;flex-direction:column;gap:8px;margin:0;padding:0}.dou-dashboard-palette.is-horizontal{flex-flow:wrap}.dou-dashboard-palette>li{margin:0}.dou-dashboard-palette__item{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:var(--dou-font-size-sm);cursor:grab;user-select:none;-webkit-touch-callout:none;transition:border-color var(--dou-motion-duration-fast)var(--dou-motion-easing);align-items: center;gap:8px;width:100%;height:32px;padding:0 12px}.dou-dashboard-palette__item:hover:not(:disabled){border-color:var(--dou-color-border-strong)}.dou-dashboard-palette__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-dashboard-palette__item:disabled{color:var(--dou-color-text-tertiary);cursor:not-allowed}.dou-dashboard-palette__icon{color:var(--dou-color-text-secondary);flex:none;width:16px;height:16px}.dou-dashboard-palette__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dou-dashboard-filter{display:flex;flex-wrap:wrap;align-items: center;gap:8px 16px}.dou-dashboard-filter__field{display:flex;align-items: center;gap:8px;min-width:0}.dou-dashboard-filter__label{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;flex:none}.dou-dashboard-filter__control{width:144px;min-width:0}.dou-dashboard-filter__control.is-range{width:272px}.dou-dashboard-filter__extra{display:flex;align-items: center;gap:4px;margin-left:auto}@media (max-width:480px){.dou-dashboard-filter__field{flex:100%}.dou-dashboard-filter__label{width:4em}.dou-dashboard-filter__control,.dou-dashboard-filter__control.is-range{flex:auto;width:auto}}.dou-dashboard-stat{display:flex;container-type:inline-size;flex-direction:column;justify-content:space-between;gap:8px;height:100%}@container (width<=200px){.dou-dashboard-stat .dou-statistic{--dou-statistic-value-size:22px}}.dou-dashboard-stat__spark{flex:none;margin:0 -16px -16px}.dou-dashboard-text{overflow:auto;color:var(--dou-color-text);white-space:pre-wrap;overflow-wrap:anywhere;height:100%;line-height:1.6}.dou-dashboard-text.is-sm{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-dashboard-text.is-md{font-size:var(--dou-font-size-md)}.dou-dashboard-text.is-lg{font-size:var(--dou-font-size-lg);font-weight:var(--dou-font-weight-medium);line-height:1.4}.dou-dashboard.is-exporting .dou-dashboard__actions{display:none}.dou-dashboard.is-exporting .dou-dashboard__links .dou-tag__close{display:none}.dou-dashboard.is-exporting .dou-dashboard__export-error{display:none}.dou-dashboard.is-exporting .dou-dashboard__peers{display:none}.dou-dashboard.is-exporting .dou-grid-layout__resize{display:none}.dou-dashboard.is-exporting .dou-dashboard__live{display:none}.dou-dashboard.is-exporting .dou-grid-layout__item{outline:none}.dou-dashboard.is-exporting .dou-dashboard__widget{outline:none}@media print{.dou-dashboard{print-color-adjust:exact}.dou-dashboard__actions,.dou-dashboard__links .dou-tag__close,.dou-dashboard__export-error,.dou-dashboard__peers,.dou-grid-layout__resize,.dou-dashboard-filter__clear,.dou-dashboard-filter__extra{display:none}.dou-grid-layout__item{outline:none;break-inside:avoid}.dou-dashboard__widget{outline:none}}}@keyframes dou-dashboard-peer-name{to{opacity:0;visibility:hidden}}
|
|
1
|
+
@layer dou.components{.dou-grid-layout{--dou-grid-item-radius:var(--dou-radius-container);--dou-grid-col:calc((100cqw - (var(--dou-grid-columns) - 1)*var(--dou-grid-gap-x))/var(--dou-grid-columns));position:relative;box-sizing:border-box;height:calc(var(--dou-grid-rows)*var(--dou-grid-row) + max(var(--dou-grid-rows) - 1,0)*var(--dou-grid-gap-y));container-type:inline-size;width:100%;min-width:0}.dou-grid-layout.is-pointer-dragging{cursor:grabbing}.dou-grid-layout.is-resizing{cursor:nwse-resize}.dou-grid-layout__item,.dou-grid-layout__placeholder{position:absolute;box-sizing:border-box;width:calc(var(--dou-grid-w)*var(--dou-grid-col) + (var(--dou-grid-w) - 1)*var(--dou-grid-gap-x) + var(--dou-grid-dw,0px));height:calc(var(--dou-grid-h)*var(--dou-grid-row) + (var(--dou-grid-h) - 1)*var(--dou-grid-gap-y) + var(--dou-grid-dh,0px));border-radius:var(--dou-grid-item-radius);transform:translate(calc(var(--dou-grid-x)*(var(--dou-grid-col) + var(--dou-grid-gap-x)) + var(--dou-grid-dx,0px)),calc(var(--dou-grid-y)*(var(--dou-grid-row) + var(--dou-grid-gap-y)) + var(--dou-grid-dy,0px)));top:0;left:0}.dou-grid-layout__item{display:grid;grid-template:minmax(0,1fr)/minmax(0,1fr);outline:none;min-width:0}.dou-grid-layout__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-grid-layout.is-editable .dou-grid-layout__item.is-movable{user-select:none;-webkit-touch-callout:none}.dou-grid-layout.is-editable:not(:-webkit-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:-moz-any(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-editable:not(:is(.is-pointer-dragging,.has-handle)) .dou-grid-layout__item.is-movable,.dou-grid-layout.is-editable.has-handle:not(.is-pointer-dragging) .dou-grid-layout__item.is-movable .dou-grid-layout__handle{cursor:grab}.dou-grid-layout.is-arranging .dou-grid-layout__item{transition:transform var(--dou-motion-duration-normal)var(--dou-motion-easing)}.dou-grid-layout__item.is-dragging,.dou-grid-layout__item.is-resizing{z-index:2;box-shadow:var(--dou-shadow-lg)}.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-dragging,.dou-grid-layout.is-pointer-dragging .dou-grid-layout__item.is-resizing{transition:none}.dou-grid-layout__placeholder{z-index:1;border:1px dashed var(--dou-color-border-strong);background-color:color-mix(in oklab,var(--dou-color-text)4%,transparent);pointer-events:none}.dou-grid-layout.is-arranging .dou-grid-layout__placeholder{transition:transform var(--dou-motion-duration-fast)var(--dou-motion-easing)}.dou-grid-layout__resize{position:absolute;z-index:1;touch-action:none}.dou-grid-layout__resize.is-e{cursor:ew-resize;width:8px;top:8px;bottom:16px;right:-4px}.dou-grid-layout__resize.is-s{cursor:ns-resize;height:8px;bottom:-4px;left:8px;right:16px}.dou-grid-layout__resize.is-se{cursor:nwse-resize;opacity:0;transition:opacity var(--dou-motion-duration-fast)var(--dou-motion-easing);width:20px;height:20px;bottom:0;right:0}.dou-grid-layout__resize.is-se:after{position:absolute;box-sizing:border-box;border-right:2px solid var(--dou-color-text-tertiary);border-bottom:2px solid var(--dou-color-text-tertiary);content:"";border-bottom-right-radius:4px;width:8px;height:8px;bottom:5px;right:5px}.dou-grid-layout__item:hover>.dou-grid-layout__resize.is-se,.dou-grid-layout__item.is-resizing>.dou-grid-layout__resize.is-se{opacity:1}.dou-grid-layout__item:focus-visible>.dou-grid-layout__resize.is-se{opacity:1}@media (pointer:coarse){.dou-grid-layout__resize.is-se{opacity:1;width:32px;height:32px}}.dou-grid-layout__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}}@layer dou.components{.dou-dashboard{position:relative;outline:none;min-width:0}.dou-dashboard__widget{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:inherit;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);overflow:hidden;flex-direction:column;min-width:0;min-height:0}.dou-grid-layout__item.is-dragging>.dou-dashboard__widget,.dou-grid-layout__item.is-resizing>.dou-dashboard__widget{border-color:var(--dou-color-border-strong)}.dou-dashboard__widget.has-peers{outline:1.5px solid var(--dou-dashboard-peer-color);outline-offset:2px}.dou-dashboard__peers{position:absolute;z-index:1;display:flex;overflow:hidden;pointer-events:none;gap:4px;max-width:calc(100% - 24px);margin-bottom:-10px;bottom:100%;left:12px}.dou-dashboard__peer{background-color:var(--dou-dashboard-peer-color);color:oklch(from var(--dou-dashboard-peer-color)clamp(.2,(.66 - l)*100,.99)0 0);font-size:var(--dou-font-size-sm);white-space:nowrap;border-radius:4px;flex:none;padding:0 6px;line-height:18px}.dou-dashboard__peer.is-focus{animation:dou-dashboard-peer-name var(--dou-motion-duration-fast)var(--dou-motion-easing)3s forwards}.dou-dashboard__header{display:flex;flex:none;align-items: center;gap:8px;height:40px;padding:0 8px 0 16px}.dou-dashboard__title{overflow:hidden;color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium);text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:min(6em,40%)}.dou-dashboard__title .dou-editable__view{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:inherit}.dou-dashboard__links{display:flex;overflow:hidden;flex:0 auto;gap:4px;min-width:0;max-width:60%}.dou-dashboard__links .dou-tag{min-width:0;max-width:100%}.dou-dashboard__links .dou-tag__label{overflow-x:clip;white-space:nowrap;text-overflow:ellipsis;min-width:0}.dou-dashboard__actions{display:flex;color:var(--dou-color-text-tertiary);flex:none;align-items: center;gap:2px}.dou-dashboard__comment{font-variant-numeric:tabular-nums}.dou-dashboard__comment:not(.has-threads){color:var(--dou-color-text-secondary)}@media (pointer:coarse){.dou-dashboard__comment.has-threads:after{position:absolute;content:"";inset:min(0px,50% - 20px)}}.dou-dashboard__fullscreen{display:flex;flex-direction:column;height:100%;min-height:0}.dou-dashboard__fullscreen>.dou-dashboard__body.is-fullscreen{flex:1;min-height:0}.dou-dashboard__fullscreen-bar{display:flex;justify-content:flex-end;margin-bottom:8px}.dou-dashboard__comment-card{box-sizing:border-box;max-height:min(var(--dou-floating-available,100vh),480px,calc(100vh - 32px));overflow-y:auto;overscroll-behavior:contain;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-container);background-color:color-mix(in oklab,var(--dou-color-text)calc(4%*var(--dou-scheme-dark)),var(--dou-color-bg-surface));box-shadow:var(--dou-shadow-md);width:min(340px,100vw - 32px);padding:12px}.dou-dashboard__comment-card>.dou-comment-thread+.dou-comment-thread{border-top:1px solid var(--dou-color-border-subtle);margin-top:12px;padding-top:12px}.dou-dashboard__export-error{flex:none;padding:0 8px 8px}.dou-dashboard__export-error .dou-alert__description{overflow-y:auto;max-height:4.5lh}.dou-dashboard__body{position:relative;flex:auto;min-width:0;min-height:0;padding:0 16px 16px}.dou-dashboard__body.is-fullscreen{height:100%;padding:0}.dou-dashboard__content{min-width:0;height:100%}.dou-dashboard__notice{display:grid;color:var(--dou-color-text-tertiary);text-align:center;place-items: center;height:100%}.dou-dashboard__status{position:absolute;display:flex;background-color:var(--dou-color-bg-surface);color:var(--dou-color-text-secondary);text-align:center;flex-direction:column;justify-content:center;align-items: center;gap:8px;padding:0 16px 16px;inset:0}.dou-dashboard__status.is-loading{background-color:color-mix(in oklab,var(--dou-color-bg-surface)72%,transparent);animation:dou-dashboard-fade-in var(--dou-motion-duration-fast)var(--dou-motion-easing).12s both}.dou-dashboard__status-icon{color:var(--dou-color-danger);width:20px;height:20px}.dou-dashboard__empty{position:absolute;display:grid;border:1px dashed var(--dou-color-border);border-radius:var(--dou-radius-container);pointer-events:none;place-items: center;inset:0}.dou-dashboard__live{position:absolute;overflow:hidden;clip-path:inset(50%);white-space:nowrap;width:1px;height:1px}.dou-dashboard__settings{display:flex;flex-direction:column;gap:16px}.dou-dashboard__field{display:flex;flex-direction:column;gap:8px}.dou-dashboard__field-hint{color:var(--dou-color-text-tertiary);font-size:var(--dou-font-size-sm)}.dou-dashboard__field-row{display:flex;flex-wrap:wrap;gap:16px}.dou-dashboard__field-row>.dou-dashboard__field{flex:120px;min-width:0}.dou-dashboard__columns{display:flex;flex-direction:column;gap:8px}.dou-dashboard__column{display:grid;grid-template-columns:minmax(0,1fr)minmax(0,1fr);align-items: center;gap:8px}.dou-dashboard__field-label{color:var(--dou-color-text);font-size:var(--dou-font-size-sm);font-weight:var(--dou-font-weight-medium)}@keyframes dou-dashboard-fade-in{0%{opacity:0}}.dou-dashboard-palette{display:flex;list-style:none;flex-direction:column;gap:8px;margin:0;padding:0}.dou-dashboard-palette.is-horizontal{flex-flow:wrap}.dou-dashboard-palette>li{margin:0}.dou-dashboard-palette__item{display:flex;box-sizing:border-box;border:1px solid var(--dou-color-border);border-radius:var(--dou-radius-control);background-color:var(--dou-color-bg-surface);color:var(--dou-color-text);font:inherit;font-size:var(--dou-font-size-sm);cursor:grab;user-select:none;-webkit-touch-callout:none;transition:border-color var(--dou-motion-duration-fast)var(--dou-motion-easing);align-items: center;gap:8px;width:100%;height:32px;padding:0 12px}.dou-dashboard-palette__item:hover:not(:disabled){border-color:var(--dou-color-border-strong)}.dou-dashboard-palette__item:focus-visible{outline:2px solid var(--dou-color-focus);outline-offset:2px}.dou-dashboard-palette__item:disabled{color:var(--dou-color-text-tertiary);cursor:not-allowed}.dou-dashboard-palette__icon{color:var(--dou-color-text-secondary);flex:none;width:16px;height:16px}.dou-dashboard-palette__label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dou-dashboard-filter{display:flex;flex-wrap:wrap;align-items: center;gap:8px 16px}.dou-dashboard-filter__field{display:flex;align-items: center;gap:8px;min-width:0}.dou-dashboard-filter__label{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm);white-space:nowrap;flex:none}.dou-dashboard-filter__control{width:144px;min-width:0}.dou-dashboard-filter__control.is-range{width:272px}.dou-dashboard-filter__extra{display:flex;align-items: center;gap:4px;margin-left:auto}@media (max-width:480px){.dou-dashboard-filter__field{flex:100%}.dou-dashboard-filter__label{width:4em}.dou-dashboard-filter__control,.dou-dashboard-filter__control.is-range{flex:auto;width:auto}}.dou-dashboard-stat{display:flex;container-type:inline-size;flex-direction:column;justify-content:space-between;gap:8px;height:100%}@container (width<=200px){.dou-dashboard-stat .dou-statistic{--dou-statistic-value-size:22px}}.dou-dashboard-stat__spark{flex:none;margin:0 -16px -16px}.dou-dashboard-text{overflow:auto;color:var(--dou-color-text);white-space:pre-wrap;overflow-wrap:anywhere;height:100%;line-height:1.6}.dou-dashboard-text.is-sm{color:var(--dou-color-text-secondary);font-size:var(--dou-font-size-sm)}.dou-dashboard-text.is-md{font-size:var(--dou-font-size-md)}.dou-dashboard-text.is-lg{font-size:var(--dou-font-size-lg);font-weight:var(--dou-font-weight-medium);line-height:1.4}.dou-dashboard.is-exporting .dou-dashboard__actions{display:none}.dou-dashboard.is-exporting .dou-dashboard__links .dou-tag__close{display:none}.dou-dashboard.is-exporting .dou-dashboard__export-error{display:none}.dou-dashboard.is-exporting .dou-dashboard__peers{display:none}.dou-dashboard.is-exporting .dou-grid-layout__resize{display:none}.dou-dashboard.is-exporting .dou-dashboard__live{display:none}.dou-dashboard.is-exporting .dou-grid-layout__item{outline:none}.dou-dashboard.is-exporting .dou-dashboard__widget{outline:none}@media print{.dou-dashboard{print-color-adjust:exact}.dou-dashboard__actions,.dou-dashboard__links .dou-tag__close,.dou-dashboard__export-error,.dou-dashboard__peers,.dou-grid-layout__resize,.dou-dashboard-filter__clear,.dou-dashboard-filter__extra{display:none}.dou-grid-layout__item{outline:none;break-inside:avoid}.dou-dashboard__widget{outline:none}}}@keyframes dou-dashboard-peer-name{to{opacity:0;visibility:hidden}}
|
package/dist/style.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import 'dou-ui/components/alert/style'
|
|
2
|
+
import 'dou-ui/components/autocomplete/style'
|
|
3
|
+
import 'dou-ui/components/comment-thread/style'
|
|
2
4
|
import 'dou-ui/components/date-picker/style'
|
|
3
5
|
import 'dou-ui/components/dialog/style'
|
|
4
6
|
import 'dou-ui/components/drawer/style'
|
|
5
7
|
import 'dou-ui/components/editable/style'
|
|
6
|
-
import 'dou-ui/components/dropdown/style'
|
|
7
8
|
import 'dou-ui/components/grid/style'
|
|
8
9
|
import 'dou-ui/components/input-number/style'
|
|
9
10
|
import 'dou-ui/components/segmented-control/style'
|
|
@@ -12,7 +13,5 @@ import 'dou-ui/components/sparkline/style'
|
|
|
12
13
|
import 'dou-ui/components/statistic/style'
|
|
13
14
|
import 'dou-ui/components/switch/style'
|
|
14
15
|
import 'dou-ui/components/table/style'
|
|
15
|
-
import 'dou-ui/components/textarea/style'
|
|
16
|
-
import 'dou-ui/components/tooltip/style'
|
|
17
16
|
import '@dou-ui/sheet/style'
|
|
18
17
|
import './style.css'
|
|
@@ -3,7 +3,7 @@ import type { DashboardDocument, DashboardPlace } from './types';
|
|
|
3
3
|
/** A dashboard with no widgets, the `v-model` when none is bound. */
|
|
4
4
|
export declare const emptyDocument: () => DashboardDocument;
|
|
5
5
|
export interface DocumentProblem {
|
|
6
|
-
code: 'version' | 'shape' | 'duplicate-id' | 'missing-id' | 'unknown-type' | 'bad-place';
|
|
6
|
+
code: 'version' | 'shape' | 'duplicate-id' | 'missing-id' | 'unknown-type' | 'bad-place' | 'bad-comments';
|
|
7
7
|
/** The widget at fault; none for the document's own problems. */
|
|
8
8
|
widgetId?: string;
|
|
9
9
|
/** Where the problem is, e.g. `widgets[2]` or `widgets[2].place.lg`; `version` for the version. */
|
|
@@ -22,7 +22,8 @@ export declare function isDashboardPlace(value: unknown): value is DashboardPlac
|
|
|
22
22
|
/**
|
|
23
23
|
* The problems of a dashboard document, before it is saved or shown: an
|
|
24
24
|
* unknown version, widgets without an id or sharing one, types nobody
|
|
25
|
-
* registered,
|
|
25
|
+
* registered, places that are not whole cells, and `comments` that are
|
|
26
|
+
* not a list of thread ids.
|
|
26
27
|
*/
|
|
27
28
|
export declare function checkDocument(document: DashboardDocument, options?: CheckDocumentOptions): DocumentProblem[];
|
|
28
29
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DashboardTransaction } from './transaction';
|
|
2
|
-
import type { DashboardDocument } from './types';
|
|
2
|
+
import type { DashboardDocument, DashboardWidget } from './types';
|
|
3
3
|
/** Undo and redo of a dashboard: the steps of each transaction and the steps that undo them. */
|
|
4
4
|
export declare class DashboardHistory {
|
|
5
5
|
private depth;
|
|
@@ -11,5 +11,11 @@ export declare class DashboardHistory {
|
|
|
11
11
|
record(tr: DashboardTransaction, now?: number): void;
|
|
12
12
|
undo(document: DashboardDocument): DashboardTransaction | null;
|
|
13
13
|
redo(document: DashboardDocument): DashboardTransaction | null;
|
|
14
|
+
/**
|
|
15
|
+
* Gives a change kept out of undo to the widget as undo and redo bring it
|
|
16
|
+
* back, too: comments started on a widget stay on it when its adding is
|
|
17
|
+
* undone and redone.
|
|
18
|
+
*/
|
|
19
|
+
carry(id: string, patch: Partial<DashboardWidget>): void;
|
|
14
20
|
clear(): void;
|
|
15
21
|
}
|
|
@@ -31,6 +31,10 @@ export interface DashboardTransactionMeta {
|
|
|
31
31
|
origin?: string;
|
|
32
32
|
[key: string]: unknown;
|
|
33
33
|
}
|
|
34
|
+
export interface ReplaceWidgetsOptions {
|
|
35
|
+
/** A widget that stays keeps its `comments`; `true` by default. */
|
|
36
|
+
keepComments?: boolean;
|
|
37
|
+
}
|
|
34
38
|
/** Deep equality of JSON values; key order doesn't matter. */
|
|
35
39
|
export declare function sameValue(a: unknown, b: unknown): boolean;
|
|
36
40
|
/**
|
|
@@ -82,5 +86,10 @@ export declare const cloneJson: <T>(value: T) => T;
|
|
|
82
86
|
* that are gone are removed, new ones added, changed keys updated, and the
|
|
83
87
|
* fewest widgets taken out and put back to match the order. Unchanged
|
|
84
88
|
* widgets keep their objects.
|
|
89
|
+
*
|
|
90
|
+
* A widget that stays keeps its `comments`, the discussions on it, as they
|
|
91
|
+
* are: restoring a default layout doesn't take them off. Pass
|
|
92
|
+
* `{ keepComments: false }` for the exact steps, e.g. to apply a shared
|
|
93
|
+
* document.
|
|
85
94
|
*/
|
|
86
|
-
export declare function replaceWidgets(tr: DashboardTransaction, next: DashboardDocument): DashboardTransaction;
|
|
95
|
+
export declare function replaceWidgets(tr: DashboardTransaction, next: DashboardDocument, options?: ReplaceWidgetsOptions): DashboardTransaction;
|
|
@@ -19,6 +19,11 @@ export interface DashboardWidget<P extends object = Record<string, unknown>> {
|
|
|
19
19
|
* main one; a narrower breakpoint without one is laid out from it.
|
|
20
20
|
*/
|
|
21
21
|
place: Partial<Record<string, DashboardPlace>>;
|
|
22
|
+
/**
|
|
23
|
+
* The ids of the comment threads about this widget, see the dashboard's
|
|
24
|
+
* `comments`. Kept when the widget is removed and brought back by undo.
|
|
25
|
+
*/
|
|
26
|
+
comments?: string[];
|
|
22
27
|
}
|
|
23
28
|
/** A dashboard: a JSON document the app saves and loads itself. */
|
|
24
29
|
export interface DashboardDocument {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Placement } from 'dou-ui';
|
|
2
|
+
import { type DashboardMessages } from '../locale';
|
|
3
|
+
import type { DashboardComments } from './comments';
|
|
4
|
+
type __VLS_Props = {
|
|
5
|
+
id: string;
|
|
6
|
+
comments: DashboardComments;
|
|
7
|
+
messages: DashboardMessages;
|
|
8
|
+
/** Where the tooltip goes: in the full screen view, clear of the dialog's close button above. */
|
|
9
|
+
tooltipPlacement?: Placement;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
12
|
+
tooltipPlacement: Placement;
|
|
13
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DashboardMessages } from '../locale';
|
|
2
|
+
import type { DashboardComments } from './comments';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
comments: DashboardComments;
|
|
5
|
+
messages: DashboardMessages;
|
|
6
|
+
/** The comment button of a widget, to put the card by and give the focus back to. */
|
|
7
|
+
buttonOf: (widget: string) => HTMLElement | null;
|
|
8
|
+
/** Where the card goes: the button, or the widget while its button isn't drawn yet. */
|
|
9
|
+
placeOf: (widget: string) => HTMLElement | null;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type CommentAction, type CommentThread } from 'dou-ui';
|
|
2
|
+
import { type ComputedRef, type Ref } from 'vue';
|
|
3
|
+
import type { DashboardStep, DashboardTransactionMeta } from '../core/transaction';
|
|
4
|
+
import type { DashboardDocument } from '../core/types';
|
|
5
|
+
import type { DashboardCommentAnchor, DashboardEmits, DashboardProps } from './types';
|
|
6
|
+
type Emit = <K extends keyof DashboardEmits>(event: K, ...args: DashboardEmits[K]) => void;
|
|
7
|
+
/** The thread ids on a widget; nothing when a hand-written document has something else there. */
|
|
8
|
+
export declare const commentIdsOf: (widget: {
|
|
9
|
+
comments?: unknown;
|
|
10
|
+
}) => string[];
|
|
11
|
+
/**
|
|
12
|
+
* The comments of a dashboard: which widget each thread is about, the thread
|
|
13
|
+
* open now, and the one being started.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useDashboardComments(options: {
|
|
16
|
+
props: Omit<DashboardProps, 'modelValue' | 'filters'>;
|
|
17
|
+
emit: Emit;
|
|
18
|
+
model: Ref<DashboardDocument>;
|
|
19
|
+
run: (steps: DashboardStep[], meta: DashboardTransactionMeta) => unknown;
|
|
20
|
+
/** Keeps a change out of undo on the widget as undo and redo bring it back. */
|
|
21
|
+
carry: (id: string, patch: {
|
|
22
|
+
comments: string[] | undefined;
|
|
23
|
+
}) => void;
|
|
24
|
+
}): {
|
|
25
|
+
enabled: ComputedRef<boolean>;
|
|
26
|
+
writable: ComputedRef<boolean>;
|
|
27
|
+
threads: ComputedRef<readonly CommentThread[]>;
|
|
28
|
+
author: ComputedRef<import("dou-ui").CommentAuthor | undefined>;
|
|
29
|
+
active: ComputedRef<string | null>;
|
|
30
|
+
pending: import("vue").ShallowRef<string | null, string | null>;
|
|
31
|
+
focusRequest: import("vue").ShallowRef<number, number>;
|
|
32
|
+
openOn: ComputedRef<Map<string, string[]>>;
|
|
33
|
+
current: ComputedRef<string | null>;
|
|
34
|
+
shown: ComputedRef<CommentThread[]>;
|
|
35
|
+
start: (widget: string, focus?: boolean) => boolean;
|
|
36
|
+
apply: (action: CommentAction) => void;
|
|
37
|
+
open: (id: string | null) => void;
|
|
38
|
+
close: () => void;
|
|
39
|
+
openedHere: (id: string | null) => boolean;
|
|
40
|
+
anchors: () => Record<string, DashboardCommentAnchor | null>;
|
|
41
|
+
widgetOf: (id: string) => string | null;
|
|
42
|
+
};
|
|
43
|
+
export type DashboardComments = ReturnType<typeof useDashboardComments>;
|
|
44
|
+
export {};
|
|
@@ -15,19 +15,29 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, Das
|
|
|
15
15
|
breakpointChange: (breakpoint: string) => any;
|
|
16
16
|
"update:filters": (value: DashboardFilters) => any;
|
|
17
17
|
exportError: (event: DashboardExportErrorEvent) => any;
|
|
18
|
+
"update:comments": (threads: import("dou-ui").CommentThread[]) => any;
|
|
19
|
+
"update:activeComment": (id: string | null) => any;
|
|
20
|
+
commentAction: (action: import("dou-ui").CommentAction) => any;
|
|
18
21
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
19
22
|
onChange?: ((transaction: DashboardTransaction) => any) | undefined;
|
|
20
23
|
"onUpdate:modelValue"?: ((value: DashboardDocument) => any) | undefined;
|
|
21
24
|
onBreakpointChange?: ((breakpoint: string) => any) | undefined;
|
|
22
25
|
"onUpdate:filters"?: ((value: DashboardFilters) => any) | undefined;
|
|
23
26
|
onExportError?: ((event: DashboardExportErrorEvent) => any) | undefined;
|
|
27
|
+
"onUpdate:comments"?: ((threads: import("dou-ui").CommentThread[]) => any) | undefined;
|
|
28
|
+
"onUpdate:activeComment"?: ((id: string | null) => any) | undefined;
|
|
29
|
+
onCommentAction?: ((action: import("dou-ui").CommentAction) => any) | undefined;
|
|
24
30
|
}>, {
|
|
31
|
+
comments: import("dou-ui").CommentThread[];
|
|
25
32
|
columns: number | Record<string, number>;
|
|
26
33
|
breakpoints: Record<string, number>;
|
|
27
34
|
rowHeight: number;
|
|
28
35
|
gap: number | [number, number];
|
|
29
36
|
compact: import("..").GridCompact;
|
|
30
37
|
widgets: DashboardWidgetType<any>[];
|
|
38
|
+
author: import("dou-ui").CommentAuthor;
|
|
39
|
+
activeComment: string | null;
|
|
40
|
+
commentable: boolean;
|
|
31
41
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
32
42
|
declare const _default: typeof __VLS_export;
|
|
33
43
|
export default _default;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { SheetWorkbook } from '@dou-ui/sheet/core';
|
|
2
2
|
import type { Component, InjectionKey } from 'vue';
|
|
3
3
|
import type { DashboardPeer } from '../core/collaboration';
|
|
4
|
+
import type { DashboardComments } from './comments';
|
|
4
5
|
import type { DashboardWidget } from '../core/types';
|
|
5
6
|
import type { DashboardLinkedFilter } from '../data/types';
|
|
6
7
|
import type { DashboardMessages } from '../locale';
|
|
@@ -18,6 +19,7 @@ export interface FrameExporter {
|
|
|
18
19
|
* that widget's frame again, not every frame on the grid.
|
|
19
20
|
*/
|
|
20
21
|
export interface FrameContext {
|
|
22
|
+
comments: DashboardComments;
|
|
21
23
|
widget: (id: string) => DashboardWidget | undefined;
|
|
22
24
|
type: (widget: DashboardWidget) => DashboardWidgetType<any> | undefined;
|
|
23
25
|
title: (widget: DashboardWidget) => string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommentAction, CommentAuthor, CommentThread } from 'dou-ui';
|
|
1
2
|
import type { SheetExporterOptionsOf } from '@dou-ui/sheet';
|
|
2
3
|
import type { SheetExporter } from '@dou-ui/sheet/core';
|
|
3
4
|
import type { DashboardCollaboration } from '../core/collaboration';
|
|
@@ -8,6 +9,10 @@ import type { GridCompact } from '../layout/types';
|
|
|
8
9
|
import type { DashboardMessagesOverride } from '../locale';
|
|
9
10
|
import type { DashboardWidgetType } from '../widget/define';
|
|
10
11
|
import type { DashboardImageOptions } from './export';
|
|
12
|
+
/** What a comment thread is about: a widget. */
|
|
13
|
+
export interface DashboardCommentAnchor {
|
|
14
|
+
widget: string;
|
|
15
|
+
}
|
|
11
16
|
export interface DashboardProps {
|
|
12
17
|
/** The dashboard, bound with `v-model`; a new document object after every change. */
|
|
13
18
|
modelValue?: DashboardDocument;
|
|
@@ -58,6 +63,18 @@ export interface DashboardProps {
|
|
|
58
63
|
* such as PNG, are left out.
|
|
59
64
|
*/
|
|
60
65
|
exporters?: readonly SheetExporter[];
|
|
66
|
+
/**
|
|
67
|
+
* The comment threads, bound with `v-model:comments`. The widget a thread
|
|
68
|
+
* is about keeps the thread's id in its `comments`. Left out, there are
|
|
69
|
+
* no comments.
|
|
70
|
+
*/
|
|
71
|
+
comments?: CommentThread[];
|
|
72
|
+
/** Who is commenting. Without it comments can be read but not written. */
|
|
73
|
+
author?: CommentAuthor;
|
|
74
|
+
/** The thread open now, bound with `v-model:activeComment`. */
|
|
75
|
+
activeComment?: string | null;
|
|
76
|
+
/** Threads can be started and replied to; also while not `editable`. On by default. */
|
|
77
|
+
commentable?: boolean;
|
|
61
78
|
}
|
|
62
79
|
/** Options of a dashboard's `exportWidget`. */
|
|
63
80
|
export interface DashboardExportOptions<Options = any> {
|
|
@@ -92,6 +109,10 @@ export interface DashboardEmits {
|
|
|
92
109
|
breakpointChange: [breakpoint: string];
|
|
93
110
|
/** Exporting a widget from its menu or `saveWidget` failed; the widget tells of it unless prevented. */
|
|
94
111
|
exportError: [event: DashboardExportErrorEvent];
|
|
112
|
+
'update:comments': [threads: CommentThread[]];
|
|
113
|
+
'update:activeComment': [id: string | null];
|
|
114
|
+
/** A change to the comments made here: to send to a server, notify people, keep a log. */
|
|
115
|
+
commentAction: [action: CommentAction];
|
|
95
116
|
}
|
|
96
117
|
export interface DashboardAddOptions {
|
|
97
118
|
/** Where on the widest breakpoint; defaults to the first spot it fits. */
|
|
@@ -114,6 +135,15 @@ export interface DashboardExpose {
|
|
|
114
135
|
/** Adds a widget of a registered type; returns its id, or `undefined` for an unknown type. */
|
|
115
136
|
addWidget: (type: string, options?: DashboardAddOptions) => string | undefined;
|
|
116
137
|
removeWidget: (id: string) => void;
|
|
138
|
+
/**
|
|
139
|
+
* Opens the open threads on a widget (the one holding the focus when
|
|
140
|
+
* left out), ready to reply, or starts one there; `false` when there is
|
|
141
|
+
* no such widget, comments are off, or there is nothing to open and
|
|
142
|
+
* comments can't be written.
|
|
143
|
+
*/
|
|
144
|
+
comment: (id?: string) => boolean;
|
|
145
|
+
/** The widget each thread is about; `null` when it is gone. Not reactive. */
|
|
146
|
+
getCommentAnchors: () => Record<string, DashboardCommentAnchor | null>;
|
|
117
147
|
/** Adds a copy of a widget next to it; returns the copy's id. */
|
|
118
148
|
duplicateWidget: (id: string) => string | undefined;
|
|
119
149
|
focusWidget: (id: string) => void;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -154,6 +154,7 @@ export declare const DouGridLayoutHandle: import("dou-ui").WithInstall<{
|
|
|
154
154
|
};
|
|
155
155
|
}), import("vue").HTMLAttributes>;
|
|
156
156
|
export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").DefineComponent<{
|
|
157
|
+
comments?: import("dou-ui").CommentThread[] | undefined;
|
|
157
158
|
columns?: (number | Record<string, number>) | undefined;
|
|
158
159
|
editable?: boolean | undefined;
|
|
159
160
|
label?: string | undefined;
|
|
@@ -167,6 +168,9 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
167
168
|
createId?: ((type: string) => string) | undefined;
|
|
168
169
|
collaboration?: import("./index.js").DashboardCollaboration | undefined;
|
|
169
170
|
exporters?: readonly import("@dou-ui/sheet").SheetExporter[] | undefined;
|
|
171
|
+
author?: import("dou-ui").CommentAuthor | undefined;
|
|
172
|
+
activeComment?: string | null | undefined;
|
|
173
|
+
commentable?: boolean | undefined;
|
|
170
174
|
} & {
|
|
171
175
|
modelValue?: import("./index.js").DashboardDocument;
|
|
172
176
|
filters?: import("./index.js").DashboardFilters;
|
|
@@ -176,7 +180,11 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
176
180
|
breakpointChange: (breakpoint: string) => any;
|
|
177
181
|
"update:filters": (value: import("./index.js").DashboardFilters) => any;
|
|
178
182
|
exportError: (event: import("./index.js").DashboardExportErrorEvent) => any;
|
|
183
|
+
"update:comments": (threads: import("dou-ui").CommentThread[]) => any;
|
|
184
|
+
"update:activeComment": (id: string | null) => any;
|
|
185
|
+
commentAction: (action: import("dou-ui").CommentAction) => any;
|
|
179
186
|
}, string, import("vue").PublicProps, Readonly<{
|
|
187
|
+
comments?: import("dou-ui").CommentThread[] | undefined;
|
|
180
188
|
columns?: (number | Record<string, number>) | undefined;
|
|
181
189
|
editable?: boolean | undefined;
|
|
182
190
|
label?: string | undefined;
|
|
@@ -190,6 +198,9 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
190
198
|
createId?: ((type: string) => string) | undefined;
|
|
191
199
|
collaboration?: import("./index.js").DashboardCollaboration | undefined;
|
|
192
200
|
exporters?: readonly import("@dou-ui/sheet").SheetExporter[] | undefined;
|
|
201
|
+
author?: import("dou-ui").CommentAuthor | undefined;
|
|
202
|
+
activeComment?: string | null | undefined;
|
|
203
|
+
commentable?: boolean | undefined;
|
|
193
204
|
} & {
|
|
194
205
|
modelValue?: import("./index.js").DashboardDocument;
|
|
195
206
|
filters?: import("./index.js").DashboardFilters;
|
|
@@ -199,13 +210,20 @@ export declare const DouDashboard: import("dou-ui").WithInstall<import("vue").De
|
|
|
199
210
|
onBreakpointChange?: ((breakpoint: string) => any) | undefined;
|
|
200
211
|
"onUpdate:filters"?: ((value: import("./index.js").DashboardFilters) => any) | undefined;
|
|
201
212
|
onExportError?: ((event: import("./index.js").DashboardExportErrorEvent) => any) | undefined;
|
|
213
|
+
"onUpdate:comments"?: ((threads: import("dou-ui").CommentThread[]) => any) | undefined;
|
|
214
|
+
"onUpdate:activeComment"?: ((id: string | null) => any) | undefined;
|
|
215
|
+
onCommentAction?: ((action: import("dou-ui").CommentAction) => any) | undefined;
|
|
202
216
|
}>, {
|
|
217
|
+
comments: import("dou-ui").CommentThread[];
|
|
203
218
|
columns: number | Record<string, number>;
|
|
204
219
|
breakpoints: Record<string, number>;
|
|
205
220
|
rowHeight: number;
|
|
206
221
|
gap: number | [number, number];
|
|
207
222
|
compact: import("./layout").GridCompact;
|
|
208
223
|
widgets: import("./index.js").DashboardWidgetType<any>[];
|
|
224
|
+
author: import("dou-ui").CommentAuthor;
|
|
225
|
+
activeComment: string | null;
|
|
226
|
+
commentable: boolean;
|
|
209
227
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, import("vue").HTMLAttributes>;
|
|
210
228
|
export declare const DouDashboardPalette: import("dou-ui").WithInstall<{
|
|
211
229
|
new (...args: any[]): import("vue").CreateComponentPublicInstanceWithMixins<Readonly<import("./index.js").DashboardPaletteProps> & Readonly<{}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, import("vue").PublicProps, {
|
|
@@ -264,11 +282,12 @@ export declare const DouDashboardFilterBar: import("dou-ui").WithInstall<{
|
|
|
264
282
|
default?: () => unknown;
|
|
265
283
|
};
|
|
266
284
|
}), import("vue").HTMLAttributes>;
|
|
267
|
-
export type { DashboardAddOptions, DashboardEmits, DashboardExportErrorEvent, DashboardExportOptions, DashboardSaveOptions, DashboardExpose, DashboardFilterBarProps, DashboardPaletteProps, DashboardProps, } from './dashboard/types';
|
|
285
|
+
export type { DashboardAddOptions, DashboardEmits, DashboardExportErrorEvent, DashboardExportOptions, DashboardSaveOptions, DashboardCommentAnchor, DashboardExpose, DashboardFilterBarProps, DashboardPaletteProps, DashboardProps, } from './dashboard/types';
|
|
268
286
|
export type { DashboardDocument, DashboardPlace, DashboardWidget } from './core/types';
|
|
269
287
|
export { checkDocument, emptyDocument, isDashboardPlace, migrateDocument } from './core/document';
|
|
270
288
|
export type { CheckDocumentOptions, DocumentProblem } from './core/document';
|
|
271
289
|
export { applySteps, DashboardTransaction, replaceWidgets, sameValue } from './core/transaction';
|
|
290
|
+
export type { ReplaceWidgetsOptions } from './core/transaction';
|
|
272
291
|
export type { DashboardCollaboration, DashboardCollaborationHost, DashboardPeer, DashboardPresence, DashboardPresenceAction, } from './core/collaboration';
|
|
273
292
|
export type { DashboardStep, DashboardTransactionMeta, DashboardWidgetPatch, } from './core/transaction';
|
|
274
293
|
export { DashboardHistory } from './core/history';
|
package/dist/types/locale.d.ts
CHANGED
|
@@ -37,6 +37,10 @@ export interface DashboardMessages {
|
|
|
37
37
|
nothingToExport: string;
|
|
38
38
|
duplicate: string;
|
|
39
39
|
remove: string;
|
|
40
|
+
/** The comment button and the card of a widget's discussions. */
|
|
41
|
+
comment: string;
|
|
42
|
+
/** The comment button of a widget with discussions; `{count}` is how many are open. */
|
|
43
|
+
comments: string;
|
|
40
44
|
/** The settings drawer's title: `{title}`. */
|
|
41
45
|
settingsTitle: string;
|
|
42
46
|
/** The title field in the settings drawer. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dou-ui/dashboard",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"description": "DouUI 的仪表盘:可拖动、可缩放的网格布局与仪表盘设计器",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vue",
|
|
@@ -67,9 +67,9 @@
|
|
|
67
67
|
"build": "vite build && vue-tsc -p tsconfig.build.json && bun scripts/build-style.ts"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@dou-ui/chart": "0.1.0-alpha.
|
|
71
|
-
"@dou-ui/pivot": "0.1.0-alpha.
|
|
72
|
-
"dou-ui": "0.1.0-alpha.
|
|
70
|
+
"@dou-ui/chart": "0.1.0-alpha.4",
|
|
71
|
+
"@dou-ui/pivot": "0.1.0-alpha.4",
|
|
72
|
+
"dou-ui": "0.1.0-alpha.4",
|
|
73
73
|
"vue": "^3.5.0",
|
|
74
74
|
"yjs": "^13.6.0"
|
|
75
75
|
},
|
|
@@ -85,12 +85,12 @@
|
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@dou-ui/icons": "0.1.0-alpha.
|
|
89
|
-
"@dou-ui/sheet": "0.1.0-alpha.
|
|
88
|
+
"@dou-ui/icons": "0.1.0-alpha.4",
|
|
89
|
+
"@dou-ui/sheet": "0.1.0-alpha.4"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@dou-ui/chart": "0.1.0-alpha.
|
|
93
|
-
"@dou-ui/pivot": "0.1.0-alpha.
|
|
92
|
+
"@dou-ui/chart": "0.1.0-alpha.4",
|
|
93
|
+
"@dou-ui/pivot": "0.1.0-alpha.4",
|
|
94
94
|
"y-protocols": "^1.0.7",
|
|
95
95
|
"yjs": "^13.6.33"
|
|
96
96
|
},
|