├── .cspell └── custom-words.txt ├── .cspellcache ├── .czrc ├── .eslintrc.cjs ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .prettierignore ├── .prettierrc.json ├── .vite └── deps │ ├── _metadata.json │ ├── chunk-KLYBMDCF.js │ ├── chunk-KLYBMDCF.js.map │ ├── chunk-MFXDHSGI.js │ ├── chunk-MFXDHSGI.js.map │ ├── package.json │ ├── pinia.js │ ├── pinia.js.map │ ├── vue-router.js │ ├── vue-router.js.map │ ├── vue.js │ └── vue.js.map ├── .vscode └── extensions.json ├── README.md ├── commitlint.config.js ├── cspell.json ├── cypress.config.ts ├── cypress ├── e2e │ ├── example.cy.ts │ └── tsconfig.json ├── fixtures │ └── example.json └── support │ ├── commands.ts │ └── e2e.ts ├── env.d.ts ├── example ├── dataSource.jpg ├── flow.jpg ├── layout-mobile.jpg ├── layout-pc.jpg ├── runner-mobile.jpg └── runner-pc.jpg ├── index.html ├── package.json ├── public └── favicon.ico ├── scripts ├── check.ts ├── pre-commit.ts └── utils.ts ├── src ├── App.vue ├── assets │ ├── base.css │ ├── logo.svg │ ├── main.css │ ├── reset.css │ └── variable.css ├── blocks │ ├── BlockRenderer.vue │ ├── BlockRendererVuedraggable.vue │ ├── BlocksRenderer.vue │ ├── basic │ │ ├── ChartBlock.vue │ │ ├── HeroTitleBlock.vue │ │ ├── ImageBlock.vue │ │ ├── QuoteBlock.vue │ │ └── ViewBlock.vue │ └── external │ │ ├── ButtonBlock.vue │ │ ├── FormBlock.vue │ │ └── NotesBlock.vue ├── components │ ├── AppEditorRenderer │ │ ├── AppEditorRenderer.vue │ │ ├── LaptopPreviewer.vue │ │ ├── MobilePreviewer.vue │ │ ├── PreviewModeSwitcher.vue │ │ ├── StatusBar.vue │ │ └── type.ts │ ├── AppLeftPanel │ │ ├── AppLeftPanel.vue │ │ ├── BlocksDrawer.vue │ │ └── OutlineDrawer.vue │ ├── AppNavigator.vue │ ├── AppPreviewer │ │ ├── LaptopPreviewer.vue │ │ └── MobilePreviewer.vue │ ├── AppRightPanel │ │ ├── AppRightPanel.vue │ │ ├── ChartSetting.vue │ │ ├── QuoteSetting.vue │ │ └── SchemaExporter.vue │ ├── AppRunnerRenderer │ │ └── AppRunnerRenderer.vue │ ├── ChartRenderer │ │ ├── CanvasChartRenderer │ │ │ └── CanvasChartRenderer.vue │ │ ├── ChartRenderer.vue │ │ ├── EchartsRenderer │ │ │ └── EchartsRenderer.vue │ │ └── SVGChartRenderer │ │ │ └── SVGChartRenderer.vue │ ├── DataSourceLeftPanel.vue │ ├── FlowEditor │ │ ├── FlowEditor.vue │ │ └── initial-elements.ts │ ├── NotesEditor │ │ ├── NotesEditor.vue │ │ ├── extensions │ │ │ └── ColorHighlighter.ts │ │ └── helper.ts │ ├── SmoothDnd │ │ ├── SmoothDndContainer.ts │ │ ├── SmoothDndDraggable.ts │ │ ├── deprecate__SmoothDndContainer.vue │ │ ├── deprecate__SmoothDndDraggable.vue │ │ └── utils.ts │ └── __tests__ │ │ └── AppNavigator.ts ├── constants │ └── blocksBaseMeta.ts ├── hooks │ └── useClickOutside.ts ├── main.ts ├── mocks │ └── blocks.ts ├── router │ └── index.ts ├── setup.ts ├── stores │ ├── appEditor.ts │ └── debug.ts ├── test.ts ├── types │ └── block.ts ├── ui │ └── SegmentedControl │ │ ├── SegmentedControl.vue │ │ └── types.ts ├── utils │ ├── array.ts │ └── detect.ts └── views │ ├── AboutView.vue │ ├── ActionsView.vue │ ├── AppView.vue │ ├── DataSourceContent │ ├── DataSourceContent.vue │ └── react_app │ │ └── ReactDataSource.jsx │ ├── DataSourceView.vue │ ├── PageLayoutView.vue │ └── RunnerView.vue ├── stylelint.config.js ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json ├── tsconfig.vitest.json ├── vite.config.ts └── vitest.config.ts /.cspell/custom-words.txt: -------------------------------------------------------------------------------- 1 | autoresize 2 | behaviour 3 | Byelide 4 | commitlint 5 | conventionalcommits 6 | echarts 7 | glideapps 8 | optimizelegibility 9 | pinia 10 | tiptap 11 | veaury 12 | vuedraggable 13 | vuejs 14 | vueuse 15 | zrender 16 | -------------------------------------------------------------------------------- /.cspellcache: -------------------------------------------------------------------------------- 1 | [{"/Users/lipeizhong/Ideal/SourceCode/byelide/src/App.vue":"1","/Users/lipeizhong/Ideal/SourceCode/byelide/src/assets/base.css":"2","/Users/lipeizhong/Ideal/SourceCode/byelide/src/assets/main.css":"3","/Users/lipeizhong/Ideal/SourceCode/byelide/src/main.ts":"4","/Users/lipeizhong/Ideal/SourceCode/byelide/src/router/index.ts":"5","/Users/lipeizhong/Ideal/SourceCode/byelide/src/test.ts":"6","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/AboutView.vue":"7","/Users/lipeizhong/Ideal/SourceCode/byelide/src/assets/reset.css":"8","/Users/lipeizhong/Ideal/SourceCode/byelide/src/assets/variable.css":"9","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/__tests__/AppNavigator.ts":"10","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppLeftPanel/AppLeftPanel.vue":"11","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppLeftPanel/BlocksDrawer.vue":"12","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppLeftPanel/OutlineDrawer.vue":"13","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppNavigator.vue":"14","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppPreviewer/LaptopPreviewer.vue":"15","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppPreviewer/MobilePreviewer.vue":"16","/Users/lipeizhong/Ideal/SourceCode/byelide/src/stores/debug.ts":"17","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/ActionsView.vue":"18","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/AppView.vue":"19","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/DataSourceView.vue":"20","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/PageLayoutView.vue":"21","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/SmoothDnd/deprecate__SmoothDndContainer.vue":"22","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/SmoothDnd/deprecate__SmoothDndDraggable.vue":"23","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/SmoothDnd/SmoothDndContainer.ts":"24","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/SmoothDnd/SmoothDndDraggable.ts":"25","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/SmoothDnd/utils.ts":"26","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/basic/ChartBlock.vue":"27","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/basic/HeroTitleBlock.vue":"28","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/basic/ImageBlock.vue":"29","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/basic/QuoteBlock.vue":"30","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/basic/ViewBlock.vue":"31","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/BlockRenderer.vue":"32","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/BlockRendererVuedraggable.vue":"33","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/external/ButtonBlock.vue":"34","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/external/FormBlock.vue":"35","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/external/NotesBlock.vue":"36","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/NotesEditor/extensions/ColorHighlighter.ts":"37","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/NotesEditor/helper.ts":"38","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/NotesEditor/NotesEditor.vue":"39","/Users/lipeizhong/Ideal/SourceCode/byelide/src/constants/blocksBaseMeta.ts":"40","/Users/lipeizhong/Ideal/SourceCode/byelide/src/mocks/blocks.ts":"41","/Users/lipeizhong/Ideal/SourceCode/byelide/src/setup.ts":"42","/Users/lipeizhong/Ideal/SourceCode/byelide/src/stores/appEditor.ts":"43","/Users/lipeizhong/Ideal/SourceCode/byelide/src/types/block.ts":"44","/Users/lipeizhong/Ideal/SourceCode/byelide/src/utils/array.ts":"45","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/DataSourceLeftPanel.vue":"46","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/FlowEditor/FlowEditor.vue":"47","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/FlowEditor/initial-elements.ts":"48","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppRightPanel/AppRightPanel.vue":"49","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppRightPanel/QuoteSetting.vue":"50","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/DataSourceContent/DataSourceContent.vue":"51","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/ChartRenderer/ChartRenderer.vue":"52","/Users/lipeizhong/Ideal/SourceCode/byelide/src/blocks/BlocksRenderer.vue":"53","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/ChartRenderer/CanvasChartRenderer/CanvasChartRenderer.vue":"54","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/ChartRenderer/EchartsRenderer/EchartsRenderer.vue":"55","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/ChartRenderer/SVGChartRenderer/SVGChartRenderer.vue":"56","/Users/lipeizhong/Ideal/SourceCode/byelide/src/hooks/useClickOutside.ts":"57","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppRightPanel/ChartSetting.vue":"58","/Users/lipeizhong/Ideal/SourceCode/byelide/src/ui/SegmentedControl/SegmentedControl.vue":"59","/Users/lipeizhong/Ideal/SourceCode/byelide/src/ui/SegmentedControl/types.ts":"60","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppEditorRenderer/AppEditorRenderer.vue":"61","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppEditorRenderer/LaptopPreviewer.vue":"62","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppEditorRenderer/MobilePreviewer.vue":"63","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppEditorRenderer/PreviewModeSwitcher.vue":"64","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppEditorRenderer/StatusBar.vue":"65","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppEditorRenderer/type.ts":"66","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppRightPanel/SchemaExporter.vue":"67","/Users/lipeizhong/Ideal/SourceCode/byelide/src/components/AppRunnerRenderer/AppRunnerRenderer.vue":"68","/Users/lipeizhong/Ideal/SourceCode/byelide/src/views/RunnerView.vue":"69"},{"size":116,"mtime":1700996031575,"data":"70"},{"size":1045,"mtime":1700996031575,"data":"71"},{"size":367,"mtime":1700996031575,"data":"72"},{"size":286,"mtime":1706962238512,"data":"73"},{"size":1940,"mtime":1710161924135,"data":"74"},{"size":0,"mtime":1694319102687,"data":"75"},{"size":220,"mtime":1689931589298,"data":"76"},{"size":1096,"mtime":1700996031575,"data":"77"},{"size":2402,"mtime":1700996031575,"data":"78"},{"size":337,"mtime":1706962238510,"data":"79"},{"size":2890,"mtime":1706962238503,"data":"80"},{"size":2158,"mtime":1710161924133,"data":"81"},{"size":1328,"mtime":1710161924133,"data":"82"},{"size":5621,"mtime":1710161910840,"data":"83"},{"size":1227,"mtime":1706965776329,"data":"84"},{"size":1368,"mtime":1706965801658,"data":"85"},{"size":232,"mtime":1706962238514,"data":"86"},{"size":140,"mtime":1706449417578,"data":"87"},{"size":474,"mtime":1706962238515,"data":"88"},{"size":287,"mtime":1706449439992,"data":"89"},{"size":606,"mtime":1706962238516,"data":"90"},{"size":1139,"mtime":1706929685469,"data":"91"},{"size":122,"mtime":1706447067151,"data":"92"},{"size":2279,"mtime":1710161924135,"data":"93"},{"size":508,"mtime":1706962238510,"data":"94"},{"size":1264,"mtime":1706447067152,"data":"95"},{"size":360,"mtime":1706962238500,"data":"96"},{"size":232,"mtime":1706447303389,"data":"97"},{"size":334,"mtime":1706447303390,"data":"98"},{"size":1141,"mtime":1706962238500,"data":"99"},{"size":142,"mtime":1706447303390,"data":"100"},{"size":3192,"mtime":1706962238499,"data":"101"},{"size":5110,"mtime":1706447303389,"data":"102"},{"size":492,"mtime":1706929685456,"data":"103"},{"size":817,"mtime":1706929685457,"data":"104"},{"size":276,"mtime":1706447303391,"data":"105"},{"size":637,"mtime":1706447303394,"data":"106"},{"size":747,"mtime":1706447303395,"data":"107"},{"size":3158,"mtime":1706962238509,"data":"108"},{"size":2949,"mtime":1710161924135,"data":"109"},{"size":1469,"mtime":1706962238512,"data":"110"},{"size":2720,"mtime":1706962238513,"data":"111"},{"size":910,"mtime":1710161924136,"data":"112"},{"size":1773,"mtime":1706962238514,"data":"113"},{"size":214,"mtime":1706447303397,"data":"114"},{"size":1569,"mtime":1706449439990,"data":"115"},{"size":3386,"mtime":1706962238509,"data":"116"},{"size":1154,"mtime":1706449417578,"data":"117"},{"size":2434,"mtime":1710161924134,"data":"118"},{"size":2786,"mtime":1706962238507,"data":"119"},{"size":642,"mtime":1706962238515,"data":"120"},{"size":858,"mtime":1706962238508,"data":"121"},{"size":3316,"mtime":1710161924131,"data":"122"},{"size":2242,"mtime":1706962238507,"data":"123"},{"size":4587,"mtime":1710733664628,"data":"124"},{"size":2549,"mtime":1706960089518,"data":"125"},{"size":553,"mtime":1706962238511,"data":"126"},{"size":1585,"mtime":1706962238506,"data":"127"},{"size":3076,"mtime":1706929685475,"data":"128"},{"size":163,"mtime":1706929685477,"data":"129"},{"size":796,"mtime":1706962238501,"data":"130"},{"size":2802,"mtime":1710161924132,"data":"131"},{"size":2525,"mtime":1710161924133,"data":"132"},{"size":1482,"mtime":1706962238502,"data":"133"},{"size":4512,"mtime":1706962238502,"data":"134"},{"size":46,"mtime":1706962238502,"data":"135"},{"size":1495,"mtime":1710161913317,"data":"136"},{"size":1718,"mtime":1710161924134,"data":"137"},{"size":420,"mtime":1706962238516,"data":"138"},{"v":"139","r":"140","d":"141"},{"v":"139","r":"142","d":"143"},{"v":"139","r":"144","d":"143"},{"v":"139","r":"145","d":"146"},{"v":"139","r":"147","d":"146"},{"v":"139","r":"148","d":"146"},{"v":"139","r":"149","d":"141"},{"v":"139","r":"150","d":"143"},{"v":"139","r":"151","d":"143"},{"v":"139","r":"152","d":"146"},{"v":"139","r":"153","d":"141"},{"v":"139","r":"154","d":"141"},{"v":"139","r":"155","d":"141"},{"v":"139","r":"156","d":"141"},{"v":"139","r":"157","d":"141"},{"v":"139","r":"158","d":"141"},{"v":"139","r":"159","d":"146"},{"v":"139","r":"160","d":"141"},{"v":"139","r":"161","d":"141"},{"v":"139","r":"162","d":"141"},{"v":"139","r":"163","d":"141"},{"v":"139","r":"164","d":"141"},{"v":"139","r":"165","d":"141"},{"v":"139","r":"166","d":"146"},{"v":"139","r":"167","d":"146"},{"v":"139","r":"168","d":"146"},{"v":"139","r":"169","d":"141"},{"v":"139","r":"170","d":"141"},{"v":"139","r":"171","d":"141"},{"v":"139","r":"172","d":"141"},{"v":"139","r":"173","d":"141"},{"v":"139","r":"174","d":"141"},{"v":"139","r":"175","d":"141"},{"v":"139","r":"176","d":"141"},{"v":"139","r":"177","d":"141"},{"v":"139","r":"178","d":"141"},{"v":"139","r":"179","d":"146"},{"v":"139","r":"180","d":"146"},{"v":"139","r":"181","d":"141"},{"v":"139","r":"182","d":"146"},{"v":"139","r":"183","d":"146"},{"v":"139","r":"184","d":"146"},{"v":"139","r":"185","d":"146"},{"v":"139","r":"186","d":"146"},{"v":"139","r":"187","d":"146"},{"v":"139","r":"188","d":"141"},{"v":"139","r":"189","d":"141"},{"v":"139","r":"190","d":"146"},{"v":"139","r":"191","d":"141"},{"v":"139","r":"192","d":"141"},{"v":"139","r":"193","d":"141"},{"v":"139","r":"194","d":"141"},{"v":"139","r":"195","d":"141"},{"v":"139","r":"196","d":"141"},{"v":"139","r":"197","d":"141"},{"v":"139","r":"198","d":"141"},{"v":"139","r":"199","d":"146"},{"v":"139","r":"200","d":"141"},{"v":"139","r":"201","d":"141"},{"v":"139","r":"202","d":"146"},{"v":"139","r":"203","d":"141"},{"v":"139","r":"204","d":"141"},{"v":"139","r":"205","d":"141"},{"v":"139","r":"206","d":"141"},{"v":"139","r":"207","d":"141"},{"v":"139","r":"208","d":"146"},{"v":"139","r":"209","d":"141"},{"v":"139","r":"210","d":"141"},{"v":"139","r":"211","d":"141"},"6.31-1-v|r|d",{"issues":"212","processed":true,"errors":0,"configErrors":0},["213","214","215","216","217","218","219","220","221","222","223","224","225","226","227","228","229","230","231","232","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","248","249","250","251","252","253","254","255","256","257","258","259","260","261","262","263","264","265","266","267","268","269","270","271","272","273","274","275","276","277","278","279","280","281","282","283"],{"issues":"284","processed":true,"errors":0,"configErrors":0},["213","214","215","216","217","218","219","220","221","222","223","224","225","226","227","228","229","230","231","233","234","235","236","237","238","239","240","241","242","243","244","245","246","247","249","250","251","252","253","255","257","258","259","260","261","262","263","265","267","268","269","270","271","272","273","274","275","276","277","278","279","280","281","283"],{"issues":"285","processed":true,"errors":0,"configErrors":0},{"issues":"286","processed":true,"errors":0,"configErrors":0},["213","214","215","216","217","218","219","220","221","222","223","224","225","226","227","229","230","231","233","234","235","236","237","238","239","240","241","242","243","244","245","247","248","249","250","251","252","253","255","257","258","259","260","261","262","287","263","264","265","267","268","269","270","271","272","273","274","275","276","277","278","279","288","280","281","282","283"],{"issues":"289","processed":true,"errors":0,"configErrors":0},{"issues":"290","processed":true,"errors":0,"configErrors":0},{"issues":"291","processed":true,"errors":0,"configErrors":0},{"issues":"292","processed":true,"errors":0,"configErrors":0},{"issues":"293","processed":true,"errors":0,"configErrors":0},{"issues":"294","processed":true,"errors":0,"configErrors":0},{"issues":"295","processed":true,"errors":0,"configErrors":0},{"issues":"296","processed":true,"errors":0,"configErrors":0},{"issues":"297","processed":true,"errors":0,"configErrors":0},{"issues":"298","processed":true,"errors":0,"configErrors":0},{"issues":"299","processed":true,"errors":0,"configErrors":0},{"issues":"300","processed":true,"errors":0,"configErrors":0},{"issues":"301","processed":true,"errors":0,"configErrors":0},{"issues":"302","processed":true,"errors":0,"configErrors":0},{"issues":"303","processed":true,"errors":0,"configErrors":0},{"issues":"304","processed":true,"errors":0,"configErrors":0},{"issues":"305","processed":true,"errors":0,"configErrors":0},{"issues":"306","processed":true,"errors":0,"configErrors":0},{"issues":"307","processed":true,"errors":0,"configErrors":0},{"issues":"308","processed":true,"errors":0,"configErrors":0},{"issues":"309","processed":true,"errors":0,"configErrors":0},{"issues":"310","processed":true,"errors":0,"configErrors":0},{"issues":"311","processed":true,"errors":0,"configErrors":0},{"issues":"312","processed":true,"errors":0,"configErrors":0},{"issues":"313","processed":true,"errors":0,"configErrors":0},{"issues":"314","processed":true,"errors":0,"configErrors":0},{"issues":"315","processed":true,"errors":0,"configErrors":0},{"issues":"316","processed":true,"errors":0,"configErrors":0},{"issues":"317","processed":true,"errors":0,"configErrors":0},{"issues":"318","processed":true,"errors":0,"configErrors":0},{"issues":"319","processed":true,"errors":0,"configErrors":0},{"issues":"320","processed":true,"errors":0,"configErrors":0},{"issues":"321","processed":true,"errors":0,"configErrors":0},{"issues":"322","processed":true,"errors":0,"configErrors":0},{"issues":"323","processed":true,"errors":0,"configErrors":0},{"issues":"324","processed":true,"errors":0,"configErrors":0},{"issues":"325","processed":true,"errors":0,"configErrors":0},{"issues":"326","processed":true,"errors":0,"configErrors":0},{"issues":"327","processed":true,"errors":0,"configErrors":0},{"issues":"328","processed":true,"errors":0,"configErrors":0},{"issues":"329","processed":true,"errors":0,"configErrors":0},{"issues":"330","processed":true,"errors":0,"configErrors":0},{"issues":"331","processed":true,"errors":0,"configErrors":0},{"issues":"332","processed":true,"errors":0,"configErrors":0},{"issues":"333","processed":true,"errors":0,"configErrors":0},{"issues":"334","processed":true,"errors":0,"configErrors":0},{"issues":"335","processed":true,"errors":0,"configErrors":0},{"issues":"336","processed":true,"errors":0,"configErrors":0},{"issues":"337","processed":true,"errors":0,"configErrors":0},{"issues":"338","processed":true,"errors":0,"configErrors":0},{"issues":"339","processed":true,"errors":0,"configErrors":0},{"issues":"340","processed":true,"errors":0,"configErrors":0},{"issues":"341","processed":true,"errors":0,"configErrors":0},{"issues":"342","processed":true,"errors":0,"configErrors":0},{"issues":"343","processed":true,"errors":0,"configErrors":0},{"issues":"344","processed":true,"errors":0,"configErrors":0},{"issues":"345","processed":true,"errors":0,"configErrors":0},{"issues":"346","processed":true,"errors":0,"configErrors":0},{"issues":"347","processed":true,"errors":0,"configErrors":0},{"issues":"348","processed":true,"errors":0,"configErrors":0},{"issues":"349","processed":true,"errors":0,"configErrors":0},{"issues":"350","processed":true,"errors":0,"configErrors":0},{"issues":"351","processed":true,"errors":0,"configErrors":0},{"issues":"352","processed":true,"errors":0,"configErrors":0},{"issues":"353","processed":true,"errors":0,"configErrors":0},[],{"f":"354","h":"355"},{"f":"356","h":"357"},{"f":"358","h":"359"},{"f":"360","h":"361"},{"f":"362","h":"363"},{"f":"364","h":"365"},{"f":"366","h":"367"},{"f":"368","h":"369"},{"f":"370","h":"371"},{"f":"372","h":"373"},{"f":"374","h":"375"},{"f":"376","h":"377"},{"f":"378","h":"379"},{"f":"380","h":"381"},{"f":"382","h":"383"},{"f":"384","h":"385"},{"f":"386","h":"387"},{"f":"388","h":"389"},{"f":"390","h":"391"},{"f":"392","h":"393"},{"f":"394","h":"395"},{"f":"396","h":"397"},{"f":"398","h":"399"},{"f":"400","h":"401"},{"f":"402","h":"403"},{"f":"404","h":"405"},{"f":"406","h":"407"},{"f":"408","h":"409"},{"f":"410","h":"411"},{"f":"412","h":"413"},{"f":"414","h":"415"},{"f":"416","h":"417"},{"f":"418","h":"419"},{"f":"420","h":"421"},{"f":"422","h":"423"},{"f":"424","h":"425"},{"f":"426","h":"427"},{"f":"428","h":"429"},{"f":"430","h":"431"},{"f":"432","h":"433"},{"f":"434","h":"435"},{"f":"436","h":"437"},{"f":"438","h":"439"},{"f":"440","h":"441"},{"f":"442","h":"443"},{"f":"444","h":"445"},{"f":"446","h":"447"},{"f":"448","h":"449"},{"f":"450","h":"451"},{"f":"452","h":"453"},{"f":"454","h":"455"},{"f":"456","h":"457"},{"f":"458","h":"459"},{"f":"460","h":"461"},{"f":"462","h":"463"},{"f":"464","h":"465"},{"f":"466","h":"467"},{"f":"468","h":"469"},{"f":"470","h":"471"},{"f":"472","h":"473"},{"f":"474","h":"475"},{"f":"476","h":"477"},{"f":"478","h":"479"},{"f":"480","h":"481"},{"f":"482","h":"483"},{"f":"484","h":"485"},{"f":"486","h":"487"},{"f":"488","h":"489"},{"f":"490","h":"491"},{"f":"492","h":"493"},{"f":"494","h":"495"},[],[],[],{"f":"496","h":"497"},{"f":"498","h":"499"},[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],"/Users/lipeizhong/Ideal/SourceCode/byelide/.cspell/custom-words.txt","d4490ed2ac83b2066925c35f860ee44c","/Users/lipeizhong/Ideal/SourceCode/byelide/cspell.json","298379ab5ade125c38e810a7f2a6be97","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+cspell-bundled-dicts@6.31.2/node_modules/@cspell/cspell-bundled-dicts/cspell-default.config.js","b3cce138e6770b1d0ef754c3e03a9377","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+cspell-bundled-dicts@6.31.2/node_modules/@cspell/cspell-bundled-dicts/cspell-default.json","448e57f919fe80e23846daf87b73813f","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-ada@4.0.2/node_modules/@cspell/dict-ada/cspell-ext.json","ada8ac29458417e58ebdef02e3c60682","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-aws@3.0.0/node_modules/@cspell/dict-aws/aws.txt.gz","cb7cda452732278fa641263aec33e302","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-aws@3.0.0/node_modules/@cspell/dict-aws/cspell-ext.json","51140c397c70d0f5476806ea8cd0fc7a","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-bash@4.1.1/node_modules/@cspell/dict-bash/cspell-ext.json","64be15965d14c6ad022a19a7055c5310","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-companies@3.0.17/node_modules/@cspell/dict-companies/cspell-ext.json","801dd6efb9e1cf30b06c8a095f6e31f4","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-companies@3.0.17/node_modules/@cspell/dict-companies/dict/companies.txt","95bf67a3960cf3cca9e55d417a6b7490","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-cpp@5.0.4/node_modules/@cspell/dict-cpp/cspell-ext.json","018335cbc82996c11d4ff5dcb1dfe918","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-cryptocurrencies@3.0.1/node_modules/@cspell/dict-cryptocurrencies/cryptocurrencies.txt.gz","1b8dd3df3526e390d7d2acc340794523","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-cryptocurrencies@3.0.1/node_modules/@cspell/dict-cryptocurrencies/cspell-ext.json","3195a1180115937b58052425eaf0fef4","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-csharp@4.0.2/node_modules/@cspell/dict-csharp/cspell-ext.json","4f758986459c61fd3b78fd4c6c7f04e5","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-css@4.0.6/node_modules/@cspell/dict-css/cspell-ext.json","f568653c615bfb944aeff1d581a1b6fb","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-css@4.0.6/node_modules/@cspell/dict-css/dict/css.txt","20962be396a734d95472898a7f46cbd3","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-dart@2.0.3/node_modules/@cspell/dict-dart/cspell-ext.json","4fca6723c7e99b83c8b2d20d3dda9cac","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-data-science@1.0.8/node_modules/@cspell/dict-data-science/cspell-ext.json","6a8bc28993a55974987ab1fcfb74fcaf","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-django@4.1.0/node_modules/@cspell/dict-django/cspell-ext.json","2a5dbe1146a60abe50b6b5a76c7905a6","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-django@4.1.0/node_modules/@cspell/dict-django/dict/django.txt","6e0b645200a8d60aefbe6f692dac6309","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-docker@1.1.7/node_modules/@cspell/dict-docker/cspell-ext.json","d9d9174aeb2cdbebc7a82731bf82727e","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-dotnet@5.0.0/node_modules/@cspell/dict-dotnet/cspell-ext.json","1cff6a13b4a81c81fb46804919419c1c","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-elixir@4.0.3/node_modules/@cspell/dict-elixir/cspell-ext.json","6dc32a9ac33413d3be493c0cf8b3ed7e","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en-common-misspellings@1.0.2/node_modules/@cspell/dict-en-common-misspellings/cspell-ext.json","1282dcdf1ad9c6e5a8abcb2d89fc0a7e","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en-common-misspellings@1.0.2/node_modules/@cspell/dict-en-common-misspellings/dict-en-gb.yaml","d2c51f30e122934a75b55e29533db32e","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en-common-misspellings@1.0.2/node_modules/@cspell/dict-en-common-misspellings/dict-en-us.yaml","82710176ca225f64adb0fec153437e2c","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en-common-misspellings@1.0.2/node_modules/@cspell/dict-en-common-misspellings/dict-en.yaml","b28acc7e7cc4508a4ba617153d23ed32","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en-gb@1.1.33/node_modules/@cspell/dict-en-gb/cspell-ext.json","8a830537004e3efa3b64835732ce2d90","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en_us@4.3.6/node_modules/@cspell/dict-en_us/cspell-ext.json","f594f14689e56c98fe5bab7efa4384ab","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-en_us@4.3.6/node_modules/@cspell/dict-en_us/en_US.trie.gz","aec837a5463f5e0cc97fd91901657100","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-filetypes@3.0.1/node_modules/@cspell/dict-filetypes/cspell-ext.json","67bc9da5f86d2b5fb07960db03a4e0ba","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-filetypes@3.0.1/node_modules/@cspell/dict-filetypes/filetypes.txt.gz","a3f4a76ca4690aa80223deb9a3f73eed","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-fonts@3.0.2/node_modules/@cspell/dict-fonts/cspell-ext.json","ff9f6baa0dd44c6e2390f22564232229","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-fonts@3.0.2/node_modules/@cspell/dict-fonts/fonts.txt.gz","f4a79e4c0d4890ea9400b4a9e1da0163","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-fullstack@3.1.5/node_modules/@cspell/dict-fullstack/cspell-ext.json","95ebaec1c1ab40963c149169ae24c16b","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-fullstack@3.1.5/node_modules/@cspell/dict-fullstack/dict/fullstack.txt","395ab24dd58ee0a9f30346f021303406","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-gaming-terms@1.0.4/node_modules/@cspell/dict-gaming-terms/cspell-ext.json","5507855d9042bba0b65ec468e0d25ae4","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-git@2.0.0/node_modules/@cspell/dict-git/cspell-ext.json","b5e1a6cd37b97555cce790f804858bd2","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-golang@6.0.2/node_modules/@cspell/dict-golang/cspell-ext.json","fd0173f39d516a36507aa72a2778d19f","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-haskell@4.0.1/node_modules/@cspell/dict-haskell/cspell-ext.json","b60ef206b0238e328f3c3f889a949e26","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-html-symbol-entities@4.0.0/node_modules/@cspell/dict-html-symbol-entities/cspell-ext.json","1ae028b3a10c811456bda3bfa51db2d9","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-html-symbol-entities@4.0.0/node_modules/@cspell/dict-html-symbol-entities/entities.txt.gz","2db5fd4bfd44d048eb4b546d771469e3","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-html@4.0.3/node_modules/@cspell/dict-html/cspell-ext.json","e50fe9fd4667d9aa1d209b94fb41ba89","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-html@4.0.3/node_modules/@cspell/dict-html/dict/html.txt","a700c3e756b62cd0250caac797bf6601","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-java@5.0.5/node_modules/@cspell/dict-java/cspell-ext.json","450260d59f32227ac1342ca4fcb01f2b","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-k8s@1.0.1/node_modules/@cspell/dict-k8s/cspell-ext.json","52660a0fb34ccf3576d13d9c2ad81827","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-latex@4.0.0/node_modules/@cspell/dict-latex/cspell-ext.json","3fab8d3e4d5b99c6862ade7d360d3c60","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-lorem-ipsum@3.0.0/node_modules/@cspell/dict-lorem-ipsum/cspell-ext.json","7d82da2934eb8143a23aedd23e4f30c5","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-lua@4.0.1/node_modules/@cspell/dict-lua/cspell-ext.json","0b20f8e96e8682acbc3c45d68bf6c908","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-node@4.0.2/node_modules/@cspell/dict-node/cspell-ext.json","f5aae3e3fb78a7aacb6f94ec884286df","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-npm@5.0.7/node_modules/@cspell/dict-npm/cspell-ext.json","76c4e1f6873413d12f15290c40d6ed54","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-npm@5.0.7/node_modules/@cspell/dict-npm/dict/npm.txt","535952fc03d6491a59ec1d344f12da78","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-php@4.0.1/node_modules/@cspell/dict-php/cspell-ext.json","e393b7e14e5a397e101196ce534913af","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-php@4.0.1/node_modules/@cspell/dict-php/dict/php.txt","85cd724016f0dfa0e2d38523353593e4","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-powershell@5.0.2/node_modules/@cspell/dict-powershell/cspell-ext.json","10e145cc901764c95a01a50040c986ef","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-public-licenses@2.0.3/node_modules/@cspell/dict-public-licenses/cspell-ext.json","2b52f46e2d70d9fdf6ea97370f5130c9","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-public-licenses@2.0.3/node_modules/@cspell/dict-public-licenses/public-licenses.txt.gz","7fd03aea3b1b4e6e779cc8e59eadf272","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-python@4.1.3/node_modules/@cspell/dict-python/cspell-ext.json","4fbe79488a8e9bba3ae36974d9f627f0","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-r@2.0.1/node_modules/@cspell/dict-r/cspell-ext.json","bff29ea09b5c57f6757c322f20d67fcb","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-ruby@5.0.0/node_modules/@cspell/dict-ruby/cspell-ext.json","53115b7841b578ef4fbcf18e4c621b68","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-rust@4.0.1/node_modules/@cspell/dict-rust/cspell-ext.json","ddbc8d41c4861fb4b0bbcea24e08cdfb","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-scala@5.0.0/node_modules/@cspell/dict-scala/cspell-ext.json","4d9fe488659ece5d2463b279d78440f7","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-software-terms@3.2.0/node_modules/@cspell/dict-software-terms/cspell-ext.json","a9291707191c94a23bb79fb3a6c105c8","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-software-terms@3.2.0/node_modules/@cspell/dict-software-terms/dict/computing-acronyms.txt","f5d30eed605d206e135aed50da089687","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-software-terms@3.2.0/node_modules/@cspell/dict-software-terms/dict/softwareTerms.txt","b9180c568e10c29b0e37b9896778b708","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-sql@2.1.1/node_modules/@cspell/dict-sql/cspell-ext.json","ad33af28f2d88f74d3bee599579a43b6","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-svelte@1.0.2/node_modules/@cspell/dict-svelte/cspell-ext.json","9d9e970492326991eccb807c3e53711b","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-swift@2.0.1/node_modules/@cspell/dict-swift/cspell-ext.json","da83d48b4d10342a919b0c008ccfd3df","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-typescript@3.1.1/node_modules/@cspell/dict-typescript/cspell-ext.json","779bde89c91e571dbfcc481deda1c372","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-typescript@3.1.1/node_modules/@cspell/dict-typescript/dict/typescript.txt","e53e89a2518e96f8ddd58713d877cd4b","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-vue@3.0.0/node_modules/@cspell/dict-vue/cspell-ext.json","60c4486f8b2f52d948fab125597233d7","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-node@4.0.2/node_modules/@cspell/dict-node/dict/node.txt","3a63f19f2b7e421504f9652b5a2b6d8d","/Users/lipeizhong/Ideal/SourceCode/byelide/node_modules/.pnpm/@cspell+dict-svelte@1.0.2/node_modules/@cspell/dict-svelte/dict/svelte.txt","cfe8a01c5c0df41d12ecb166e08bb41f"] -------------------------------------------------------------------------------- /.czrc: -------------------------------------------------------------------------------- 1 | { 2 | "path": "node_modules/cz-git" 3 | } 4 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution') 3 | 4 | module.exports = { 5 | root: true, 6 | extends: [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/eslint-config-typescript', 10 | '@vue/eslint-config-prettier/skip-formatting' 11 | ], 12 | overrides: [ 13 | { 14 | files: ['cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}'], 15 | extends: ['plugin:cypress/recommended'] 16 | } 17 | ], 18 | plugins: ['simple-import-sort'], 19 | rules: { 20 | // 'no-console': 'error', 21 | 'simple-import-sort/imports': 'error' 22 | }, 23 | parserOptions: { 24 | ecmaVersion: 'latest' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | /scripts/*.tsno.mjs 21 | 22 | # Editor directories and files 23 | .vscode/* 24 | !.vscode/extensions.json 25 | .idea 26 | *.suo 27 | *.ntvs* 28 | *.njsproj 29 | *.sln 30 | *.sw? 31 | bundle-analysis.html 32 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit ${1} 5 | npm run commitlint ${1} 6 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm exec tsno run ./scripts/pre-commit.ts 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | .idea 4 | .eslintcache 5 | 6 | lib 7 | dist 8 | dist-ssr 9 | docs 10 | coverage 11 | test-results 12 | .pnpm-store 13 | pnpm-lock.yaml 14 | tsconfig.tsbuildinfo 15 | .babel-cache 16 | .env 17 | *.local 18 | *.cache 19 | *error.log 20 | *debug.log 21 | *err.log 22 | stats.html 23 | .cspell 24 | .cspellcache 25 | .husky 26 | .prettierignore 27 | .gitignore 28 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "trailingComma": "none" 8 | } 9 | -------------------------------------------------------------------------------- /.vite/deps/_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "cce25e05", 3 | "browserHash": "2cceebf7", 4 | "optimized": { 5 | "vue": { 6 | "src": "../../node_modules/.pnpm/vue@3.3.4/node_modules/vue/dist/vue.runtime.esm-bundler.js", 7 | "file": "vue.js", 8 | "fileHash": "cc6f8dd5", 9 | "needsInterop": false 10 | }, 11 | "pinia": { 12 | "src": "../../node_modules/.pnpm/pinia@2.1.3_typescript@5.0.4_vue@3.3.4/node_modules/pinia/dist/pinia.mjs", 13 | "file": "pinia.js", 14 | "fileHash": "74100c68", 15 | "needsInterop": false 16 | }, 17 | "vue-router": { 18 | "src": "../../node_modules/.pnpm/vue-router@4.2.2_vue@3.3.4/node_modules/vue-router/dist/vue-router.mjs", 19 | "file": "vue-router.js", 20 | "fileHash": "756afc54", 21 | "needsInterop": false 22 | } 23 | }, 24 | "chunks": { 25 | "chunk-KLYBMDCF": { 26 | "file": "chunk-KLYBMDCF.js" 27 | }, 28 | "chunk-MFXDHSGI": { 29 | "file": "chunk-MFXDHSGI.js" 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /.vite/deps/chunk-KLYBMDCF.js: -------------------------------------------------------------------------------- 1 | // node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/env.js 2 | function getDevtoolsGlobalHook() { 3 | return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__; 4 | } 5 | function getTarget() { 6 | return typeof navigator !== "undefined" && typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : {}; 7 | } 8 | var isProxyAvailable = typeof Proxy === "function"; 9 | 10 | // node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/const.js 11 | var HOOK_SETUP = "devtools-plugin:setup"; 12 | var HOOK_PLUGIN_SETTINGS_SET = "plugin:settings:set"; 13 | 14 | // node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/time.js 15 | var supported; 16 | var perf; 17 | function isPerformanceSupported() { 18 | var _a; 19 | if (supported !== void 0) { 20 | return supported; 21 | } 22 | if (typeof window !== "undefined" && window.performance) { 23 | supported = true; 24 | perf = window.performance; 25 | } else if (typeof global !== "undefined" && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) { 26 | supported = true; 27 | perf = global.perf_hooks.performance; 28 | } else { 29 | supported = false; 30 | } 31 | return supported; 32 | } 33 | function now() { 34 | return isPerformanceSupported() ? perf.now() : Date.now(); 35 | } 36 | 37 | // node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/proxy.js 38 | var ApiProxy = class { 39 | constructor(plugin, hook) { 40 | this.target = null; 41 | this.targetQueue = []; 42 | this.onQueue = []; 43 | this.plugin = plugin; 44 | this.hook = hook; 45 | const defaultSettings = {}; 46 | if (plugin.settings) { 47 | for (const id in plugin.settings) { 48 | const item = plugin.settings[id]; 49 | defaultSettings[id] = item.defaultValue; 50 | } 51 | } 52 | const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`; 53 | let currentSettings = Object.assign({}, defaultSettings); 54 | try { 55 | const raw = localStorage.getItem(localSettingsSaveId); 56 | const data = JSON.parse(raw); 57 | Object.assign(currentSettings, data); 58 | } catch (e) { 59 | } 60 | this.fallbacks = { 61 | getSettings() { 62 | return currentSettings; 63 | }, 64 | setSettings(value) { 65 | try { 66 | localStorage.setItem(localSettingsSaveId, JSON.stringify(value)); 67 | } catch (e) { 68 | } 69 | currentSettings = value; 70 | }, 71 | now() { 72 | return now(); 73 | } 74 | }; 75 | if (hook) { 76 | hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => { 77 | if (pluginId === this.plugin.id) { 78 | this.fallbacks.setSettings(value); 79 | } 80 | }); 81 | } 82 | this.proxiedOn = new Proxy({}, { 83 | get: (_target, prop) => { 84 | if (this.target) { 85 | return this.target.on[prop]; 86 | } else { 87 | return (...args) => { 88 | this.onQueue.push({ 89 | method: prop, 90 | args 91 | }); 92 | }; 93 | } 94 | } 95 | }); 96 | this.proxiedTarget = new Proxy({}, { 97 | get: (_target, prop) => { 98 | if (this.target) { 99 | return this.target[prop]; 100 | } else if (prop === "on") { 101 | return this.proxiedOn; 102 | } else if (Object.keys(this.fallbacks).includes(prop)) { 103 | return (...args) => { 104 | this.targetQueue.push({ 105 | method: prop, 106 | args, 107 | resolve: () => { 108 | } 109 | }); 110 | return this.fallbacks[prop](...args); 111 | }; 112 | } else { 113 | return (...args) => { 114 | return new Promise((resolve) => { 115 | this.targetQueue.push({ 116 | method: prop, 117 | args, 118 | resolve 119 | }); 120 | }); 121 | }; 122 | } 123 | } 124 | }); 125 | } 126 | async setRealTarget(target) { 127 | this.target = target; 128 | for (const item of this.onQueue) { 129 | this.target.on[item.method](...item.args); 130 | } 131 | for (const item of this.targetQueue) { 132 | item.resolve(await this.target[item.method](...item.args)); 133 | } 134 | } 135 | }; 136 | 137 | // node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/index.js 138 | function setupDevtoolsPlugin(pluginDescriptor, setupFn) { 139 | const descriptor = pluginDescriptor; 140 | const target = getTarget(); 141 | const hook = getDevtoolsGlobalHook(); 142 | const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy; 143 | if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) { 144 | hook.emit(HOOK_SETUP, pluginDescriptor, setupFn); 145 | } else { 146 | const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null; 147 | const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || []; 148 | list.push({ 149 | pluginDescriptor: descriptor, 150 | setupFn, 151 | proxy 152 | }); 153 | if (proxy) 154 | setupFn(proxy.proxiedTarget); 155 | } 156 | } 157 | 158 | export { 159 | setupDevtoolsPlugin 160 | }; 161 | //# sourceMappingURL=chunk-KLYBMDCF.js.map 162 | -------------------------------------------------------------------------------- /.vite/deps/chunk-KLYBMDCF.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": ["../../node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/env.js", "../../node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/const.js", "../../node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/time.js", "../../node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/proxy.js", "../../node_modules/.pnpm/@vue+devtools-api@6.5.0/node_modules/@vue/devtools-api/lib/esm/index.js"], 4 | "sourcesContent": ["export function getDevtoolsGlobalHook() {\n return getTarget().__VUE_DEVTOOLS_GLOBAL_HOOK__;\n}\nexport function getTarget() {\n // @ts-ignore\n return (typeof navigator !== 'undefined' && typeof window !== 'undefined')\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n}\nexport const isProxyAvailable = typeof Proxy === 'function';\n", "export const HOOK_SETUP = 'devtools-plugin:setup';\nexport const HOOK_PLUGIN_SETTINGS_SET = 'plugin:settings:set';\n", "let supported;\nlet perf;\nexport function isPerformanceSupported() {\n var _a;\n if (supported !== undefined) {\n return supported;\n }\n if (typeof window !== 'undefined' && window.performance) {\n supported = true;\n perf = window.performance;\n }\n else if (typeof global !== 'undefined' && ((_a = global.perf_hooks) === null || _a === void 0 ? void 0 : _a.performance)) {\n supported = true;\n perf = global.perf_hooks.performance;\n }\n else {\n supported = false;\n }\n return supported;\n}\nexport function now() {\n return isPerformanceSupported() ? perf.now() : Date.now();\n}\n", "import { HOOK_PLUGIN_SETTINGS_SET } from './const.js';\nimport { now } from './time.js';\nexport class ApiProxy {\n constructor(plugin, hook) {\n this.target = null;\n this.targetQueue = [];\n this.onQueue = [];\n this.plugin = plugin;\n this.hook = hook;\n const defaultSettings = {};\n if (plugin.settings) {\n for (const id in plugin.settings) {\n const item = plugin.settings[id];\n defaultSettings[id] = item.defaultValue;\n }\n }\n const localSettingsSaveId = `__vue-devtools-plugin-settings__${plugin.id}`;\n let currentSettings = Object.assign({}, defaultSettings);\n try {\n const raw = localStorage.getItem(localSettingsSaveId);\n const data = JSON.parse(raw);\n Object.assign(currentSettings, data);\n }\n catch (e) {\n // noop\n }\n this.fallbacks = {\n getSettings() {\n return currentSettings;\n },\n setSettings(value) {\n try {\n localStorage.setItem(localSettingsSaveId, JSON.stringify(value));\n }\n catch (e) {\n // noop\n }\n currentSettings = value;\n },\n now() {\n return now();\n },\n };\n if (hook) {\n hook.on(HOOK_PLUGIN_SETTINGS_SET, (pluginId, value) => {\n if (pluginId === this.plugin.id) {\n this.fallbacks.setSettings(value);\n }\n });\n }\n this.proxiedOn = new Proxy({}, {\n get: (_target, prop) => {\n if (this.target) {\n return this.target.on[prop];\n }\n else {\n return (...args) => {\n this.onQueue.push({\n method: prop,\n args,\n });\n };\n }\n },\n });\n this.proxiedTarget = new Proxy({}, {\n get: (_target, prop) => {\n if (this.target) {\n return this.target[prop];\n }\n else if (prop === 'on') {\n return this.proxiedOn;\n }\n else if (Object.keys(this.fallbacks).includes(prop)) {\n return (...args) => {\n this.targetQueue.push({\n method: prop,\n args,\n resolve: () => { },\n });\n return this.fallbacks[prop](...args);\n };\n }\n else {\n return (...args) => {\n return new Promise(resolve => {\n this.targetQueue.push({\n method: prop,\n args,\n resolve,\n });\n });\n };\n }\n },\n });\n }\n async setRealTarget(target) {\n this.target = target;\n for (const item of this.onQueue) {\n this.target.on[item.method](...item.args);\n }\n for (const item of this.targetQueue) {\n item.resolve(await this.target[item.method](...item.args));\n }\n }\n}\n", "import { getTarget, getDevtoolsGlobalHook, isProxyAvailable } from './env.js';\nimport { HOOK_SETUP } from './const.js';\nimport { ApiProxy } from './proxy.js';\nexport * from './api/index.js';\nexport * from './plugin.js';\nexport * from './time.js';\nexport function setupDevtoolsPlugin(pluginDescriptor, setupFn) {\n const descriptor = pluginDescriptor;\n const target = getTarget();\n const hook = getDevtoolsGlobalHook();\n const enableProxy = isProxyAvailable && descriptor.enableEarlyProxy;\n if (hook && (target.__VUE_DEVTOOLS_PLUGIN_API_AVAILABLE__ || !enableProxy)) {\n hook.emit(HOOK_SETUP, pluginDescriptor, setupFn);\n }\n else {\n const proxy = enableProxy ? new ApiProxy(descriptor, hook) : null;\n const list = target.__VUE_DEVTOOLS_PLUGINS__ = target.__VUE_DEVTOOLS_PLUGINS__ || [];\n list.push({\n pluginDescriptor: descriptor,\n setupFn,\n proxy,\n });\n if (proxy)\n setupFn(proxy.proxiedTarget);\n }\n}\n"], 5 | "mappings": ";AAAO,SAAS,wBAAwB;AACpC,SAAO,UAAU,EAAE;AACvB;AACO,SAAS,YAAY;AAExB,SAAQ,OAAO,cAAc,eAAe,OAAO,WAAW,cACxD,SACA,OAAO,WAAW,cACd,SACA,CAAC;AACf;AACO,IAAM,mBAAmB,OAAO,UAAU;;;ACX1C,IAAM,aAAa;AACnB,IAAM,2BAA2B;;;ACDxC,IAAI;AACJ,IAAI;AACG,SAAS,yBAAyB;AACrC,MAAI;AACJ,MAAI,cAAc,QAAW;AACzB,WAAO;AAAA,EACX;AACA,MAAI,OAAO,WAAW,eAAe,OAAO,aAAa;AACrD,gBAAY;AACZ,WAAO,OAAO;AAAA,EAClB,WACS,OAAO,WAAW,iBAAiB,KAAK,OAAO,gBAAgB,QAAQ,OAAO,SAAS,SAAS,GAAG,cAAc;AACtH,gBAAY;AACZ,WAAO,OAAO,WAAW;AAAA,EAC7B,OACK;AACD,gBAAY;AAAA,EAChB;AACA,SAAO;AACX;AACO,SAAS,MAAM;AAClB,SAAO,uBAAuB,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI;AAC5D;;;ACpBO,IAAM,WAAN,MAAe;AAAA,EAClB,YAAY,QAAQ,MAAM;AACtB,SAAK,SAAS;AACd,SAAK,cAAc,CAAC;AACpB,SAAK,UAAU,CAAC;AAChB,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,UAAM,kBAAkB,CAAC;AACzB,QAAI,OAAO,UAAU;AACjB,iBAAW,MAAM,OAAO,UAAU;AAC9B,cAAM,OAAO,OAAO,SAAS,EAAE;AAC/B,wBAAgB,EAAE,IAAI,KAAK;AAAA,MAC/B;AAAA,IACJ;AACA,UAAM,sBAAsB,mCAAmC,OAAO;AACtE,QAAI,kBAAkB,OAAO,OAAO,CAAC,GAAG,eAAe;AACvD,QAAI;AACA,YAAM,MAAM,aAAa,QAAQ,mBAAmB;AACpD,YAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,aAAO,OAAO,iBAAiB,IAAI;AAAA,IACvC,SACO,GAAP;AAAA,IAEA;AACA,SAAK,YAAY;AAAA,MACb,cAAc;AACV,eAAO;AAAA,MACX;AAAA,MACA,YAAY,OAAO;AACf,YAAI;AACA,uBAAa,QAAQ,qBAAqB,KAAK,UAAU,KAAK,CAAC;AAAA,QACnE,SACO,GAAP;AAAA,QAEA;AACA,0BAAkB;AAAA,MACtB;AAAA,MACA,MAAM;AACF,eAAO,IAAI;AAAA,MACf;AAAA,IACJ;AACA,QAAI,MAAM;AACN,WAAK,GAAG,0BAA0B,CAAC,UAAU,UAAU;AACnD,YAAI,aAAa,KAAK,OAAO,IAAI;AAC7B,eAAK,UAAU,YAAY,KAAK;AAAA,QACpC;AAAA,MACJ,CAAC;AAAA,IACL;AACA,SAAK,YAAY,IAAI,MAAM,CAAC,GAAG;AAAA,MAC3B,KAAK,CAAC,SAAS,SAAS;AACpB,YAAI,KAAK,QAAQ;AACb,iBAAO,KAAK,OAAO,GAAG,IAAI;AAAA,QAC9B,OACK;AACD,iBAAO,IAAI,SAAS;AAChB,iBAAK,QAAQ,KAAK;AAAA,cACd,QAAQ;AAAA,cACR;AAAA,YACJ,CAAC;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAC;AACD,SAAK,gBAAgB,IAAI,MAAM,CAAC,GAAG;AAAA,MAC/B,KAAK,CAAC,SAAS,SAAS;AACpB,YAAI,KAAK,QAAQ;AACb,iBAAO,KAAK,OAAO,IAAI;AAAA,QAC3B,WACS,SAAS,MAAM;AACpB,iBAAO,KAAK;AAAA,QAChB,WACS,OAAO,KAAK,KAAK,SAAS,EAAE,SAAS,IAAI,GAAG;AACjD,iBAAO,IAAI,SAAS;AAChB,iBAAK,YAAY,KAAK;AAAA,cAClB,QAAQ;AAAA,cACR;AAAA,cACA,SAAS,MAAM;AAAA,cAAE;AAAA,YACrB,CAAC;AACD,mBAAO,KAAK,UAAU,IAAI,EAAE,GAAG,IAAI;AAAA,UACvC;AAAA,QACJ,OACK;AACD,iBAAO,IAAI,SAAS;AAChB,mBAAO,IAAI,QAAQ,aAAW;AAC1B,mBAAK,YAAY,KAAK;AAAA,gBAClB,QAAQ;AAAA,gBACR;AAAA,gBACA;AAAA,cACJ,CAAC;AAAA,YACL,CAAC;AAAA,UACL;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,EACL;AAAA,EACA,MAAM,cAAc,QAAQ;AACxB,SAAK,SAAS;AACd,eAAW,QAAQ,KAAK,SAAS;AAC7B,WAAK,OAAO,GAAG,KAAK,MAAM,EAAE,GAAG,KAAK,IAAI;AAAA,IAC5C;AACA,eAAW,QAAQ,KAAK,aAAa;AACjC,WAAK,QAAQ,MAAM,KAAK,OAAO,KAAK,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;AAAA,IAC7D;AAAA,EACJ;AACJ;;;ACpGO,SAAS,oBAAoB,kBAAkB,SAAS;AAC3D,QAAM,aAAa;AACnB,QAAM,SAAS,UAAU;AACzB,QAAM,OAAO,sBAAsB;AACnC,QAAM,cAAc,oBAAoB,WAAW;AACnD,MAAI,SAAS,OAAO,yCAAyC,CAAC,cAAc;AACxE,SAAK,KAAK,YAAY,kBAAkB,OAAO;AAAA,EACnD,OACK;AACD,UAAM,QAAQ,cAAc,IAAI,SAAS,YAAY,IAAI,IAAI;AAC7D,UAAM,OAAO,OAAO,2BAA2B,OAAO,4BAA4B,CAAC;AACnF,SAAK,KAAK;AAAA,MACN,kBAAkB;AAAA,MAClB;AAAA,MACA;AAAA,IACJ,CAAC;AACD,QAAI;AACA,cAAQ,MAAM,aAAa;AAAA,EACnC;AACJ;", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /.vite/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /.vite/deps/vue.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseTransition, 3 | BaseTransitionPropsValidators, 4 | Comment, 5 | EffectScope, 6 | Fragment, 7 | KeepAlive, 8 | ReactiveEffect, 9 | Static, 10 | Suspense, 11 | Teleport, 12 | Text, 13 | Transition, 14 | TransitionGroup, 15 | VueElement, 16 | assertNumber, 17 | callWithAsyncErrorHandling, 18 | callWithErrorHandling, 19 | camelize, 20 | capitalize, 21 | cloneVNode, 22 | compatUtils, 23 | compile, 24 | computed, 25 | createApp, 26 | createBaseVNode, 27 | createBlock, 28 | createCommentVNode, 29 | createElementBlock, 30 | createHydrationRenderer, 31 | createPropsRestProxy, 32 | createRenderer, 33 | createSSRApp, 34 | createSlots, 35 | createStaticVNode, 36 | createTextVNode, 37 | createVNode, 38 | customRef, 39 | defineAsyncComponent, 40 | defineComponent, 41 | defineCustomElement, 42 | defineEmits, 43 | defineExpose, 44 | defineModel, 45 | defineOptions, 46 | defineProps, 47 | defineSSRCustomElement, 48 | defineSlots, 49 | devtools, 50 | effect, 51 | effectScope, 52 | getCurrentInstance, 53 | getCurrentScope, 54 | getTransitionRawChildren, 55 | guardReactiveProps, 56 | h, 57 | handleError, 58 | hasInjectionContext, 59 | hydrate, 60 | initCustomFormatter, 61 | initDirectivesForSSR, 62 | inject, 63 | isMemoSame, 64 | isProxy, 65 | isReactive, 66 | isReadonly, 67 | isRef, 68 | isRuntimeOnly, 69 | isShallow, 70 | isVNode, 71 | markRaw, 72 | mergeDefaults, 73 | mergeModels, 74 | mergeProps, 75 | nextTick, 76 | normalizeClass, 77 | normalizeProps, 78 | normalizeStyle, 79 | onActivated, 80 | onBeforeMount, 81 | onBeforeUnmount, 82 | onBeforeUpdate, 83 | onDeactivated, 84 | onErrorCaptured, 85 | onMounted, 86 | onRenderTracked, 87 | onRenderTriggered, 88 | onScopeDispose, 89 | onServerPrefetch, 90 | onUnmounted, 91 | onUpdated, 92 | openBlock, 93 | popScopeId, 94 | provide, 95 | proxyRefs, 96 | pushScopeId, 97 | queuePostFlushCb, 98 | reactive, 99 | readonly, 100 | ref, 101 | registerRuntimeCompiler, 102 | render, 103 | renderList, 104 | renderSlot, 105 | resolveComponent, 106 | resolveDirective, 107 | resolveDynamicComponent, 108 | resolveFilter, 109 | resolveTransitionHooks, 110 | setBlockTracking, 111 | setDevtoolsHook, 112 | setTransitionHooks, 113 | shallowReactive, 114 | shallowReadonly, 115 | shallowRef, 116 | ssrContextKey, 117 | ssrUtils, 118 | stop, 119 | toDisplayString, 120 | toHandlerKey, 121 | toHandlers, 122 | toRaw, 123 | toRef, 124 | toRefs, 125 | toValue, 126 | transformVNodeArgs, 127 | triggerRef, 128 | unref, 129 | useAttrs, 130 | useCssModule, 131 | useCssVars, 132 | useModel, 133 | useSSRContext, 134 | useSlots, 135 | useTransitionState, 136 | vModelCheckbox, 137 | vModelDynamic, 138 | vModelRadio, 139 | vModelSelect, 140 | vModelText, 141 | vShow, 142 | version, 143 | warn, 144 | watch, 145 | watchEffect, 146 | watchPostEffect, 147 | watchSyncEffect, 148 | withAsyncContext, 149 | withCtx, 150 | withDefaults, 151 | withDirectives, 152 | withKeys, 153 | withMemo, 154 | withModifiers, 155 | withScopeId 156 | } from "./chunk-MFXDHSGI.js"; 157 | export { 158 | BaseTransition, 159 | BaseTransitionPropsValidators, 160 | Comment, 161 | EffectScope, 162 | Fragment, 163 | KeepAlive, 164 | ReactiveEffect, 165 | Static, 166 | Suspense, 167 | Teleport, 168 | Text, 169 | Transition, 170 | TransitionGroup, 171 | VueElement, 172 | assertNumber, 173 | callWithAsyncErrorHandling, 174 | callWithErrorHandling, 175 | camelize, 176 | capitalize, 177 | cloneVNode, 178 | compatUtils, 179 | compile, 180 | computed, 181 | createApp, 182 | createBlock, 183 | createCommentVNode, 184 | createElementBlock, 185 | createBaseVNode as createElementVNode, 186 | createHydrationRenderer, 187 | createPropsRestProxy, 188 | createRenderer, 189 | createSSRApp, 190 | createSlots, 191 | createStaticVNode, 192 | createTextVNode, 193 | createVNode, 194 | customRef, 195 | defineAsyncComponent, 196 | defineComponent, 197 | defineCustomElement, 198 | defineEmits, 199 | defineExpose, 200 | defineModel, 201 | defineOptions, 202 | defineProps, 203 | defineSSRCustomElement, 204 | defineSlots, 205 | devtools, 206 | effect, 207 | effectScope, 208 | getCurrentInstance, 209 | getCurrentScope, 210 | getTransitionRawChildren, 211 | guardReactiveProps, 212 | h, 213 | handleError, 214 | hasInjectionContext, 215 | hydrate, 216 | initCustomFormatter, 217 | initDirectivesForSSR, 218 | inject, 219 | isMemoSame, 220 | isProxy, 221 | isReactive, 222 | isReadonly, 223 | isRef, 224 | isRuntimeOnly, 225 | isShallow, 226 | isVNode, 227 | markRaw, 228 | mergeDefaults, 229 | mergeModels, 230 | mergeProps, 231 | nextTick, 232 | normalizeClass, 233 | normalizeProps, 234 | normalizeStyle, 235 | onActivated, 236 | onBeforeMount, 237 | onBeforeUnmount, 238 | onBeforeUpdate, 239 | onDeactivated, 240 | onErrorCaptured, 241 | onMounted, 242 | onRenderTracked, 243 | onRenderTriggered, 244 | onScopeDispose, 245 | onServerPrefetch, 246 | onUnmounted, 247 | onUpdated, 248 | openBlock, 249 | popScopeId, 250 | provide, 251 | proxyRefs, 252 | pushScopeId, 253 | queuePostFlushCb, 254 | reactive, 255 | readonly, 256 | ref, 257 | registerRuntimeCompiler, 258 | render, 259 | renderList, 260 | renderSlot, 261 | resolveComponent, 262 | resolveDirective, 263 | resolveDynamicComponent, 264 | resolveFilter, 265 | resolveTransitionHooks, 266 | setBlockTracking, 267 | setDevtoolsHook, 268 | setTransitionHooks, 269 | shallowReactive, 270 | shallowReadonly, 271 | shallowRef, 272 | ssrContextKey, 273 | ssrUtils, 274 | stop, 275 | toDisplayString, 276 | toHandlerKey, 277 | toHandlers, 278 | toRaw, 279 | toRef, 280 | toRefs, 281 | toValue, 282 | transformVNodeArgs, 283 | triggerRef, 284 | unref, 285 | useAttrs, 286 | useCssModule, 287 | useCssVars, 288 | useModel, 289 | useSSRContext, 290 | useSlots, 291 | useTransitionState, 292 | vModelCheckbox, 293 | vModelDynamic, 294 | vModelRadio, 295 | vModelSelect, 296 | vModelText, 297 | vShow, 298 | version, 299 | warn, 300 | watch, 301 | watchEffect, 302 | watchPostEffect, 303 | watchSyncEffect, 304 | withAsyncContext, 305 | withCtx, 306 | withDefaults, 307 | withDirectives, 308 | withKeys, 309 | withMemo, 310 | withModifiers, 311 | withScopeId 312 | }; 313 | //# sourceMappingURL=vue.js.map 314 | -------------------------------------------------------------------------------- /.vite/deps/vue.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # encode-byelide 2 | 印客学院 Vue3 低代码可视化项目实战 3 | 4 | ## 特性 5 | - 物料管理 6 | - 编排 7 | - 渲染 8 | - 数据管理 9 | - 流程引擎 10 | 11 | ## 效果展示 12 | 13 | PC 端布局编排 14 | ![pc 布局](example/layout-pc.jpg) 15 | 16 | mobile 端布局编排 17 | ![mobile 布局](example/layout-mobile.jpg) 18 | 19 | 数据源管理 20 | ![数据源](example/dataSource.jpg) 21 | 22 | 流程引擎 23 | ![流程引擎](example/flow.jpg) 24 | 25 | PC 渲染器 26 | ![pc 渲染器](example/runner-pc.jpg) 27 | 28 | mobile 渲染器 29 | ![mobile 渲染器](example/runner-mobile.jpg) 30 | 31 | ### 项目需求分析评审(入料、编排、渲染、出码) 32 | #### 背景介绍 33 | 近年来,无代码平台与可视化相关平台日益火热。 34 | 无代码允许开发人员低成本通过拖拉拽的方式快速构建企业内部系统或落地页,常见的无代码平台能力包括:审批流、应用构建等。其在企业开发提效与运营方面取得了不错的成绩。例如国外的:Coda、Airtable、Notion 等产品,例如国内的:明道云、极简云、ClickPaaS 等产品。构建无代码平台是一件有挑战性的事情,这节实战课会从业务与技术架构入手,带你彻底弄懂无代码平台研发。 35 | 36 | 可视化平台允许数据分析人员通过拖拉拽的方式快速组建仪表盘或数据分析大盘,其在企业运营方面发挥重要作用。例如国外的:PowerBI、Monday、Coda 等产品,国内的:观远数据、BDP、FineBI 等产品。构建可视化 SaaS 是一件非常有趣的事情,这节实战课会从业务与技术架构出发,带你从零完成可视化图表数据协议设计、图表渲染器开发、图表编排等功能。 37 | 38 | 当无代码遇上可视化,相信会有更多火花,没错,我们课程将这两大火热业务方向进行融合,带你真正体验大厂企业级项目的设计、开发与流程管控。 39 | 开发过程中,我们会严格按照大厂开发流程,从项目搭建、规范约定、技术选型与评估、需求分析到开发,每个流程细节我们都不会放过。技术选型方面,我们会选用 Vue3 作为技术栈,状态管理选用 Pinia,编辑器开发我们会基于 tiptap 来展开,Echarts 开发图表相关内容,除此之外,我们会向大家展示如何更优雅更松散处理复杂表单的场景。相信你学完后,一定会感慨自己就这样又更上了一层楼! 40 | 41 | 请注意无代码与低代码的主要区别: 42 | 1. 无代码一般面向普通用户,可以没有编程经验,可以以最简单形式搭建应用。而低代码需要用户具备一定的编程能力。 43 | 2. 在实现上,低代码比无代码更复杂,低代码还会存在例如 DSL 以及代码植入的能力,低代码的代码片段植入思路接近微前端。 44 | 核心能力 45 | - 可视化配置面板 46 | - 具有可拓展能力:组件、模板、逻辑复用 47 | - 生命周期管理:开发管理、页面管理、部署管理 48 | 49 | #### 架构设计 50 | ##### 物料堆 51 | 包含可供使用的物料,通常物料的组织与消费是插件化的,还有很多产品将物料组织发布到插件市场,可供用户自行拓展,这都是跟插件化思想与 js 沙盒设计离不开的。 52 | https://juejin.cn/post/6981374562877308936 53 | 54 | ##### 编排 55 | - 微内核思想:操作的是DSL(json树),f(state)->view 56 | - 组合和渲染层隔离 57 | - render runtime(渲染引擎sdk) + dsl(json) = 页面 58 | - 事件:DND拖拽、Mouse Event 59 | - 画布分层技术:借鉴浏览器渲染模型,使用冒泡机制,走到所有层 60 | - 第一层:div,负责渲染,render(dsl, document.querySelector("#root")) 61 | - 第二层:加一层div,只负责处理右键事件 62 | - 第三层:加一层div,只处理快捷键 63 | - event bus:所有层可通过 event bus 进行通信 64 | - 画布功能及拓展: 65 | - 简单编排 66 | - 物料均为块级,操作简便,不涉及复杂布局问题 67 | - 画布灵活编排 68 | - 无限画布、引导线(衫格)、吸附对齐、旋转、快捷键、右键、缩放 69 | - 无限画布:监听滚动事件,每次给画布加宽带 70 | - 引导线:使用div画线(高度和宽带为1px)、绝对定位可拖动,下方 71 | - 吸附对齐:计算想尽的dom节点,定6个点和3个线,距离相近时,设置距离为0 72 | 73 | ##### 配置面板 74 | 配置面板就是对物料进行配置,我们需要将数据、视图、操作解耦 75 | - 功能:撤销、重做、预览、提测、发布 76 | - 重做(undo/redo):使用队列,指针移动 77 | - 预览:render(dsl: {type, key,props{},animate{},actions:{},attrs:{},children[]}) 78 | - 中间层:权限控制、数据操作(转换),暴露部分api 79 | 这块比较考验大家对于复杂表单的设计实现 80 | 81 | ##### 渲染器与出码 82 | 通常平台会提供 schema 渲染页面的功能,同时也可将所有配置输出 JSON Schema,我们称为出码功能 83 | 84 | ##### 扩展功能与进阶(这部分内容) 85 | 历史记录和版本、模版、分享、主题 86 | 进阶:协同编辑、定时任务、微前端(集成到其他系统的能力)、混合开发 87 | - 混合开发:组件(ts、flow)和 json 混合开发 88 | - 逻辑的配置:使用流程图(flow),最后生成业务逻辑 89 | - 协同:crdt算法,yjs、ot 等方案 90 | 91 | #### Vue 项目基础架构设计,基于 Vite、Pinia、Vue-Router 92 | 技术选型 93 | - 包管理:pnpm 94 | - 工程化相关 95 | - vite 96 | - lint-staged 97 | - cspell 98 | - commitizen 99 | - cz-git 100 | - husky 101 | - zx 102 | - tsno 103 | - lint规范: 104 | - commitlint; 105 | - stylelint; 106 | - prettier; 107 | - eslint; 108 | - editorconfig; 109 | - Vue CLI、Vue3 110 | - Pinia 111 | - Vue-Router 112 | - 拖拽库:基于原生的 smooth-dnd 封装用于 Vue3 的拖拽组件 113 | - 编辑器:tiptap for vue3,https://tiptap.dev/installation/vue3 114 | - UI 库:Arco Design,https://arco.design/vue/docs/start 115 | - 表单校验:vee-validate,https://vee-validate.logaretm.com/v4/ 116 | - 流程编排:@vue-flow/core,https://vueflow.dev/ 117 | - 图表:echarts 118 | 119 | ## 📧 联系 120 | - 印客学院官网: http://encodestudio.cn 121 | - encode byelide https://github.com/encode-studio-fe/encode-byelide 122 | - GitHub: https://github.com/encode-studio-fe 123 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | // module.exports = { extends: ['@commitlint/config-conventional'] } 2 | 3 | // eslint-disable-next-line no-undef 4 | module.exports = { 5 | extends: ['@commitlint/config-conventional'], // extends can be nested 6 | parserPreset: 'conventional-changelog-conventionalcommits', 7 | prompt: { 8 | settings: {}, 9 | messages: { 10 | skip: ':skip', 11 | max: 'upper %d chars', 12 | min: '%d chars at least', 13 | emptyWarning: 'can not be empty', 14 | upperLimitWarning: 'over limit', 15 | lowerLimitWarning: 'below limit' 16 | }, 17 | types: [ 18 | { value: 'feat', name: 'feat: ✨ A new feature', emoji: '✨ ' }, 19 | { value: 'fix', name: 'fix: 🐛 A bug fix', emoji: '🐛 ' }, 20 | { value: 'docs', name: 'docs: 📝 Documentation only changes', emoji: '📝 ' }, 21 | { 22 | value: 'style', 23 | name: 'style: 💄 Changes that do not affect the meaning of the code', 24 | emoji: '💄 ' 25 | }, 26 | { 27 | value: 'refactor', 28 | name: 'refactor: 📦️ A code change that neither fixes a bug nor adds a feature', 29 | emoji: '📦️ ' 30 | }, 31 | { 32 | value: 'perf', 33 | name: 'perf: 🚀 A code change that improves performance', 34 | emoji: '🚀 ' 35 | }, 36 | { 37 | value: 'test', 38 | name: 'test: 🚨 Adding missing tests or correcting existing tests', 39 | emoji: '🚨 ' 40 | }, 41 | { 42 | value: 'build', 43 | name: 'build: 🛠 Changes that affect the build system or external dependencies', 44 | emoji: '🛠 ' 45 | }, 46 | { 47 | value: 'ci', 48 | name: 'ci: 🎡 Changes to our CI configuration files and scripts', 49 | emoji: '🎡 ' 50 | }, 51 | { 52 | value: 'chore', 53 | name: "chore: 🔨 Other changes that don't modify src or test files", 54 | emoji: '🔨 ' 55 | }, 56 | { value: 'revert', name: 'revert: ⏪️ Reverts a previous commit', emoji: ':rewind:' } 57 | ], 58 | useEmoji: true, 59 | confirmColorize: true, 60 | emojiAlign: 'center', 61 | questions: { 62 | scope: { 63 | description: 'What is the scope of this change (e.g. component or file name)' 64 | }, 65 | subject: { 66 | description: 'Write a short, imperative tense description of the change' 67 | }, 68 | body: { 69 | description: 'Provide a longer description of the change' 70 | }, 71 | isBreaking: { 72 | description: 'Are there any breaking changes?' 73 | }, 74 | breakingBody: { 75 | description: 76 | 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself' 77 | }, 78 | breaking: { 79 | description: 'Describe the breaking changes' 80 | }, 81 | isIssueAffected: { 82 | description: 'Does this change affect any open issues?' 83 | }, 84 | issuesBody: { 85 | description: 86 | 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself' 87 | }, 88 | issues: { 89 | description: 'Add issue references (e.g. "fix #123", "re #123".)' 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": ["@cspell/dict-lorem-ipsum/cspell-ext.json"], 3 | "caseSensitive": false, 4 | "dictionaries": ["custom-words"], 5 | "dictionaryDefinitions": [ 6 | { 7 | "name": "custom-words", 8 | "path": "./.cspell/custom-words.txt", 9 | "addWords": true 10 | } 11 | ], 12 | "ignorePaths": [ 13 | "**/node_modules/**", 14 | "**/dist/**", 15 | "**/lib/**", 16 | "**/docs/**", 17 | "**/stats.html", 18 | "**/detect.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'cypress' 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}', 6 | baseUrl: 'http://localhost:4173' 7 | } 8 | }) 9 | -------------------------------------------------------------------------------- /cypress/e2e/example.cy.ts: -------------------------------------------------------------------------------- 1 | // https://on.cypress.io/api 2 | 3 | describe('My First Test', () => { 4 | it('visits the app root url', () => { 5 | cy.visit('/') 6 | cy.contains('h1', 'You did it!') 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /cypress/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["./**/*", "../support/**/*"], 4 | "compilerOptions": { 5 | "isolatedModules": false, 6 | "target": "es5", 7 | "lib": ["es5", "dom"], 8 | "types": ["cypress"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************** 3 | // This example commands.ts shows you how to 4 | // create various custom commands and overwrite 5 | // existing commands. 6 | // 7 | // For more comprehensive examples of custom 8 | // commands please read more here: 9 | // https://on.cypress.io/custom-commands 10 | // *********************************************** 11 | // 12 | // 13 | // -- This is a parent command -- 14 | // Cypress.Commands.add('login', (email, password) => { ... }) 15 | // 16 | // 17 | // -- This is a child command -- 18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 19 | // 20 | // 21 | // -- This is a dual command -- 22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 23 | // 24 | // 25 | // -- This will overwrite an existing command -- 26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 27 | // 28 | // declare global { 29 | // namespace Cypress { 30 | // interface Chainable { 31 | // login(email: string, password: string): Chainable 32 | // drag(subject: string, options?: Partial): Chainable 33 | // dismiss(subject: string, options?: Partial): Chainable 34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable 35 | // } 36 | // } 37 | // } 38 | 39 | export {} 40 | -------------------------------------------------------------------------------- /cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /example/dataSource.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/example/dataSource.jpg -------------------------------------------------------------------------------- /example/flow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/example/flow.jpg -------------------------------------------------------------------------------- /example/layout-mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/example/layout-mobile.jpg -------------------------------------------------------------------------------- /example/layout-pc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/example/layout-pc.jpg -------------------------------------------------------------------------------- /example/runner-mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/example/runner-mobile.jpg -------------------------------------------------------------------------------- /example/runner-pc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/example/runner-pc.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Byelide 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "byelide", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "run-p type-check build-only", 8 | "preview": "vite preview", 9 | "test:unit": "vitest", 10 | "test:e2e": "start-server-and-test preview http://localhost:4173 'cypress run --e2e'", 11 | "test:e2e:dev": "start-server-and-test 'vite dev --port 4173' http://localhost:4173 'cypress open --e2e'", 12 | "build-only": "vite build", 13 | "spellcheck": "cspell lint --dot --gitignore --color --cache --show-suggestions \"src/**/*.@(html|js|cjs|mjs|ts|tsx|css|scss|md|vue)\"", 14 | "type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false", 15 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", 16 | "lint:style": "stylelint **/*.{vue,css}", 17 | "lint:stage": "lint-staged", 18 | "format": "prettier --write src/", 19 | "check": "tsno run ./scripts/check.ts", 20 | "prepare": "husky install", 21 | "commit": "git-cz", 22 | "commitlint": "commitlint --edit" 23 | }, 24 | "lint-staged": { 25 | "*": "prettier --write", 26 | "*.{vue,ts}": "eslint --fix", 27 | "*.{html,vue,css,sass,scss}": "stylelint --fix" 28 | }, 29 | "dependencies": { 30 | "pinia": "2.1.4", 31 | "vue": "3.3.4", 32 | "vue-router": "4.2.4", 33 | "@icon-park/vue-next": "1.4.2", 34 | "smooth-dnd": "0.12.1", 35 | "@vue-flow/core": "1.21.2", 36 | "@vue-flow/additional-components": "1.3.3", 37 | "vee-validate": "4.10.7", 38 | "@tiptap/core": "2.0.4", 39 | "@tiptap/vue-3": "2.0.4", 40 | "@tiptap/pm": "2.0.4", 41 | "@tiptap/starter-kit": "2.0.4", 42 | "veaury": "2.3.12", 43 | "@glideapps/glide-data-grid": "5.2.1", 44 | "react": "18.2.0", 45 | "react-dom": "18.2.0", 46 | "echarts": "5.4.3", 47 | "vue-echarts": "6.6.0", 48 | "zrender": "5.4.4", 49 | "d3": "7.8.5", 50 | "vue-json-pretty": "2.2.4", 51 | "copy-text-to-clipboard": "3.2.0", 52 | "nanoid": "5.0.4" 53 | }, 54 | "devDependencies": { 55 | "@commitlint/cli": "17.6.7", 56 | "@commitlint/config-conventional": "17.6.7", 57 | "@commitlint/cz-commitlint": "17.6.7", 58 | "stylelint": "15.10.2", 59 | "stylelint-config-standard": "34.0.0", 60 | "stylelint-config-prettier": "9.0.5", 61 | "stylelint-config-html": "1.1.0", 62 | "stylelint-config-vue": "1.0.0", 63 | "@rushstack/eslint-patch": "1.3.2", 64 | "@tsconfig/node18": "18.2.0", 65 | "@types/jsdom": "^21.1.1", 66 | "@types/node": "20.4.2", 67 | "@types/d3": "7.4.0", 68 | "@vitejs/plugin-vue": "4.2.3", 69 | "@vitejs/plugin-react": "4.0.3", 70 | "@vitejs/plugin-vue-jsx": "3.0.1", 71 | "@vue/eslint-config-prettier": "8.0.0", 72 | "@vue/eslint-config-typescript": "^11.0.3", 73 | "@vue/test-utils": "2.4.1", 74 | "@vue/tsconfig": "^0.4.0", 75 | "cspell": "6.31.2", 76 | "cypress": "12.17.2", 77 | "eslint": "8.45.0", 78 | "eslint-plugin-cypress": "2.13.3", 79 | "eslint-plugin-vue": "9.15.1", 80 | "eslint-plugin-simple-import-sort": "10.0.0", 81 | "husky": "8.0.3", 82 | "jsdom": "22.1.0", 83 | "lint-staged": "13.2.3", 84 | "npm-run-all": "4.1.5", 85 | "prettier": "3.0.0", 86 | "start-server-and-test": "^2.0.0", 87 | "tsno": "2.0.0", 88 | "typescript": "5.1.6", 89 | "vite": "4.4.5", 90 | "vitest": "0.33.0", 91 | "vue-tsc": "1.8.5", 92 | "zx": "7.2.3", 93 | "commitizen": "4.3.0", 94 | "cz-git": "1.7.0", 95 | "rollup-plugin-visualizer": "5.9.2" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/public/favicon.ico -------------------------------------------------------------------------------- /scripts/check.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zx 2 | 3 | import type { ProcessOutput } from 'zx' 4 | import { $ } from 'zx' 5 | 6 | import { printObject } from './utils' 7 | 8 | await $`pnpm spellcheck`.catch((out: ProcessOutput) => { 9 | console.log(out) 10 | 11 | throw new Error(out.stdout) 12 | }) 13 | 14 | // await Promise.all([$`pnpm type-check`, $`pnpm lint`]).catch((out: ProcessOutput) => { 15 | // printObject(out) 16 | // throw new Error(out.stdout) 17 | // }) 18 | 19 | // check type and stage 20 | await Promise.all([$`pnpm type-check`, $`pnpm lint`]).catch((out: ProcessOutput) => { 21 | printObject(out) 22 | throw new Error(out.stdout) 23 | }) 24 | -------------------------------------------------------------------------------- /scripts/pre-commit.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zx 2 | 3 | import { $ } from 'zx' 4 | 5 | console.log('开始执行代码质量评估...\n') 6 | 7 | await import('./check').catch((out) => { 8 | throw new Error('代码质量评估失败, 请检查代码') 9 | }) 10 | 11 | console.log('printf "检测通过, 创建 commit 中...\n') 12 | 13 | await $`git add .` 14 | -------------------------------------------------------------------------------- /scripts/utils.ts: -------------------------------------------------------------------------------- 1 | import { ProcessOutput } from 'zx/core' 2 | 3 | export function printObject( 4 | object: Record | ProcessOutput, 5 | method: 'log' | 'warn' | 'error' = 'log' 6 | ) { 7 | for (const [key, value] of Object.entries(object)) { 8 | // eslint-disable-next-line no-console 9 | console[method](`${key}:\n${value}\n`) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /src/assets/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::before, 3 | *::after { 4 | box-sizing: border-box; 5 | margin: 0; 6 | } 7 | 8 | body { 9 | min-height: 100vh; 10 | color: var(--color-text); 11 | background: var(--color-background); 12 | transition: 13 | color 0.5s, 14 | background-color 0.5s; 15 | line-height: 1.6; 16 | font-family: 17 | Inter, 18 | -apple-system, 19 | BlinkMacSystemFont, 20 | 'Segoe UI', 21 | Roboto, 22 | Oxygen, 23 | Ubuntu, 24 | Cantarell, 25 | 'Open Sans', 26 | 'Helvetica Neue', 27 | 'Icons16', 28 | sans-serif; 29 | font-size: var(--font-size-normal); 30 | text-rendering: optimizelegibility; 31 | -webkit-font-smoothing: antialiased; 32 | -moz-osx-font-smoothing: grayscale; 33 | } 34 | 35 | /* .tiny-scrollbar::-webkit-scrollbar { 36 | scrollbar-width: thin; 37 | scrollbar-color: var(--color-gray-400) var(--color-gray-100); 38 | } */ 39 | 40 | /* width */ 41 | .tiny-scrollbar::-webkit-scrollbar { 42 | width: 6px; 43 | } 44 | 45 | /* Track */ 46 | .tiny-scrollbar::-webkit-scrollbar-track { 47 | background: var(--color-gray-100); 48 | } 49 | 50 | /* Handle */ 51 | .tiny-scrollbar::-webkit-scrollbar-thumb { 52 | border-radius: 8px; 53 | background: var(--color-gray-400); 54 | } 55 | 56 | .i-icon { 57 | line-height: 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/main.css: -------------------------------------------------------------------------------- 1 | @import url('./reset.css'); 2 | @import url('./base.css'); 3 | @import url('./variable.css'); 4 | 5 | a, 6 | .green { 7 | text-decoration: none; 8 | color: hsl(160deg 100% 37% / 100%); 9 | transition: 0.4s; 10 | } 11 | 12 | @media (hover: hover) { 13 | a:hover { 14 | background-color: hsl(160deg 100% 37% / 20%); 15 | } 16 | } 17 | 18 | @media (width >= 1024px) { 19 | body { 20 | display: flex; 21 | flex-direction: column; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/assets/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, 7 | body, 8 | div, 9 | span, 10 | applet, 11 | object, 12 | iframe, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | blockquote, 21 | pre, 22 | a, 23 | abbr, 24 | acronym, 25 | address, 26 | big, 27 | cite, 28 | code, 29 | del, 30 | dfn, 31 | em, 32 | img, 33 | ins, 34 | kbd, 35 | q, 36 | s, 37 | samp, 38 | small, 39 | strike, 40 | strong, 41 | sub, 42 | sup, 43 | tt, 44 | var, 45 | b, 46 | u, 47 | i, 48 | center, 49 | dl, 50 | dt, 51 | dd, 52 | ol, 53 | ul, 54 | li, 55 | fieldset, 56 | form, 57 | label, 58 | legend, 59 | table, 60 | caption, 61 | tbody, 62 | tfoot, 63 | thead, 64 | tr, 65 | th, 66 | td, 67 | article, 68 | aside, 69 | canvas, 70 | details, 71 | embed, 72 | figure, 73 | figcaption, 74 | footer, 75 | header, 76 | hgroup, 77 | menu, 78 | nav, 79 | output, 80 | ruby, 81 | section, 82 | summary, 83 | time, 84 | mark, 85 | audio, 86 | video { 87 | margin: 0; 88 | padding: 0; 89 | border: 0; 90 | font-size: 100%; 91 | vertical-align: baseline; 92 | } 93 | 94 | /* HTML5 display-role reset for older browsers */ 95 | article, 96 | aside, 97 | details, 98 | figcaption, 99 | figure, 100 | footer, 101 | header, 102 | hgroup, 103 | menu, 104 | nav, 105 | section { 106 | display: block; 107 | } 108 | 109 | body { 110 | line-height: 1; 111 | } 112 | 113 | ol, 114 | ul { 115 | list-style: none; 116 | } 117 | 118 | blockquote, 119 | q { 120 | quotes: none; 121 | } 122 | 123 | blockquote::before, 124 | blockquote::after, 125 | q::before, 126 | q::after { 127 | content: ''; 128 | content: none; 129 | } 130 | 131 | table { 132 | border-collapse: collapse; 133 | border-spacing: 0; 134 | } 135 | -------------------------------------------------------------------------------- /src/assets/variable.css: -------------------------------------------------------------------------------- 1 | :root { 2 | /* font size */ 3 | --font-size-small: 12px; 4 | --font-size-normal: 14px; 5 | --font-size-large: 16px; 6 | 7 | /* font weight */ 8 | --font-weight-light: 300; 9 | --font-weight-normal: 400; 10 | --font-weight-bold: 500; 11 | --font-weight-bolder: 700; 12 | 13 | /* 颜色相关 */ 14 | 15 | /* gray */ 16 | --color-gray-100: #f8f8f8; 17 | --color-gray-200: #f2f2f2; 18 | --color-gray-300: #e6e6e6; 19 | --color-gray-400: #d9d9d9; 20 | --color-gray-500: #ccc; 21 | --color-gray-600: #b3b3b3; 22 | --color-gray-700: #999; 23 | --color-gray-800: #666; 24 | --color-gray-900: #333; 25 | 26 | /* blue */ 27 | --color-blue-100: #e6f7ff; 28 | --color-blue-200: #bae7ff; 29 | --color-blue-300: #91d5ff; 30 | --color-blue-400: #69c0ff; 31 | --color-blue-500: #40a9ff; 32 | --color-blue-600: #6592b7; 33 | --color-blue-700: #096dd9; 34 | --color-blue-800: #0050b3; 35 | --color-blue-900: #003a8c; 36 | 37 | /* white black */ 38 | --color-white: #fff; 39 | --color-black: var(--color-gray-900); 40 | 41 | /* theme */ 42 | --color-primary: var(--color-blue-600); 43 | 44 | /* mics */ 45 | --panel-width: 320px; 46 | } 47 | 48 | /* color palette from */ 49 | 50 | /* :root { 51 | --vt-c-white: #ffffff; 52 | --vt-c-white-soft: #f8f8f8; 53 | --vt-c-white-mute: #f2f2f2; 54 | 55 | --vt-c-black: #181818; 56 | --vt-c-black-soft: #222222; 57 | --vt-c-black-mute: #282828; 58 | 59 | --vt-c-indigo: #333333; 60 | 61 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); 62 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); 63 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); 64 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); 65 | 66 | --vt-c-text-light-1: var(--vt-c-indigo); 67 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66); 68 | --vt-c-text-dark-1: var(--vt-c-white); 69 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); 70 | } 71 | 72 | :root { 73 | --color-background: var(--vt-c-white); 74 | --color-background-soft: var(--vt-c-white-soft); 75 | --color-background-mute: var(--vt-c-white-mute); 76 | 77 | --color-border: var(--vt-c-divider-light-2); 78 | --color-border-hover: var(--vt-c-divider-light-1); 79 | 80 | --color-heading: var(--vt-c-text-light-1); 81 | --color-text: var(--vt-c-text-light-1); 82 | 83 | --section-gap: 160px; 84 | } 85 | 86 | @media (prefers-color-scheme: dark) { 87 | :root { 88 | --color-background: var(--vt-c-black); 89 | --color-background-soft: var(--vt-c-black-soft); 90 | --color-background-mute: var(--vt-c-black-mute); 91 | 92 | --color-border: var(--vt-c-divider-dark-2); 93 | --color-border-hover: var(--vt-c-divider-dark-1); 94 | 95 | --color-heading: var(--vt-c-text-dark-1); 96 | --color-text: var(--vt-c-text-dark-2); 97 | } 98 | } */ 99 | -------------------------------------------------------------------------------- /src/blocks/BlockRenderer.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 60 | 61 | 137 | 138 | 143 | -------------------------------------------------------------------------------- /src/blocks/BlockRendererVuedraggable.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 222 | -------------------------------------------------------------------------------- /src/blocks/BlocksRenderer.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 65 | 66 | 145 | 146 | 151 | -------------------------------------------------------------------------------- /src/blocks/basic/ChartBlock.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/blocks/basic/HeroTitleBlock.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /src/blocks/basic/ImageBlock.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /src/blocks/basic/QuoteBlock.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /src/blocks/basic/ViewBlock.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/blocks/external/ButtonBlock.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /src/blocks/external/FormBlock.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 45 | 46 | 58 | -------------------------------------------------------------------------------- /src/blocks/external/NotesBlock.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /src/components/AppEditorRenderer/AppEditorRenderer.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | 27 | 37 | -------------------------------------------------------------------------------- /src/components/AppEditorRenderer/LaptopPreviewer.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 48 | 49 | 130 | -------------------------------------------------------------------------------- /src/components/AppEditorRenderer/MobilePreviewer.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 38 | 39 | 119 | -------------------------------------------------------------------------------- /src/components/AppEditorRenderer/PreviewModeSwitcher.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 46 | 47 | 73 | -------------------------------------------------------------------------------- /src/components/AppEditorRenderer/StatusBar.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 64 | 65 | 70 | -------------------------------------------------------------------------------- /src/components/AppEditorRenderer/type.ts: -------------------------------------------------------------------------------- 1 | export type PreviewType = 'mobile' | 'laptop' 2 | -------------------------------------------------------------------------------- /src/components/AppLeftPanel/AppLeftPanel.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 49 | 50 | 117 | -------------------------------------------------------------------------------- /src/components/AppLeftPanel/BlocksDrawer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 36 | 37 | 92 | -------------------------------------------------------------------------------- /src/components/AppLeftPanel/OutlineDrawer.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | 28 | 63 | -------------------------------------------------------------------------------- /src/components/AppNavigator.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 130 | 131 | 235 | -------------------------------------------------------------------------------- /src/components/AppPreviewer/LaptopPreviewer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 58 | -------------------------------------------------------------------------------- /src/components/AppPreviewer/MobilePreviewer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | 19 | 78 | -------------------------------------------------------------------------------- /src/components/AppRightPanel/AppRightPanel.vue: -------------------------------------------------------------------------------- 1 | 42 | 43 | 69 | 70 | 94 | -------------------------------------------------------------------------------- /src/components/AppRightPanel/ChartSetting.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 62 | 63 | 77 | -------------------------------------------------------------------------------- /src/components/AppRightPanel/QuoteSetting.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 61 | 62 | 95 | -------------------------------------------------------------------------------- /src/components/AppRightPanel/SchemaExporter.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 35 | 36 | 64 | 65 | 74 | -------------------------------------------------------------------------------- /src/components/AppRunnerRenderer/AppRunnerRenderer.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 42 | 43 | 84 | -------------------------------------------------------------------------------- /src/components/ChartRenderer/CanvasChartRenderer/CanvasChartRenderer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 103 | 104 | 111 | -------------------------------------------------------------------------------- /src/components/ChartRenderer/ChartRenderer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/components/ChartRenderer/EchartsRenderer/EchartsRenderer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 229 | 230 | 235 | -------------------------------------------------------------------------------- /src/components/ChartRenderer/SVGChartRenderer/SVGChartRenderer.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 81 | 82 | 88 | 89 | 101 | -------------------------------------------------------------------------------- /src/components/DataSourceLeftPanel.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 49 | 50 | 86 | -------------------------------------------------------------------------------- /src/components/FlowEditor/FlowEditor.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 97 | 98 | 131 | -------------------------------------------------------------------------------- /src/components/FlowEditor/initial-elements.ts: -------------------------------------------------------------------------------- 1 | import { MarkerType } from '@vue-flow/core' 2 | 3 | /** 4 | * You can pass elements together as a v-model value 5 | * or split them up into nodes and edges and pass them to the `nodes` and `edges` props of Vue Flow (or useVueFlow composable) 6 | */ 7 | export const initialElements = [ 8 | { id: '1', type: 'input', label: 'Node 1', position: { x: 250, y: 0 }, class: 'light' }, 9 | { id: '2', type: 'output', label: 'Node 2', position: { x: 100, y: 100 }, class: 'light' }, 10 | { id: '3', label: 'Node 3', position: { x: 400, y: 100 }, class: 'light' }, 11 | { id: '4', label: 'Node 4', position: { x: 150, y: 200 }, class: 'light' }, 12 | { id: '5', type: 'output', label: 'Node 5', position: { x: 300, y: 300 }, class: 'light' }, 13 | { id: 'e1-2', source: '1', target: '2', animated: true }, 14 | { 15 | id: 'e1-3', 16 | label: 'edge with arrowhead', 17 | source: '1', 18 | target: '3', 19 | markerEnd: MarkerType.ArrowClosed 20 | }, 21 | { 22 | id: 'e4-5', 23 | type: 'step', 24 | label: 'step-edge', 25 | source: '4', 26 | target: '5', 27 | style: { stroke: 'orange' }, 28 | labelBgStyle: { fill: 'orange' } 29 | }, 30 | { id: 'e3-4', type: 'smoothstep', label: 'smoothstep-edge', source: '3', target: '4' } 31 | ] 32 | -------------------------------------------------------------------------------- /src/components/NotesEditor/NotesEditor.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 56 | 57 | 103 | 104 | 148 | -------------------------------------------------------------------------------- /src/components/NotesEditor/extensions/ColorHighlighter.ts: -------------------------------------------------------------------------------- 1 | import { Extension } from '@tiptap/core' 2 | import { Plugin } from '@tiptap/pm/state' 3 | 4 | import { findColors } from '../helper' 5 | 6 | export const ColorHighlighter = Extension.create({ 7 | name: 'colorHighlighter', 8 | 9 | addProseMirrorPlugins() { 10 | return [ 11 | new Plugin({ 12 | state: { 13 | init(_, { doc }) { 14 | return findColors(doc) 15 | }, 16 | apply(transaction, oldState) { 17 | return transaction.docChanged ? findColors(transaction.doc) : oldState 18 | } 19 | }, 20 | props: { 21 | decorations(state) { 22 | return this.getState(state) 23 | } 24 | } 25 | }) 26 | ] 27 | } 28 | }) 29 | -------------------------------------------------------------------------------- /src/components/NotesEditor/helper.ts: -------------------------------------------------------------------------------- 1 | import { Node } from '@tiptap/pm/model' 2 | import { Decoration, DecorationSet } from '@tiptap/pm/view' 3 | 4 | export function findColors(doc: Node): DecorationSet { 5 | const hexColor = /(#[0-9a-f]{3,6})\b/gi 6 | const decorations: Decoration[] = [] 7 | 8 | doc.descendants((node, position) => { 9 | if (!node.text) { 10 | return 11 | } 12 | 13 | Array.from(node.text.matchAll(hexColor)).forEach((match) => { 14 | const color = match[0] 15 | const index = match.index || 0 16 | const from = position + index 17 | const to = from + color.length 18 | const decoration = Decoration.inline(from, to, { 19 | class: 'color', 20 | style: `--color: ${color}` 21 | }) 22 | 23 | decorations.push(decoration) 24 | }) 25 | }) 26 | 27 | return DecorationSet.create(doc, decorations) 28 | } 29 | -------------------------------------------------------------------------------- /src/components/SmoothDnd/SmoothDndContainer.ts: -------------------------------------------------------------------------------- 1 | import type { SmoothDnD } from 'smooth-dnd' 2 | import { dropHandlers, smoothDnD } from 'smooth-dnd' 3 | import { defineComponent, h } from 'vue' 4 | 5 | import { getTagProps, validateTagProp } from './utils' 6 | 7 | smoothDnD.dropHandler = dropHandlers.reactDropHandler().handler 8 | smoothDnD.wrapChild = false 9 | 10 | type EventKey = 'drag-start' | 'drag-end' | 'drop' | 'drag-enter' | 'drag-leave' | 'drop-ready' 11 | 12 | const eventEmitterMap: Record = { 13 | 'drag-start': 'onDragStart', 14 | 'drag-end': 'onDragEnd', 15 | drop: 'onDrop', 16 | 'drag-enter': 'onDragEnter', 17 | 'drag-leave': 'onDragLeave', 18 | 'drop-ready': 'onDropReady' 19 | } 20 | 21 | export const SmoothDndContainer = defineComponent({ 22 | name: 'SmoothDndContainer', 23 | setup() { 24 | return { 25 | container: null as SmoothDnD | null 26 | } 27 | }, 28 | mounted() { 29 | // emit events 30 | const options: any = Object.assign({}, this.$props) 31 | for (const key in eventEmitterMap) { 32 | const eventKey = key as EventKey 33 | options[eventEmitterMap[eventKey]] = (props: any) => { 34 | this.$emit(eventKey, props) 35 | } 36 | } 37 | const containerElement = this.$refs.container || this.$el 38 | this.container = smoothDnD(containerElement, options) 39 | }, 40 | unmounted() { 41 | if (this.container) { 42 | try { 43 | this.container.dispose() 44 | } catch { 45 | // ignore 46 | } 47 | } 48 | }, 49 | emits: ['drop', 'drag-start', 'drag-end', 'drag-enter', 'drag-leave', 'drop-ready'], 50 | props: { 51 | orientation: { type: String, default: 'vertical' }, 52 | removeOnDropOut: { type: Boolean, default: false }, 53 | autoScrollEnabled: { type: Boolean, default: true }, 54 | animationDuration: { type: Number, default: 250 }, 55 | behaviour: String, 56 | groupName: String, 57 | dragHandleSelector: String, 58 | nonDragAreaSelector: String, 59 | lockAxis: String, 60 | dragClass: String, 61 | dropClass: String, 62 | dragBeginDelay: Number, 63 | getChildPayload: Function, 64 | shouldAnimateDrop: Function, 65 | shouldAcceptDrop: Function, 66 | getGhostParent: Function, 67 | dropPlaceholder: [Object, Boolean], 68 | tag: { 69 | validator: validateTagProp, 70 | default: 'div' 71 | } 72 | }, 73 | render() { 74 | const tagProps = getTagProps(this) 75 | return h( 76 | tagProps.value, 77 | Object.assign({}, { ref: 'container' }, tagProps.props), 78 | this.$slots.default?.() 79 | ) 80 | } 81 | }) 82 | -------------------------------------------------------------------------------- /src/components/SmoothDnd/SmoothDndDraggable.ts: -------------------------------------------------------------------------------- 1 | import { constants } from 'smooth-dnd' 2 | import { defineComponent, h } from 'vue' 3 | 4 | import { getTagProps, validateTagProp } from './utils' 5 | 6 | export const SmoothDndDraggable = defineComponent({ 7 | name: 'SmoothDndDraggable', 8 | props: { 9 | tag: { 10 | validator: validateTagProp, 11 | default: 'div' 12 | } 13 | }, 14 | render: function () { 15 | //wrap child 16 | const tagProps = getTagProps(this, constants.wrapperClass) 17 | return h(tagProps.value, Object.assign({}, tagProps.props), this.$slots?.default?.()) 18 | } 19 | }) 20 | -------------------------------------------------------------------------------- /src/components/SmoothDnd/deprecate__SmoothDndContainer.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/components/SmoothDnd/deprecate__SmoothDndDraggable.vue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/SmoothDnd/utils.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from 'vue' 2 | 3 | /** 4 | * Checks if tag or tag.value (ref) is string function or object 5 | * @param {*} tag 6 | * @returns boolean 7 | */ 8 | export function validateTagProp(tag?: Ref) { 9 | if (tag) { 10 | if (typeof tag === 'string') return true 11 | if (typeof tag === 'object') { 12 | if ( 13 | typeof tag.value === 'string' || 14 | typeof tag.value === 'function' || 15 | typeof tag.value === 'object' 16 | ) { 17 | return true 18 | } 19 | } 20 | return false 21 | } 22 | return true 23 | } 24 | 25 | export function getTagProps(ctx: any, tagClass?: string) { 26 | const tag = ctx.$props.tag 27 | if (tag) { 28 | if (typeof tag === 'string') { 29 | const result: any = { value: tag } 30 | if (tagClass) { 31 | result.props = { class: tagClass } 32 | } 33 | return result 34 | } else if (typeof tag === 'object') { 35 | const result = { value: tag.value || 'div', props: tag.props || {} } 36 | if (tagClass) { 37 | if (result.props.class) { 38 | if (Array.isArray(result.props.class)) { 39 | result.props.class.push(tagClass) 40 | } else { 41 | result.props.class = [tagClass, result.props.class] 42 | } 43 | } else { 44 | result.props.class = tagClass 45 | } 46 | } 47 | return result 48 | } 49 | } 50 | return { value: 'div' } 51 | } 52 | -------------------------------------------------------------------------------- /src/components/__tests__/AppNavigator.ts: -------------------------------------------------------------------------------- 1 | import { mount } from '@vue/test-utils' 2 | import { describe, expect,it } from 'vitest' 3 | 4 | import AppNavigator from '../AppNavigator.vue' 5 | 6 | describe('AppNavigator', () => { 7 | it('renders properly', () => { 8 | const wrapper = mount(AppNavigator, { props: { msg: 'Hello Vitest' } }) 9 | expect(wrapper.text()).toContain('Hello Vitest') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /src/constants/blocksBaseMeta.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChartLine, 3 | Form, 4 | HamburgerButton, 5 | ImageFiles, 6 | Notes, 7 | Quote, 8 | Table, 9 | TitleLevel 10 | } from '@icon-park/vue-next' 11 | import type { Icon } from '@icon-park/vue-next/lib/runtime' 12 | import { nanoid } from 'nanoid' 13 | 14 | import type { BlockInfo, BlockType } from '@/types/block' 15 | 16 | export const blocksBaseMetaList: { type: BlockType; label: string; icon: Icon }[] = [ 17 | { 18 | type: 'quote', 19 | label: '引述', 20 | icon: Quote 21 | }, 22 | { 23 | type: 'notes', 24 | label: '笔记', 25 | icon: Notes 26 | }, 27 | { 28 | type: 'heroTitle', 29 | label: '超级标题', 30 | icon: TitleLevel 31 | }, 32 | { type: 'image', label: '图片', icon: ImageFiles }, 33 | { 34 | type: 'view', 35 | label: '视图', 36 | icon: Table 37 | }, 38 | { 39 | type: 'chart', 40 | label: '图表', 41 | icon: ChartLine 42 | }, 43 | { 44 | type: 'button', 45 | label: '按钮', 46 | icon: HamburgerButton 47 | }, 48 | { 49 | type: 'form', 50 | label: '表单', 51 | icon: Form 52 | } 53 | ] 54 | 55 | export const blocksBaseMeta = Object.fromEntries( 56 | blocksBaseMetaList.map((item) => [item.type, item]) 57 | ) 58 | 59 | export const getBlocksDefaultData = (type: BlockType): BlockInfo => { 60 | const id = nanoid() 61 | switch (type) { 62 | case 'quote': 63 | return { 64 | id, 65 | type: 'quote', 66 | label: '引述', 67 | props: { 68 | content: '引述文本 quote', 69 | status: 'success' 70 | } 71 | } 72 | case 'notes': 73 | return { 74 | id, 75 | type: 'notes', 76 | label: '笔记', 77 | props: { 78 | content: ` 79 |

I’m running Tiptap with Vue.js. 🎉

80 |

You can also teach the editor new things. For example to recognize hex colors and add a color

81 |

swatch on the fly: #FFF, #0D0D0D, #616161, #A975FF, #FB5151, #FD9170, #FFCB6B, #68CEF8, #80cbc4, #9DEF8F

82 | ` 83 | } 84 | } 85 | case 'heroTitle': 86 | return { 87 | id, 88 | type: 'heroTitle', 89 | label: '标题', 90 | props: { 91 | content: '标题' 92 | } 93 | } 94 | case 'image': 95 | return { 96 | id, 97 | type: 'image', 98 | label: '图片', 99 | props: { 100 | url: 'https://images.pexels.com/photos/2577274/pexels-photo-2577274.jpeg?auto=compress&cs=tinysrgb&w=1600' 101 | } 102 | } 103 | case 'view': 104 | return { 105 | id, 106 | type: 'view', 107 | label: '视图', 108 | props: { 109 | fields: { 110 | id: { 111 | type: 'text' 112 | } 113 | }, 114 | fieldProps: [], 115 | data: [] 116 | } 117 | } 118 | case 'chart': 119 | return { 120 | id, 121 | type: 'chart', 122 | label: '图表', 123 | props: { 124 | chartType: 'echarts' 125 | } 126 | } 127 | case 'button': 128 | return { 129 | id, 130 | type: 'button', 131 | label: '按钮', 132 | props: { 133 | content: '按钮' 134 | } 135 | } 136 | case 'form': 137 | return { 138 | id, 139 | type: 'form', 140 | label: '表单', 141 | props: { 142 | fields: [] 143 | } 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/hooks/useClickOutside.ts: -------------------------------------------------------------------------------- 1 | import type { Ref } from "vue" 2 | 3 | import { useAppEditorStore } from "@/stores/appEditor" 4 | 5 | export const useClickOutside = (domRef: Ref) => { 6 | const appEditorStore = useAppEditorStore() 7 | 8 | const handleClickOutside = (e: MouseEvent) => { 9 | if (!appEditorStore.currentBlockId) return 10 | if (!domRef.value?.contains(e.target as HTMLElement)) { 11 | appEditorStore.selectBlock('') 12 | } 13 | } 14 | 15 | document.addEventListener('click', handleClickOutside) 16 | 17 | return () => { 18 | document.removeEventListener('click', handleClickOutside) 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import './assets/main.css' 2 | 3 | import { createPinia } from 'pinia' 4 | import { createApp } from 'vue' 5 | 6 | import App from './App.vue' 7 | import router from './router' 8 | import { setup } from './setup' 9 | 10 | const app = createApp(App) 11 | 12 | app.use(createPinia()) 13 | app.use(router) 14 | 15 | setup(app) 16 | 17 | app.mount('#app') 18 | -------------------------------------------------------------------------------- /src/mocks/blocks.ts: -------------------------------------------------------------------------------- 1 | import type { BlockInfo } from '@/types/block' 2 | 3 | export const blocks: BlockInfo[] = [ 4 | { 5 | id: '1', 6 | type: 'quote', 7 | label: '引述', 8 | props: { 9 | content: '引述文本 quote', 10 | status: 'success' 11 | } 12 | }, 13 | { 14 | id: '2', 15 | type: 'chart', 16 | label: '图表', 17 | props: { 18 | chartType: 'echarts' 19 | } 20 | }, 21 | { 22 | id: '3', 23 | type: 'notes', 24 | label: '笔记', 25 | props: { 26 | content: ` 27 |

I’m running Tiptap with Vue.js. 🎉

28 |

You can also teach the editor new things. For example to recognize hex colors and add a color

29 |

swatch on the fly: #FFF, #0D0D0D, #616161, #A975FF, #FB5151, #FD9170, #FFCB6B, #68CEF8, #80cbc4, #9DEF8F

30 | ` 31 | } 32 | }, 33 | { 34 | id: '4', 35 | type: 'heroTitle', 36 | label: '标题', 37 | props: { 38 | content: '标题' 39 | } 40 | }, 41 | { 42 | id: '5', 43 | type: 'image', 44 | label: '图片', 45 | props: { 46 | url: 'https://images.pexels.com/photos/2577274/pexels-photo-2577274.jpeg?auto=compress&cs=tinysrgb&w=1600' 47 | } 48 | }, 49 | { 50 | id: '6', 51 | type: 'view', 52 | label: '视图', 53 | props: { 54 | fields: { 55 | 'id': { 56 | type: 'text', 57 | }, 58 | }, 59 | fieldProps: [], 60 | data: [], 61 | 62 | } 63 | }, 64 | { 65 | id: '7', 66 | type: 'button', 67 | label: '按钮', 68 | props: { 69 | content: '按钮' 70 | } 71 | }, 72 | { 73 | id: '8', 74 | type: 'form', 75 | label: '表单', 76 | props: { 77 | fields: [] 78 | } 79 | } 80 | ] 81 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { defineAsyncComponent } from 'vue' 2 | import { createMemoryHistory, createRouter, createWebHistory } from 'vue-router' 3 | 4 | import AppView from '../views/AppView.vue' 5 | 6 | const router = createRouter({ 7 | history: createWebHistory(import.meta.env.BASE_URL), 8 | routes: [ 9 | { 10 | path: '/app', 11 | name: 'home', 12 | component: AppView, 13 | children: [ 14 | { 15 | path: 'dataSource', 16 | name: 'dataSource', 17 | component: defineAsyncComponent(() => import('../views/DataSourceView.vue')), 18 | children: [ 19 | { 20 | path: ':id', 21 | component: defineAsyncComponent( 22 | () => import('../views/DataSourceContent/DataSourceContent.vue') 23 | ) 24 | }, 25 | { 26 | path: '', 27 | redirect: '/app/dataSource/1' 28 | } 29 | ] 30 | }, 31 | { 32 | path: 'layout', 33 | name: 'layout', 34 | component: defineAsyncComponent(() => import('../views/PageLayoutView.vue')) 35 | }, 36 | { 37 | path: 'actions', 38 | name: 'actions', 39 | component: defineAsyncComponent(() => import('../views/ActionsView.vue')) 40 | } 41 | ] 42 | }, 43 | { 44 | path: '/runner', 45 | name: 'runner', 46 | component: defineAsyncComponent(() => import('../views/RunnerView.vue')) 47 | }, 48 | { 49 | path: '/about', 50 | name: 'about', 51 | // route level code-splitting 52 | // this generates a separate chunk (About.[hash].js) for this route 53 | // which is lazy-loaded when the route is visited. 54 | component: defineAsyncComponent(() => import('../views/AboutView.vue')) 55 | }, 56 | { 57 | path: '/', 58 | redirect: '/app/layout' 59 | } 60 | ] 61 | }) 62 | 63 | // export const innerRouter = createRouter({ 64 | // history: createMemoryHistory(import.meta.env.BASE_URL), 65 | // routes: [ 66 | // { 67 | // path: '/', 68 | // name: 'home', 69 | // component: HomeView 70 | // } 71 | // ] 72 | // }) 73 | 74 | export default router 75 | -------------------------------------------------------------------------------- /src/setup.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | 3 | import ChartBlock from '@/blocks/basic/ChartBlock.vue' 4 | import HeroTitleBlock from '@/blocks/basic/HeroTitleBlock.vue' 5 | import ImageBlock from '@/blocks/basic/ImageBlock.vue' 6 | import QuoteBlock from '@/blocks/basic/QuoteBlock.vue' 7 | import ViewBlock from '@/blocks/basic/ViewBlock.vue' 8 | import ButtonBlock from '@/blocks/external/ButtonBlock.vue' 9 | import FormBlock from '@/blocks/external/FormBlock.vue' 10 | import NotesBlock from '@/blocks/external/NotesBlock.vue' 11 | import type { BlockType } from '@/types/block' 12 | 13 | const baseBlocks = [ 14 | { 15 | type: 'quote', 16 | material: QuoteBlock 17 | }, 18 | { 19 | type: 'heroTitle', 20 | material: HeroTitleBlock 21 | }, 22 | { 23 | type: 'view', 24 | material: ViewBlock 25 | }, 26 | { 27 | type: 'chart', 28 | material: ChartBlock 29 | }, 30 | { 31 | type: 'image', 32 | material: ImageBlock 33 | } 34 | ] 35 | // 因为我们后面会考虑插件市场,所以我们需要一个类来管理所有的 block 36 | // 只有你安装了对应的外部插件,你才能在页面中使用 37 | class BlockSuite { 38 | private blocks = baseBlocks 39 | constructor() {} 40 | getBlocksMap() { 41 | return Object.fromEntries(this.blocks.map((block) => [block.type, block])) 42 | } 43 | getBlocks() { 44 | return this.blocks 45 | } 46 | addBlock(block: any) { 47 | this.blocks.push(block) 48 | } 49 | hasBlock(type: BlockType) { 50 | return !!this.getBlocksMap()[type] 51 | } 52 | } 53 | 54 | const blockSuite = new BlockSuite() 55 | 56 | console.log( 57 | '🚀 ~ file: BlockRenderer.vue:55 ~ blockSuite.hasBlock(button):', 58 | blockSuite.hasBlock('button') 59 | ) 60 | 61 | blockSuite.addBlock({ 62 | type: 'button', 63 | material: ButtonBlock 64 | }) 65 | blockSuite.addBlock({ 66 | type: 'form', 67 | material: FormBlock 68 | }) 69 | blockSuite.addBlock({ 70 | type: 'notes', 71 | material: NotesBlock 72 | }) 73 | console.log( 74 | '🚀 ~ file: BlockRenderer.vue:68 ~ blockSuite.hasBlock(button):', 75 | blockSuite.hasBlock('button') 76 | ) 77 | const blocksMap = blockSuite.getBlocksMap() 78 | 79 | export const blocksMapSymbol = Symbol('blocksMap') 80 | 81 | export const setup = (app: App) => { 82 | const ins = { 83 | install(app: App) { 84 | // 这两个操作基本上是 Vue3 视图相关插件的标配 85 | app.provide(blocksMapSymbol, blocksMap) 86 | // provide 之后,我们就可以在任何地方使用 inject 来获取到这个值 87 | app.config.globalProperties.$blocksMap = blocksMap 88 | } 89 | } 90 | 91 | app.use(ins) 92 | } 93 | 94 | // Extensions of Vue types to be appended manually 95 | // https://github.com/microsoft/rushstack/issues/2090 96 | // https://github.com/microsoft/rushstack/issues/1709 97 | 98 | // TODO: figure out why it cannot be 'vue' 99 | // @ts-ignore: works on Vue 3, fails in Vue 2 100 | declare module '@vue/runtime-core' { 101 | export interface ComponentCustomProperties { 102 | /** 103 | * Access to the application's blocksMap 104 | */ 105 | $blocksMap: string 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/stores/appEditor.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import { ref } from 'vue' 3 | 4 | import { blocks as blocksData } from '@/mocks/blocks' 5 | import type { BlockInfo } from '@/types/block' 6 | 7 | export const useAppEditorStore = defineStore('appEditor', () => { 8 | const currentBlockId = ref(null) 9 | const blocks = ref(blocksData) 10 | 11 | 12 | function selectBlock(id: string) { 13 | currentBlockId.value = id 14 | } 15 | 16 | function updateBlocks(newBlocks: typeof blocksData) { 17 | blocks.value = newBlocks 18 | } 19 | 20 | function updateBlock(id: string, newBlock: BlockInfo) { 21 | // blocks.value = blocks.value.map((block) => { 22 | // if (block.id === id) { 23 | // return newBlock 24 | // } 25 | // return block 26 | // }) 27 | for (const block of blocks.value) { 28 | if (block.id === id) { 29 | Object.assign(block, newBlock) 30 | break 31 | } 32 | } 33 | } 34 | 35 | return { currentBlockId, blocks, selectBlock, updateBlocks, updateBlock } 36 | }) 37 | -------------------------------------------------------------------------------- /src/stores/debug.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | import { ref } from 'vue' 3 | 4 | export const useEnvStore = defineStore('env', () => { 5 | const debug = ref(false) 6 | function toggle() { 7 | debug.value = !debug.value 8 | } 9 | 10 | return { debug, toggle } 11 | }) 12 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/encode-studio-fe/encode-byelide/633a88a61e69f2c5356a0c20875113ae18cc9060/src/test.ts -------------------------------------------------------------------------------- /src/types/block.ts: -------------------------------------------------------------------------------- 1 | export type BasicBlockType = 'heroTitle' | 'view' | 'chart' | 'quote' | 'image' 2 | export type ExternalBlockType = 'button' | 'form' | 'notes' 3 | 4 | export type BlockType = BasicBlockType | ExternalBlockType 5 | 6 | export interface BaseBlockInfo { 7 | id: string 8 | label: string 9 | } 10 | 11 | // basic 12 | 13 | export interface HeroTitleBlockInfo extends BaseBlockInfo { 14 | type: 'heroTitle' 15 | props: { 16 | content: string 17 | } 18 | } 19 | 20 | export interface ViewBlockInfo extends BaseBlockInfo { 21 | type: 'view', 22 | props: { 23 | fields: Record 26 | fieldProps: { 27 | width: number 28 | visible: boolean 29 | }[] 30 | data: { id: string; value: string }[] 31 | } 32 | } 33 | 34 | export type QuoteBlockStatus = 'success' | 'warning' | 'error' 35 | 36 | export interface QuoteBlockInfo extends BaseBlockInfo { 37 | type: 'quote', 38 | props: { 39 | content: string 40 | status: QuoteBlockStatus 41 | } 42 | } 43 | 44 | export interface ImageBlockInfo extends BaseBlockInfo { 45 | type: 'image', 46 | props: { 47 | url: string 48 | } 49 | } 50 | 51 | // external 52 | export interface ButtonBlockInfo extends BaseBlockInfo { 53 | type: 'button', 54 | props: { 55 | content: string 56 | } 57 | } 58 | 59 | export interface FormBlockInfo extends BaseBlockInfo { 60 | type: 'form', 61 | props: { 62 | fields: { 63 | type: string 64 | label: string 65 | placeholder?: string 66 | required?: boolean 67 | }[] 68 | } 69 | } 70 | 71 | export interface NotesBlockInfo extends BaseBlockInfo { 72 | type: 'notes', 73 | props: { 74 | content: string 75 | } 76 | } 77 | 78 | 79 | export type ChartType = 'echarts' | 'canvas' | 'svg' 80 | 81 | export interface ChartBlockInfo extends BaseBlockInfo { 82 | type: 'chart', 83 | props: { 84 | chartType: ChartType 85 | } 86 | } 87 | 88 | export type BlockInfo = 89 | // basic 90 | | HeroTitleBlockInfo 91 | | ViewBlockInfo 92 | | QuoteBlockInfo 93 | | ImageBlockInfo 94 | | ChartBlockInfo 95 | // external 96 | | ButtonBlockInfo 97 | | FormBlockInfo 98 | | NotesBlockInfo 99 | -------------------------------------------------------------------------------- /src/ui/SegmentedControl/SegmentedControl.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 94 | 95 | 138 | -------------------------------------------------------------------------------- /src/ui/SegmentedControl/types.ts: -------------------------------------------------------------------------------- 1 | export type SegmentedControlItem = { 2 | value: string 3 | label: string 4 | } 5 | 6 | export interface SegmentedControlProps { 7 | value?: string 8 | data: SegmentedControlItem[] 9 | } 10 | -------------------------------------------------------------------------------- /src/utils/array.ts: -------------------------------------------------------------------------------- 1 | export function arrayMove(array: T[], from: number, to: number): T[] { 2 | const newArray = array.slice() 3 | newArray.splice(to < 0 ? newArray.length + to : to, 0, newArray.splice(from, 1)[0]) 4 | 5 | return newArray 6 | } 7 | -------------------------------------------------------------------------------- /src/utils/detect.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-useless-escape */ 2 | export function isMobileTablet() { 3 | let check = false; 4 | (function (a) { 5 | if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) 6 | check = true; 7 | })(navigator.userAgent); 8 | return check; 9 | } 10 | -------------------------------------------------------------------------------- /src/views/AboutView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /src/views/ActionsView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /src/views/AppView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 31 | -------------------------------------------------------------------------------- /src/views/DataSourceContent/DataSourceContent.vue: -------------------------------------------------------------------------------- 1 | 8 | 15 | 16 | 31 | -------------------------------------------------------------------------------- /src/views/DataSourceContent/react_app/ReactDataSource.jsx: -------------------------------------------------------------------------------- 1 | import '@glideapps/glide-data-grid/dist/index.css' 2 | 3 | import { DataEditor, GridCellKind, GridColumnIcon } from '@glideapps/glide-data-grid' 4 | import { useEffect, useRef, useState } from 'react' 5 | 6 | const tempDataList = new Array(100_0000).fill(0) 7 | 8 | const tempDataPool = [ 9 | { 10 | id: '001', 11 | name: '合一', 12 | age: '15', 13 | isOpen: true, 14 | hobby: ['football', 'swimming'], 15 | avatar: ['https://i.pravatar.cc/300?img=3'], 16 | notes: '**This is a markdown cell**' 17 | }, 18 | { 19 | id: '002', 20 | name: '合二', 21 | age: '18', 22 | isOpen: true, 23 | hobby: ['basketball', 'swimming'], 24 | avatar: ['https://i.pravatar.cc/300?img=1'], 25 | notes: 'true' 26 | }, 27 | { 28 | id: '003', 29 | name: '合三', 30 | age: '23', 31 | isOpen: false, 32 | hobby: ['basketball'], 33 | avatar: ['https://i.pravatar.cc/300?img=4'], 34 | notes: 'true' 35 | }, 36 | { 37 | id: '004', 38 | name: '合四', 39 | age: '25', 40 | isOpen: true, 41 | hobby: ['football', 'swimming'], 42 | avatar: ['https://i.pravatar.cc/300?img=5'], 43 | notes: 'true' 44 | } 45 | ] 46 | 47 | const data = tempDataList.map((item, index) => { 48 | const randomIndex = Math.floor(Math.random() * 4) 49 | const randomItem = tempDataPool[randomIndex] 50 | return { 51 | ...randomItem, 52 | id: `00${index}`, 53 | avatar: randomItem.avatar 54 | } 55 | }) 56 | 57 | // Grid columns may also provide icon, overlayIcon, menu, style, and theme overrides 58 | const columns = [ 59 | { title: 'ID', width: 100, icon: GridColumnIcon.RowID }, 60 | { title: '姓名', width: 100, icon: GridColumnIcon.Text }, 61 | { title: '年龄', width: 100 }, 62 | { title: '状态', width: 50 }, 63 | { title: '爱好', width: 200 }, 64 | { title: '头像', width: 200 }, 65 | { title: '笔记', width: 200 } 66 | ] 67 | 68 | // If fetching data is slow you can use the DataEditor ref to send updates for cells 69 | // once data is loaded. 70 | function getData([col, row]) { 71 | const person = data[row] 72 | 73 | switch (col) { 74 | case 0: { 75 | return { 76 | kind: GridCellKind.RowID, 77 | data: person.id, 78 | allowOverlay: false, 79 | displayData: person.id 80 | } 81 | } 82 | 83 | case 1: { 84 | return { 85 | kind: GridCellKind.Text, 86 | data: person.name, 87 | allowOverlay: true, 88 | displayData: person.name, 89 | hasMenu: true 90 | } 91 | } 92 | 93 | case 2: { 94 | return { 95 | kind: GridCellKind.Number, 96 | data: person.age, 97 | allowOverlay: true, 98 | displayData: person.age 99 | } 100 | } 101 | 102 | case 3: { 103 | return { 104 | kind: GridCellKind.Boolean, 105 | data: person.isOpen, 106 | allowOverlay: true, 107 | displayData: person.isOpen 108 | } 109 | } 110 | 111 | case 4: { 112 | return { 113 | kind: GridCellKind.Bubble, 114 | data: person.hobby, 115 | allowOverlay: true, 116 | displayData: person.hobby 117 | } 118 | } 119 | 120 | case 5: { 121 | return { 122 | kind: GridCellKind.Image, 123 | data: person.avatar, 124 | allowOverlay: true, 125 | displayData: person.avatar 126 | } 127 | } 128 | 129 | case 6: { 130 | return { 131 | kind: GridCellKind.Markdown, 132 | data: person.notes, 133 | allowOverlay: true, 134 | displayData: person.Markdown 135 | } 136 | } 137 | 138 | default: { 139 | return {} 140 | } 141 | } 142 | } 143 | 144 | export default function ReactDataSource() { 145 | const ref = useRef(null) 146 | const [editorRect, setEditorRect] = useState({ width: 500, height: 300 }) 147 | const { width, height } = editorRect 148 | 149 | useEffect(() => { 150 | const calcRect = () => { 151 | const outerContainerDom = ref.current.parentElement.parentElement 152 | if (outerContainerDom) { 153 | const { width, height } = outerContainerDom.getBoundingClientRect() 154 | setEditorRect({ width: width - 12, height: height - 12 }) 155 | } 156 | } 157 | 158 | calcRect() 159 | 160 | window.addEventListener('resize', calcRect, false) 161 | 162 | return () => { 163 | window.removeEventListener('resize', calcRect, false) 164 | } 165 | }, []) 166 | 167 | return ( 168 |
169 | console.log(p, q)} 176 | /> 177 |
178 |
179 | ) 180 | } 181 | -------------------------------------------------------------------------------- /src/views/DataSourceView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 18 | -------------------------------------------------------------------------------- /src/views/PageLayoutView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 15 | 28 | -------------------------------------------------------------------------------- /src/views/RunnerView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 24 | -------------------------------------------------------------------------------- /stylelint.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | extends: ['stylelint-config-standard', 'stylelint-config-prettier', 'stylelint-config-html/vue'] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/**/__tests__/*", "vite.config.ts"], 5 | "compilerOptions": { 6 | "composite": true, 7 | "baseUrl": ".", 8 | "paths": { 9 | "@/*": ["./src/*"] 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.node.json" 6 | }, 7 | { 8 | "path": "./tsconfig.app.json" 9 | }, 10 | { 11 | "path": "./tsconfig.vitest.json" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node18/tsconfig.json", 3 | "include": [ 4 | // "vite.config.*", 5 | // "vitest.config.*", 6 | "cypress.config.*", 7 | "nightwatch.conf.*", 8 | "playwright.config.*" 9 | ], 10 | "compilerOptions": { 11 | "composite": true, 12 | "module": "ESNext", 13 | "types": ["node"] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.vitest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.app.json", 3 | "exclude": [], 4 | "compilerOptions": { 5 | "composite": true, 6 | "lib": [], 7 | "types": ["node", "jsdom"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { visualizer } from 'rollup-plugin-visualizer' 4 | import veauryVitePlugins from 'veaury/vite/index.js' 5 | import { defineConfig, splitVendorChunkPlugin } from 'vite' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [ 10 | // vue(), 11 | // vueJsx(), 12 | splitVendorChunkPlugin(), 13 | visualizer({ 14 | filename: './bundle-analysis.html' 15 | }), 16 | veauryVitePlugins({ 17 | type: 'vue' 18 | }) 19 | ], 20 | build: { 21 | rollupOptions: { 22 | output: { 23 | manualChunks: { 24 | 'vue-common-lib': ['vue', 'vue-router', 'pinia'], 25 | 'react-common-lib': ['react', 'react-dom', '@glideapps/glide-data-grid'], 26 | } 27 | } 28 | } 29 | }, 30 | resolve: { 31 | alias: { 32 | '@': fileURLToPath(new URL('./src', import.meta.url)) 33 | } 34 | } 35 | }) 36 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | 3 | import { mergeConfig } from 'vite' 4 | import { configDefaults, defineConfig } from 'vitest/config' 5 | 6 | import viteConfig from './vite.config' 7 | 8 | export default mergeConfig( 9 | viteConfig, 10 | defineConfig({ 11 | test: { 12 | environment: 'jsdom', 13 | exclude: [...configDefaults.exclude, 'e2e/*'], 14 | root: fileURLToPath(new URL('./', import.meta.url)), 15 | transformMode: { 16 | web: [/\.[jt]sx$/] 17 | } 18 | } 19 | }) 20 | ) 21 | --------------------------------------------------------------------------------