├── .browserslistrc
├── .editorconfig
├── .eslintignore
├── .github
└── workflows
│ └── github-page.yml
├── .gitignore
├── LICENSE
├── README.md
├── auto-imports.d.ts
├── components.d.ts
├── eslint.config.js
├── index.html
├── package.json
├── public
├── audio
│ ├── ding.mp3
│ ├── hangup.m4a
│ ├── ringtone.m4a
│ └── voice
│ │ ├── elvis.mp3
│ │ ├── jackie_chan.wav
│ │ ├── mrs_pan.m4a
│ │ └── squidward.m4a
├── favicon.ico
├── firework
│ ├── index.html
│ ├── script.js
│ └── style.css
├── font
│ ├── SairaExtraCondensed-Regular.ttf
│ ├── SairaExtraCondensed-Regular.woff
│ └── SairaExtraCondensed-Regular.woff2
├── images
│ ├── avatar
│ │ ├── elvis.png
│ │ ├── international_friend.png
│ │ ├── jackie_chan.jpg
│ │ └── mrs_pan.jpg
│ ├── preview_birthday_list.png
│ ├── preview_clipboard.png
│ ├── preview_countdown.png
│ ├── preview_countdown2.png
│ ├── preview_keystroke.png
│ ├── preview_labor_progress.png
│ ├── preview_lyric_book.png
│ ├── preview_phone_reminder.png
│ ├── preview_photo.png
│ ├── preview_sit_reminder.png
│ ├── preview_time_progress.png
│ ├── preview_todo_list.png
│ ├── preview_water_reminder.png
│ ├── preview_wave_progress.png
│ └── zhangyuge.jpg
├── screenshot.jpg
└── widget.json
├── screenshot
├── dynamic_island.gif
├── labor_progress.gif
├── logo.png
└── photo.png
├── src
├── App.vue
├── api
│ ├── FeatureWallApi.ts
│ ├── WebWidgetApi.ts
│ └── axios.ts
├── assets
│ ├── cancel.svg
│ ├── css
│ │ └── common.css
│ ├── images
│ │ ├── bilibili_logo_blue.png
│ │ ├── bilibili_logo_red.png
│ │ ├── douyin.png
│ │ ├── github-mark-white.png
│ │ ├── github-mark.png
│ │ ├── logo.png
│ │ ├── qq.png
│ │ ├── storybook.svg
│ │ ├── typescript.svg
│ │ └── vue.png
│ ├── scss
│ │ └── theme.scss
│ ├── svg
│ │ └── phone-hangup.svg
│ └── video
│ │ └── tray_guide.webm
├── common
│ ├── Constants.ts
│ └── dayjs-extend.ts
├── components
│ ├── DatePickerDialog.vue
│ ├── FontSelector.vue
│ ├── LunarDatePicker.vue
│ ├── SolarDatePicker.vue
│ ├── TimePicker.vue
│ └── TimePickerDialog.vue
├── composition
│ ├── useAppConfig.ts
│ ├── useAppRuntimeInfo.ts
│ └── useWidgetPackage.ts
├── countdown
│ ├── CountdownList.vue
│ └── Event.ts
├── i18n
│ ├── default
│ │ ├── en.json
│ │ └── zh.json
│ ├── i18n.ts
│ ├── settings
│ │ ├── en.json
│ │ └── zh.json
│ └── tray
│ │ ├── en.json
│ │ └── zh.json
├── index.css
├── main.ts
├── model
│ ├── AppVersion.ts
│ └── FeatureWall.ts
├── router
│ └── index.ts
├── shims-vue.d.ts
├── util
│ ├── LunarUtils.ts
│ └── TimeUtils.ts
├── utils
│ ├── TimeUtils.ts
│ ├── VersionUtils.ts
│ └── WidgetUtil.ts
├── views
│ ├── Loading.vue
│ ├── add
│ │ ├── AddWidgetView.vue
│ │ ├── SearchItem.vue
│ │ ├── WidgetContainer.vue
│ │ ├── WidgetTags.vue
│ │ └── feature
│ │ │ ├── FeatureWallList.vue
│ │ │ └── FeatureWallListItem.vue
│ ├── desktop
│ │ ├── Grid.vue
│ │ ├── GridSystem.ts
│ │ ├── GridSystemDrawer.ts
│ │ ├── Loading.vue
│ │ ├── TrayGuide.vue
│ │ └── WidgetFailed.vue
│ ├── manager
│ │ ├── DeployedWidgetCard.vue
│ │ ├── DeployedWidgetList.vue
│ │ └── ManagerView.vue
│ ├── overlap
│ │ ├── OverlapGuide.vue
│ │ └── OverlapWrapper.vue
│ ├── settings
│ │ ├── AiSettingPanel.vue
│ │ ├── AppRuntimeView.vue
│ │ ├── ProxySettingPanel.vue
│ │ ├── SettingSection.vue
│ │ ├── SettingView.vue
│ │ └── theme
│ │ │ ├── ThemeSettingPanel.vue
│ │ │ ├── ThemeTag.ts
│ │ │ └── ThemeTags.vue
│ ├── tray
│ │ ├── SocialLinks.vue
│ │ └── TrayMenuView.vue
│ └── update
│ │ └── CheckUpdateView.vue
├── vite-env.d.ts
└── widgets
│ ├── birthday-list
│ ├── BirthdayList.widget.ts
│ ├── BirthdayListConfigView.vue
│ ├── BirthdayListWidget.vue
│ ├── BirthdayListWidgetRoutes.ts
│ ├── BirthdayListWidgetView.vue
│ ├── images
│ │ └── balloon.png
│ └── model
│ │ └── BirthdayListData.ts
│ ├── countdown
│ ├── Countdown.widget.ts
│ ├── CountdownConfigView.vue
│ ├── CountdownWidget.vue
│ ├── CountdownWidgetRoutes.ts
│ ├── CountdownWidgetView.vue
│ └── model
│ │ └── CountdownModel.ts
│ ├── countdown2
│ ├── Countdown2.widget.ts
│ ├── Countdown2ConfigView.vue
│ ├── Countdown2Widget.vue
│ ├── Countdown2WidgetRoutes.ts
│ └── Countdown2WidgetView.vue
│ ├── dynamic-island
│ ├── DynamicIsland.widget.ts
│ ├── DynamicIslandWidget.vue
│ ├── DynamicIslandWidgetRoutes.ts
│ ├── DynamicIslandWidgetView.vue
│ ├── components
│ │ ├── AdvanceCountdownNotification.vue
│ │ ├── CountingNotification.vue
│ │ ├── CustomUrlNotification.vue
│ │ ├── MessageNotification.vue
│ │ ├── PhoneCallNotification.vue
│ │ ├── ReminderNotification.vue
│ │ └── VoiceBar.vue
│ ├── model
│ │ ├── Demo.ts
│ │ └── NotificationState.ts
│ └── scss
│ │ └── notification.scss
│ ├── key-stroke
│ ├── KeyStroke.widget.ts
│ ├── KeyStrokeWidget.vue
│ ├── KeyStrokeWidgetRoutes.ts
│ └── KeyStrokeWidgetView.vue
│ ├── labor-progress
│ ├── LaborProgress.widget.ts
│ ├── LaborProgressConfigView.vue
│ ├── LaborProgressRoutes.ts
│ ├── LaborProgressWidget.vue
│ ├── LaborProgressWidgetView.vue
│ ├── images
│ │ ├── face_holding_back_tears_3d.png
│ │ ├── face_with_rolling_eyes_3d.png
│ │ ├── face_with_spiral_eyes_3d.png
│ │ ├── face_with_steam_from_nose_3d.png
│ │ ├── knocked-out_face_3d.png
│ │ ├── partying_face_3d.png
│ │ ├── sleeping_face_3d.png
│ │ ├── sleepy_face_3d.png
│ │ ├── smiling_face_with_sunglasses_3d.png
│ │ ├── star-struck_3d.png
│ │ └── yawning_face_3d.png
│ └── model
│ │ ├── EmojiTimeline.ts
│ │ └── LaborProgressData.ts
│ ├── phone-reminder
│ ├── PhoneReminder.widget.ts
│ ├── PhoneReminderConfigView.vue
│ ├── PhoneReminderWidgetRoutes.ts
│ ├── PhoneReminderWidgetView.vue
│ └── model
│ │ └── PhoneReminder.ts
│ ├── photo
│ ├── Photo.widget.ts
│ ├── PhotoConfigView.vue
│ ├── PhotoWidgetRoutes.ts
│ ├── PhotoWidgetView.vue
│ ├── assets
│ │ ├── photo1.jpg
│ │ ├── photo2.jpg
│ │ └── photo3.jpg
│ └── model
│ │ └── PhotoData.ts
│ ├── sit-reminder
│ ├── BreakView.vue
│ ├── SitReminder.widget.ts
│ ├── SitReminderConfigView.vue
│ ├── SitReminderWidget.vue
│ ├── SitReminderWidgetRoutes.ts
│ ├── TextSwitcher.vue
│ ├── composition
│ │ └── use-sit-reminder.ts
│ └── model
│ │ └── SitReminder.ts
│ ├── time-progress
│ ├── TimeProgress.widget.ts
│ ├── TimeProgressConfig.vue
│ ├── TimeProgressRoutes.ts
│ ├── TimeProgressWidgetView.vue
│ └── images
│ │ └── time_progress_decorate.svg
│ ├── todo-list
│ ├── TodoList.widget.ts
│ ├── TodoListConfigView.vue
│ ├── TodoListWidgetRoutes.ts
│ ├── TodoListWidgetView.vue
│ ├── WidgetBackground.vue
│ ├── components
│ │ ├── EditBox.vue
│ │ ├── FinishedTodoList.vue
│ │ ├── TodoItem.vue
│ │ └── TodoList.vue
│ └── model
│ │ ├── TodoListData.ts
│ │ └── useTodoStore.ts
│ ├── water-reminder
│ ├── WaterReminder.widget.ts
│ ├── WaterReminderComponent.vue
│ ├── WaterReminderConfigView.vue
│ ├── WaterReminderWidgetRoutes.ts
│ ├── WaterReminderWidgetView.vue
│ └── model
│ │ ├── WaterReminderModel.ts
│ │ └── WaveBall.ts
│ ├── wave-progress
│ ├── WaveProgress.widget.ts
│ ├── WaveProgressConfigView.vue
│ ├── WaveProgressRoute.ts
│ ├── WaveProgressWidget.vue
│ ├── WaveProgressWidgetView.vue
│ └── model
│ │ └── WaveProgressData.ts
│ └── widget-router.ts
├── test
└── dayjs.test.ts
├── tsconfig.json
├── tsconfig.node.json
├── uno.config.ts
├── vite.config.ts
└── widget.package.ts
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 | not ie 11
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules
3 | patches/
4 | types/
5 | cache/
6 | !packages/.vitepress
7 | !/.eslintrc.js
8 | !/rollup.config.js
9 | !.test
10 | .temp
11 |
--------------------------------------------------------------------------------
/.github/workflows/github-page.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3 |
4 | name: Deploy CI
5 | permissions:
6 | id-token: write
7 | pages: write
8 |
9 | on:
10 | push:
11 | branches: [ "master" ]
12 | pull_request:
13 | branches: [ "master" ]
14 |
15 | jobs:
16 | build:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v4
21 | - name: Use Node.js
22 | uses: actions/setup-node@v4
23 | with:
24 | node-version: '18.x'
25 | - name: Setup pnpm
26 | uses: pnpm/action-setup@v4
27 | with:
28 | version: 8
29 | - name: Build static files
30 | id: build
31 | run: |
32 | pnpm install
33 | pnpm run build
34 | - name: Upload static files as artifact
35 | id: deployment
36 | uses: actions/upload-pages-artifact@v3
37 | with:
38 | path: dist/
39 |
40 | deploy:
41 | environment:
42 | name: github-pages
43 | url: ${{ steps.deployment.outputs.page_url }}
44 | runs-on: ubuntu-latest
45 | needs: build
46 | steps:
47 | - name: Deploy to GitHub Pages
48 | id: deployment
49 | uses: actions/deploy-pages@v4
50 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | storybook-static
5 |
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 | pnpm-debug.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 | .eslintcache
26 | #Electron-builder output
27 | /dist_electron
28 |
--------------------------------------------------------------------------------
/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | // Generated by 'unplugin-auto-import'
2 | export {}
3 | declare global {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/components.d.ts:
--------------------------------------------------------------------------------
1 | // generated by unplugin-vue-components
2 | // We suggest you to commit this file into source control
3 | // Read more: https://github.com/vuejs/core/pull/3399
4 | import '@vue/runtime-core'
5 |
6 | export {}
7 |
8 | declare module '@vue/runtime-core' {
9 | export interface GlobalComponents {
10 | DatePickerDialog: typeof import('./src/components/DatePickerDialog.vue')['default']
11 | ElAlert: typeof import('element-plus/es')['ElAlert']
12 | ElAvatar: typeof import('element-plus/es')['ElAvatar']
13 | ElButton: typeof import('element-plus/es')['ElButton']
14 | ElCard: typeof import('element-plus/es')['ElCard']
15 | ElCarousel: typeof import('element-plus/es')['ElCarousel']
16 | ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
17 | ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
18 | ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
19 | ElCol: typeof import('element-plus/es')['ElCol']
20 | ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
21 | ElDialog: typeof import('element-plus/es')['ElDialog']
22 | ElDivider: typeof import('element-plus/es')['ElDivider']
23 | ElForm: typeof import('element-plus/es')['ElForm']
24 | ElFormItem: typeof import('element-plus/es')['ElFormItem']
25 | ElImage: typeof import('element-plus/es')['ElImage']
26 | ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
27 | ElInput: typeof import('element-plus/es')['ElInput']
28 | ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
29 | ElOption: typeof import('element-plus/es')['ElOption']
30 | ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
31 | ElPopover: typeof import('element-plus/es')['ElPopover']
32 | ElRadio: typeof import('element-plus/es')['ElRadio']
33 | ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
34 | ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
35 | ElRow: typeof import('element-plus/es')['ElRow']
36 | ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
37 | ElSelect: typeof import('element-plus/es')['ElSelect']
38 | ElSwitch: typeof import('element-plus/es')['ElSwitch']
39 | ElTable: typeof import('element-plus/es')['ElTable']
40 | ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
41 | ElTabPane: typeof import('element-plus/es')['ElTabPane']
42 | ElTabs: typeof import('element-plus/es')['ElTabs']
43 | ElTag: typeof import('element-plus/es')['ElTag']
44 | ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
45 | ElTooltip: typeof import('element-plus/es')['ElTooltip']
46 | FontSelector: typeof import('./src/components/FontSelector.vue')['default']
47 | LunarDatePicker: typeof import('./src/components/LunarDatePicker.vue')['default']
48 | RouterLink: typeof import('vue-router')['RouterLink']
49 | RouterView: typeof import('vue-router')['RouterView']
50 | SolarDatePicker: typeof import('./src/components/SolarDatePicker.vue')['default']
51 | TimePicker: typeof import('./src/components/TimePicker.vue')['default']
52 | TimePickerDialog: typeof import('./src/components/TimePickerDialog.vue')['default']
53 | }
54 | export interface ComponentCustomProperties {
55 | vLoading: typeof import('element-plus/es')['ElLoadingDirective']
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import antfu from '@antfu/eslint-config'
2 |
3 | export default antfu({
4 | ignores: ['**/*.md', '**/*.md/*.*', 'dist/', 'public/', '**/dist/**/', 'node_modules', '**/node_modules/**', 'node_modules/', '**/node_modules/**/', 'patches/', '**/patches/**/', 'types/', '**/types/**/', 'cache/', '**/cache/**/', '!packages/.vitepress', '!packages/.vitepress/**', '!.eslintrc.js', '!.eslintrc.js/**', '!rollup.config.js', '!rollup.config.js/**', '!.test', '!**/.test/**', '.temp', '**/.temp/**'],
5 | }, {
6 | rules: {
7 | 'vue/no-deprecated-functional-template': 'off',
8 | 'vue/one-component-per-file': 'off',
9 | 'vue/no-template-shadow': 'off',
10 | 'vue/require-prop-types': 'off',
11 | 'vue/dot-location': 'off',
12 | 'spaced-comment': ['error', 'always', { exceptions: ['#__PURE__'] }],
13 | 'no-restricted-imports': [
14 | 'error',
15 | {
16 | patterns: ['../**/core', '../**/vue3'],
17 | },
18 | ],
19 | 'vue/eqeqeq': 'off',
20 | 'vue/space-unary-ops': 'off',
21 | 'vue/comma-dangle': ['error', 'only-multiline'],
22 | 'node/no-callback-literal': 'off',
23 | 'import/namespace': 'off',
24 | 'eqeqeq': 'off',
25 | 'import/default': 'off',
26 | 'import/no-named-as-default': 'off',
27 | 'import/no-named-as-default-member': 'off',
28 | 'curly': ['error', 'multi-line'],
29 | 'max-statements-per-line': ['error', {
30 | max: 1,
31 | }],
32 | },
33 | }, {
34 | files: ['demo.vue', 'demo.client.vue', 'scripts/*.ts', '**/*.test.ts'],
35 | rules: {
36 | 'no-alert': 'off',
37 | 'no-console': 'off',
38 | 'no-undef': 'off',
39 | 'no-unused-vars': 'off',
40 | 'no-restricted-imports': 'off',
41 | '@typescript-eslint/no-unused-vars': 'off',
42 | '@typescript-eslint/no-redeclare': 'off',
43 | 'unused-imports/no-unused-vars': 'off',
44 | },
45 | })
46 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Widget
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@widget-js/widgets",
3 | "type": "module",
4 | "version": "0.0.1",
5 | "private": true,
6 | "author": "Widget JS",
7 | "license": "MIT",
8 | "scripts": {
9 | "serve": "vite",
10 | "build": "vite build",
11 | "preview": "vite preview",
12 | "remote": "widget dependencies -t remote",
13 | "local": "widget dependencies -t local",
14 | "lint": "eslint --cache .",
15 | "lint:fix": "eslint --cache . --fix"
16 | },
17 | "dependencies": {
18 | "@icon-park/vue-next": "^1.4.2",
19 | "@lobehub/icons": "^1.76.0",
20 | "@vueuse/core": "^9.4.0",
21 | "@vueuse/integrations": "^10.5.0",
22 | "@vueuse/motion": "2.0.0-beta.12",
23 | "@vueuse/router": "^9.9.0",
24 | "@widget-js/core": "^24.1.1-beta.34",
25 | "@widget-js/vue3": "^24.1.1-beta.33",
26 | "@widget-js/web-api": "24.1.1-beta.42",
27 | "animate.css": "^4.1.1",
28 | "axios": "^1.6.0",
29 | "color": "^4.2.3",
30 | "consola": "^3.2.3",
31 | "core-js": "^3.26.1",
32 | "dayjs": "^1.11.6",
33 | "driver.js": "^0.9.8",
34 | "element-plus": "2.9.8",
35 | "localforage": "^1.10.0",
36 | "lodash-es": "^4.17.21",
37 | "lunar-typescript": "^1.7.0",
38 | "lyric-resolver": "^0.1.6",
39 | "nanoid": "^4.0.2",
40 | "pinia": "^2.1.6",
41 | "qs": "^6.11.2",
42 | "semver": "^7.6.0",
43 | "vue": "^3.5.13",
44 | "vue-demi": "^0.14.5",
45 | "vue-i18n": "10.0.5",
46 | "vue-router": "^4.2.4",
47 | "vue-scroll-picker": "^1.1.3"
48 | },
49 | "devDependencies": {
50 | "@antfu/eslint-config": "^2.6.1",
51 | "@antfu/ni": "^0.21.4",
52 | "@types/color": "^3.0.3",
53 | "@types/lodash-es": "^4.17.12",
54 | "@typescript-eslint/eslint-plugin": "^6.16.0",
55 | "@typescript-eslint/parser": "^6.16.0",
56 | "@vitejs/plugin-vue": "^4.0.0",
57 | "@vue/cli-plugin-router": "~5.0.0",
58 | "@vue/cli-plugin-typescript": "~5.0.0",
59 | "@vue/cli-service": "~5.0.0",
60 | "@vue/compiler-sfc": "^3.2.45",
61 | "@widget-js/vite-plugin-widget": "^24.1.1-beta.30",
62 | "autoprefixer": "^10.4.13",
63 | "eslint": "8.48.0",
64 | "lint-staged": "^13.0.3",
65 | "postcss": "^8.4.21",
66 | "sass": "^1.56.0",
67 | "simple-git-hooks": "^2.9.0",
68 | "style-loader": "^3.3.1",
69 | "typescript": "^5.2.2",
70 | "unocss": "^0.51.13",
71 | "unplugin-auto-import": "^0.11.4",
72 | "unplugin-vue-components": "^0.22.9",
73 | "vite": "^5.0.5",
74 | "vite-plugin-checker": "^0.6.1",
75 | "vitest": "^0.34.6"
76 | },
77 | "simple-git-hooks": {
78 | "pre-commit": "npx lint-staged"
79 | },
80 | "lint-staged": {
81 | "*.{js,ts,tsx,vue,md}": [
82 | "eslint --cache --fix"
83 | ]
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/public/audio/ding.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/ding.mp3
--------------------------------------------------------------------------------
/public/audio/hangup.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/hangup.m4a
--------------------------------------------------------------------------------
/public/audio/ringtone.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/ringtone.m4a
--------------------------------------------------------------------------------
/public/audio/voice/elvis.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/voice/elvis.mp3
--------------------------------------------------------------------------------
/public/audio/voice/jackie_chan.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/voice/jackie_chan.wav
--------------------------------------------------------------------------------
/public/audio/voice/mrs_pan.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/voice/mrs_pan.m4a
--------------------------------------------------------------------------------
/public/audio/voice/squidward.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/audio/voice/squidward.m4a
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/favicon.ico
--------------------------------------------------------------------------------
/public/firework/script.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/firework/script.js
--------------------------------------------------------------------------------
/public/font/SairaExtraCondensed-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/font/SairaExtraCondensed-Regular.ttf
--------------------------------------------------------------------------------
/public/font/SairaExtraCondensed-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/font/SairaExtraCondensed-Regular.woff
--------------------------------------------------------------------------------
/public/font/SairaExtraCondensed-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/font/SairaExtraCondensed-Regular.woff2
--------------------------------------------------------------------------------
/public/images/avatar/elvis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/avatar/elvis.png
--------------------------------------------------------------------------------
/public/images/avatar/international_friend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/avatar/international_friend.png
--------------------------------------------------------------------------------
/public/images/avatar/jackie_chan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/avatar/jackie_chan.jpg
--------------------------------------------------------------------------------
/public/images/avatar/mrs_pan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/avatar/mrs_pan.jpg
--------------------------------------------------------------------------------
/public/images/preview_birthday_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_birthday_list.png
--------------------------------------------------------------------------------
/public/images/preview_clipboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_clipboard.png
--------------------------------------------------------------------------------
/public/images/preview_countdown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_countdown.png
--------------------------------------------------------------------------------
/public/images/preview_countdown2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_countdown2.png
--------------------------------------------------------------------------------
/public/images/preview_keystroke.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_keystroke.png
--------------------------------------------------------------------------------
/public/images/preview_labor_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_labor_progress.png
--------------------------------------------------------------------------------
/public/images/preview_lyric_book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_lyric_book.png
--------------------------------------------------------------------------------
/public/images/preview_phone_reminder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_phone_reminder.png
--------------------------------------------------------------------------------
/public/images/preview_photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_photo.png
--------------------------------------------------------------------------------
/public/images/preview_sit_reminder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_sit_reminder.png
--------------------------------------------------------------------------------
/public/images/preview_time_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_time_progress.png
--------------------------------------------------------------------------------
/public/images/preview_todo_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_todo_list.png
--------------------------------------------------------------------------------
/public/images/preview_water_reminder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_water_reminder.png
--------------------------------------------------------------------------------
/public/images/preview_wave_progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/preview_wave_progress.png
--------------------------------------------------------------------------------
/public/images/zhangyuge.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/images/zhangyuge.jpg
--------------------------------------------------------------------------------
/public/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/public/screenshot.jpg
--------------------------------------------------------------------------------
/screenshot/dynamic_island.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/screenshot/dynamic_island.gif
--------------------------------------------------------------------------------
/screenshot/labor_progress.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/screenshot/labor_progress.gif
--------------------------------------------------------------------------------
/screenshot/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/screenshot/logo.png
--------------------------------------------------------------------------------
/screenshot/photo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/screenshot/photo.png
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
--------------------------------------------------------------------------------
/src/api/FeatureWallApi.ts:
--------------------------------------------------------------------------------
1 | import type { FeatureWall } from '../model/FeatureWall'
2 | import { widgetServerApi } from '@/api/axios'
3 |
4 | export class FeatureWallApi {
5 | // 获取所有 FeatureWall
6 | static findAll(): Promise {
7 | return widgetServerApi.get('/feature/wall')
8 | }
9 |
10 | // 点赞 FeatureWall
11 | static like(id: number): Promise {
12 | return widgetServerApi.post(`/feature/wall/${id}/like`)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/api/WebWidgetApi.ts:
--------------------------------------------------------------------------------
1 | import type { Pagination, WebWidget, WidgetSearchOptions } from '@widget-js/web-api'
2 | import { widgetServerApi } from '@/api/axios'
3 |
4 | export class WebWidgetApi {
5 | static search(options: WidgetSearchOptions): Promise> {
6 | return widgetServerApi.get('/widget', { params: options })
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/api/axios.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | AxiosError,
3 | AxiosInstance,
4 | AxiosRequestHeaders,
5 | AxiosResponse,
6 | InternalAxiosRequestConfig,
7 | } from 'axios'
8 | import axios from 'axios'
9 |
10 | import qs from 'qs'
11 |
12 | import { LogApi } from '@widget-js/core'
13 |
14 | axios.defaults.baseURL = 'https://widgetjs.cn/api/v1'
15 | const widgetServerApi: AxiosInstance = axios.create({
16 | timeout: 60000,
17 | })
18 |
19 | // request拦截器
20 | widgetServerApi.interceptors.request.use(
21 | (config: InternalAxiosRequestConfig) => {
22 | if (
23 | config.method === 'post'
24 | && (config.headers as AxiosRequestHeaders)['Content-Type'] === 'application/x-www-form-urlencoded'
25 | ) {
26 | config.data = qs.stringify(config.data)
27 | }
28 | if (config.method === 'get' && config.params) {
29 | let url = config.url as string
30 | url += '?'
31 | const keys = Object.keys(config.params)
32 | for (const key of keys) {
33 | if (config.params[key] !== void 0 && config.params[key] !== null) {
34 | url += `${key}=${encodeURIComponent(config.params[key])}&`
35 | }
36 | }
37 | url = url.substring(0, url.length - 1)
38 | config.params = {}
39 | config.url = url
40 | }
41 | return config
42 | },
43 | (error: AxiosError) => {
44 | LogApi.error('axios', {
45 | code: error.code,
46 | message: error.message,
47 | name: error.name,
48 | })
49 | return Promise.reject(error)
50 | },
51 | )
52 |
53 | // response 拦截器
54 | widgetServerApi.interceptors.response.use(
55 | (response: AxiosResponse) => {
56 | if (response.config.responseType === 'blob') {
57 | // 如果是文件流,直接过
58 | return response
59 | }
60 | else if (response.data.code === 200) {
61 | return response.data.data
62 | }
63 | else {
64 | return Promise.reject(response.data)
65 | }
66 | },
67 | (error: AxiosError) => {
68 | LogApi.error('axios', {
69 | code: error.code,
70 | message: error.message,
71 | name: error.name,
72 | })
73 | return Promise.reject(error)
74 | },
75 | )
76 |
77 | export { widgetServerApi }
78 |
--------------------------------------------------------------------------------
/src/assets/cancel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/css/common.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 | body, *, view {
5 | box-sizing: border-box;
6 | user-select: none;
7 | -webkit-user-drag: none;
8 | }
9 |
10 | body {
11 | margin: 0;
12 | }
13 |
14 | button {
15 | margin: 0;
16 | padding: 0;
17 | border: 1px solid transparent;
18 | outline: none;
19 | background-color: transparent;
20 | }
21 |
22 | button:active {
23 | opacity: 0.6;
24 | }
25 |
26 | .flex-col {
27 | display: flex;
28 | flex-direction: column;
29 | }
30 |
31 | .flex-row {
32 | display: flex;
33 | flex-direction: row;
34 | }
35 |
36 | .justify-start {
37 | display: flex;
38 | justify-content: flex-start;
39 | }
40 |
41 | .justify-center {
42 | display: flex;
43 | justify-content: center;
44 | }
45 |
46 | .justify-end {
47 | display: flex;
48 | justify-content: flex-end;
49 | }
50 |
51 | .justify-evenly {
52 | display: flex;
53 | justify-content: space-evenly;
54 | }
55 |
56 | .justify-around {
57 | display: flex;
58 | justify-content: space-around;
59 | }
60 |
61 | .justify-between {
62 | display: flex;
63 | justify-content: space-between;
64 | }
65 |
66 | .align-start {
67 | display: flex;
68 | align-items: flex-start;
69 | }
70 |
71 | .align-center {
72 | display: flex;
73 | align-items: center;
74 | }
75 |
76 | .align-end {
77 | display: flex;
78 | align-items: flex-end;
79 | }
80 |
--------------------------------------------------------------------------------
/src/assets/images/bilibili_logo_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/bilibili_logo_blue.png
--------------------------------------------------------------------------------
/src/assets/images/bilibili_logo_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/bilibili_logo_red.png
--------------------------------------------------------------------------------
/src/assets/images/douyin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/douyin.png
--------------------------------------------------------------------------------
/src/assets/images/github-mark-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/github-mark-white.png
--------------------------------------------------------------------------------
/src/assets/images/github-mark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/github-mark.png
--------------------------------------------------------------------------------
/src/assets/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/logo.png
--------------------------------------------------------------------------------
/src/assets/images/qq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/qq.png
--------------------------------------------------------------------------------
/src/assets/images/storybook.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/src/assets/images/typescript.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/src/assets/images/vue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/images/vue.png
--------------------------------------------------------------------------------
/src/assets/scss/theme.scss:
--------------------------------------------------------------------------------
1 | @use "sass:map";
2 | @import "element-plus/theme-chalk/src/common/var.scss";
3 |
4 | $text-color-primary: map.get($text-color, "primary");
5 | $border-radius-base: map.get($border-radius, "base");
6 | $fill-color-default: map.get($fill-color, '');
7 | $box-shadow-default: map.get($box-shadow, '');
8 |
9 | $weight-regular: 400;
10 | $weight-bold: 700;
11 |
12 | @mixin electron-dialog{
13 | background-color: $fill-color-default;
14 | border-radius: $border-radius-base;
15 | box-shadow: $box-shadow-default;
16 | margin: 32px;
17 | border-width: 1px;
18 | border-color: rgba(0, 0, 0, 0.11);
19 | border-style: solid;
20 | }
21 |
22 | @mixin title-medium {
23 | font-weight: $weight-regular;
24 | font-size: 16px;
25 | color: $text-color-primary;
26 | }
27 |
28 | @mixin title-medium-bold {
29 | font-weight: $weight-bold;
30 | font-size: 16px;
31 | color: $text-color-primary;
32 | }
33 |
--------------------------------------------------------------------------------
/src/assets/svg/phone-hangup.svg:
--------------------------------------------------------------------------------
1 |
3 |
8 |
--------------------------------------------------------------------------------
/src/assets/video/tray_guide.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/assets/video/tray_guide.webm
--------------------------------------------------------------------------------
/src/common/Constants.ts:
--------------------------------------------------------------------------------
1 | export default class Constants {
2 | static readonly GUIDE_KEY_OVERLAP_MENU = 'Aijee1zeiY7meeghiewiebahfei0ic1'
3 | }
4 |
--------------------------------------------------------------------------------
/src/common/dayjs-extend.ts:
--------------------------------------------------------------------------------
1 | import dayjs from 'dayjs'
2 | import isoWeek from 'dayjs/plugin/isoWeek'
3 | import objectSupport from 'dayjs/plugin/objectSupport'
4 | import isBetween from 'dayjs/plugin/isBetween'
5 | import weekday from 'dayjs/plugin/weekday'
6 | import duration from 'dayjs/plugin/duration'
7 |
8 | dayjs.extend(duration)
9 | dayjs.extend(weekday)
10 | dayjs.extend(objectSupport)
11 | dayjs.extend(isBetween)
12 | dayjs.extend(isoWeek)
13 |
--------------------------------------------------------------------------------
/src/components/DatePickerDialog.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
43 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
80 |
--------------------------------------------------------------------------------
/src/components/FontSelector.vue:
--------------------------------------------------------------------------------
1 |
38 |
39 |
40 |
41 |
42 | 默认字体
43 |
44 |
45 | {{ font }} - 中国智造,慧及全球
46 |
47 |
48 |
49 |
50 |
53 |
--------------------------------------------------------------------------------
/src/components/LunarDatePicker.vue:
--------------------------------------------------------------------------------
1 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
123 |
--------------------------------------------------------------------------------
/src/components/SolarDatePicker.vue:
--------------------------------------------------------------------------------
1 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
82 |
--------------------------------------------------------------------------------
/src/components/TimePicker.vue:
--------------------------------------------------------------------------------
1 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
88 |
--------------------------------------------------------------------------------
/src/components/TimePickerDialog.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
38 |
39 |
40 |
46 |
47 |
48 |
49 |
50 |
51 |
62 |
--------------------------------------------------------------------------------
/src/composition/useAppConfig.ts:
--------------------------------------------------------------------------------
1 | import type { LanguageCode } from '@widget-js/core'
2 | import { AppApi } from '@widget-js/core'
3 | import { onMounted, ref, watch } from 'vue'
4 |
5 | const debugMode = ref(false)
6 | export function useDebugConfig(onLoad?: (debug: boolean) => void) {
7 | onMounted(async () => {
8 | debugMode.value = await AppApi.getDevMode()
9 | onLoad?.(debugMode.value)
10 | watch(debugMode, async (newValue) => {
11 | await AppApi.setDevMode(newValue)
12 | })
13 | })
14 | return debugMode
15 | }
16 |
17 | export function useCellSizeConfig() {
18 | const gridSize = ref(80)
19 | onMounted(async () => {
20 | gridSize.value = await AppApi.getGridCellSize()
21 | watch(gridSize, async (newValue) => {
22 | await AppApi.setGridCellSize(newValue)
23 | })
24 | })
25 |
26 | return gridSize
27 | }
28 |
29 | export function useLanguageConfig() {
30 | const languageCode = ref(navigator.language)
31 | let inited = false
32 | AppApi.getLanguageCode().then((result) => {
33 | languageCode.value = result
34 | inited = true
35 | })
36 |
37 | watch(languageCode, async (newValue) => {
38 | if (inited) {
39 | await AppApi.setLanguageCode(newValue as LanguageCode)
40 | }
41 | })
42 | return languageCode
43 | }
44 |
--------------------------------------------------------------------------------
/src/composition/useAppRuntimeInfo.ts:
--------------------------------------------------------------------------------
1 | import type { AppRuntimeInfo } from '@widget-js/core'
2 | import { AppApi } from '@widget-js/core'
3 | import { computed, ref } from 'vue'
4 |
5 | export type SimpleAppRuntimeInfo = Omit
6 | export function useAppRuntimeInfo() {
7 | const info = ref()
8 |
9 | AppApi.getRuntimeInfo().then((data) => {
10 | // sort keys
11 | const res = Object.keys(data).sort().reduce((obj, key) => {
12 | obj[key] = data[key]
13 | return obj
14 | }, {})
15 | info.value = res as AppRuntimeInfo
16 | })
17 |
18 | const simpleInfo = computed(() => {
19 | if (info.value) {
20 | const simple: SimpleAppRuntimeInfo = {
21 | app: info.value.app,
22 | cpuModel: info.value.cpuModel,
23 | arch: info.value.arch,
24 | electron: info.value.electron,
25 | release: info.value.release,
26 | isWindowsStore: info.value.isWindowsStore,
27 | totalMem: info.value.totalMem,
28 | systemName: info.value.systemName,
29 | }
30 | return simple
31 | }
32 | return undefined
33 | })
34 |
35 | return { info, simpleInfo }
36 | }
37 |
--------------------------------------------------------------------------------
/src/composition/useWidgetPackage.ts:
--------------------------------------------------------------------------------
1 | import type { RemotePackageUrlInfo } from '@widget-js/core'
2 | import { NotificationApi, WidgetPackageApi } from '@widget-js/core'
3 | import semver from 'semver'
4 | import type { ComputedRef, Ref } from 'vue'
5 | import { computed, reactive, ref, toRaw } from 'vue'
6 | import consola from 'consola'
7 |
8 | export interface UseWidgetPackageReturn {
9 | upgrading: ComputedRef
10 | upgradable: Ref
11 | checkUpgrade: () => Promise
12 | upgradePackage: () => Promise
13 | }
14 |
15 | const upgradablePackages = reactive([])
16 | const upgradingPackages = reactive([])
17 | const instanceCache = new Map()
18 |
19 | export function useWidgetPackage(packageName: string, remoteVersion: string, remoteUrlInfo?: RemotePackageUrlInfo): UseWidgetPackageReturn {
20 | if (instanceCache.has(packageName)) {
21 | return instanceCache.get(packageName)!
22 | }
23 | const checking = ref(false)
24 |
25 | const upgrading = computed(() => {
26 | return upgradingPackages.includes(packageName)
27 | })
28 |
29 | const upgradable = ref(false)
30 |
31 | const checkUpgrade = async (): Promise => {
32 | if (checking.value) {
33 | return false
34 | }
35 | checking.value = true
36 | try {
37 | const widgetPackage = await WidgetPackageApi.getPackage(packageName)
38 | if (widgetPackage) {
39 | if (widgetPackage.name == 'widget.js.fun') {
40 | consola.log(remoteVersion)
41 | }
42 | upgradable.value = semver.gt(remoteVersion, widgetPackage.version ?? '1.0.0')
43 | if (upgradable.value && !upgradablePackages.includes(packageName)) {
44 | upgradablePackages.push(packageName)
45 | }
46 | return upgradable.value
47 | }
48 | upgradablePackages.splice(upgradablePackages.indexOf(packageName), 1)
49 | }
50 | catch (e) {
51 | consola.error(e)
52 | }
53 | checking.value = false
54 | return false
55 | }
56 |
57 | const upgradePackage = async () => {
58 | upgradingPackages.push(packageName)
59 | try {
60 | if (!remoteUrlInfo) {
61 | NotificationApi.error('未配置组件包信息')
62 | return
63 | }
64 | await WidgetPackageApi.upgrade(packageName, toRaw(remoteUrlInfo))
65 | upgradingPackages.splice(upgradingPackages.indexOf(packageName), 1)
66 | upgradablePackages.splice(upgradablePackages.indexOf(packageName), 1)
67 | NotificationApi.success('组件包升级成功')
68 | upgradable.value = false
69 | }
70 | catch (e) {
71 | console.error(e)
72 | }
73 | }
74 | const instance: UseWidgetPackageReturn = { upgrading, upgradable, checkUpgrade, upgradePackage }
75 | instanceCache.set(packageName, instance)
76 | return instance
77 | }
78 |
--------------------------------------------------------------------------------
/src/countdown/CountdownList.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
--------------------------------------------------------------------------------
/src/countdown/Event.ts:
--------------------------------------------------------------------------------
1 | export enum DateType {
2 | LUNAR = 'LUNAR',
3 | SOLAR = 'SOLAR',
4 | }
5 |
6 | export class Event {
7 | name: string
8 | date: string
9 |
10 | dateType = DateType.SOLAR
11 |
12 | constructor(name: string, date: string, dateType: DateType) {
13 | this.name = name
14 | this.date = date
15 | this.dateType = dateType
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/i18n/default/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "social": "Follow",
3 | "proxy": "Proxy",
4 | "infoCopied": "Info Copied",
5 | "appInfo": "App Info",
6 | "loading": "Loading",
7 | "fullDetail": "Detail",
8 | "copyAndReport": "Copy & Report",
9 | "copy": "Copy",
10 | "add": "Add",
11 | "network": {
12 | "offline": "Network is offline",
13 | "failed": "Page failed to load: {msg}"
14 | },
15 | "search": {
16 | "title": "Search Widget",
17 | "placeholder": "Enter keyword",
18 | "developerTip": "Develop your own desktop widget",
19 | "devDoc": "Documentation",
20 | "enable": "Enable",
21 | "upgrade": "Upgrade",
22 | "add": "Add",
23 | "disable": "Disable",
24 | "desktop": "Desktop",
25 | "overlap": "Overlap"
26 | },
27 | "tags": {
28 | "all": "All",
29 | "ai": "AI",
30 | "tools": "Tools",
31 | "productivity": "Productivity",
32 | "news": "News",
33 | "weather": "Weather",
34 | "fun": "Fun",
35 | "calendar": "Calendar",
36 | "time": "Time",
37 | "countdown": "Countdown",
38 | "photo": "Photo",
39 | "debug": "Dev",
40 | "finance": "Finance",
41 | "wish": "Wish"
42 | },
43 | "manager": {
44 | "remove": "Remove",
45 | "refresh": "Refresh",
46 | "title": "Widget Title",
47 | "name": "Widget Name",
48 | "windowTitle": "Widget Manager",
49 | "confirmRemove": "Are you sure to remove this widget?"
50 | },
51 | "theme": {
52 | "translucent": "Translucent",
53 | "dark": "Dark",
54 | "light": "Light",
55 | "custom": "Custom"
56 | },
57 | "update": {
58 | "windowTitle": "Check for Updates",
59 | "alreadyLatestVersion": "Already the latest version",
60 | "newVersionDetect": "New version detected:",
61 | "upgradeToNew": "Please upgrade App to the latest version"
62 | },
63 | "notification": {
64 | "enableDevMode": "Developer mode enabled"
65 | },
66 | "exit": "Exit"
67 | }
68 |
--------------------------------------------------------------------------------
/src/i18n/default/zh.json:
--------------------------------------------------------------------------------
1 | {
2 | "social": "交个朋友",
3 | "appInfo": "应用信息",
4 | "copy": "应用信息",
5 | "fullDetail": "详细信息",
6 | "infoCopied": "已复制信息",
7 | "copyAndReport": "复制并提交BUG",
8 | "loading": "加载中",
9 | "tags": {
10 | "all": "全部",
11 | "ai": "AI",
12 | "tools": "工具",
13 | "productivity": "效率",
14 | "news": "资讯",
15 | "weather": "天气",
16 | "fun": "趣味",
17 | "calendar": "日历",
18 | "time": "时间",
19 | "countdown": "倒计时",
20 | "finance": "金融",
21 | "photo": "照片",
22 | "debug": "开发组件",
23 | "wish": "需求墙"
24 | },
25 | "search": {
26 | "title": "搜索组件",
27 | "placeholder": "请输入关键词",
28 | "developerTip": "开发属于自己的桌面组件",
29 | "devDoc": "开发文档",
30 | "desktop": "桌面",
31 | "overlap": "悬浮窗",
32 | "add": "添加",
33 | "upgrade": "升级",
34 | "enable": "启用",
35 | "disable": "禁用"
36 | },
37 | "manager": {
38 | "remove": "移除",
39 | "refresh": "刷新",
40 | "title": "组件标题",
41 | "name": "组件名",
42 | "windowTitle": "组件管理",
43 | "confirmRemove": "确定移除该组件"
44 | },
45 | "theme": {
46 | "translucent": "半透明",
47 | "dark": "深色",
48 | "light": "浅色",
49 | "custom": "自定义"
50 | },
51 | "network": {
52 | "offline": "村里还没通网,等待网络接通中",
53 | "failed": "组件加载失败:{msg}"
54 | },
55 | "update": {
56 | "windowTitle": "检测更新",
57 | "alreadyLatestVersion": "已经是最新版本",
58 | "newVersionDetect": "检测到新版本:",
59 | "upgradeToNew": "请先升级应用到最新版"
60 | },
61 | "notification": {
62 | "enableDevMode": "启用开发者模式"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/i18n/i18n.ts:
--------------------------------------------------------------------------------
1 | import { createI18n } from 'vue-i18n'
2 | import defaultZh from '@/i18n/default/zh.json'
3 | import defaultEn from '@/i18n/default/en.json'
4 | import settingsZh from '@/i18n/settings/zh.json'
5 | import settingsEn from '@/i18n/settings/en.json'
6 | import trayEn from '@/i18n/tray/en.json'
7 | import trayZh from '@/i18n/tray/zh.json'
8 |
9 | export const i18n = createI18n({
10 | legacy: false,
11 | locale: 'zh',
12 | messages: {
13 | 'zh': {
14 | ...defaultZh,
15 | settings: settingsZh,
16 | tray: trayZh,
17 | },
18 | 'en-US': {
19 | ...defaultEn,
20 | settings: settingsEn,
21 | tray: trayEn,
22 | },
23 | },
24 | fallbackLocale: 'en',
25 | })
26 |
--------------------------------------------------------------------------------
/src/i18n/settings/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Settings",
3 | "language": "Language",
4 | "common": "Common",
5 | "theme": "Global Theme",
6 | "desktop": "Desktop",
7 | "app": "App",
8 | "gridSize": "Grid Size",
9 | "launchAtStartup": "Startup",
10 | "developerMode": "Dev mode",
11 | "proxy": {
12 | "title": "Proxy",
13 | "tips": "If the proxy does not take effect, please try to refresh the widget",
14 | "port": "Port",
15 | "protocol": "Protocol",
16 | "server": "Server",
17 | "clear": "Clear"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/i18n/settings/zh.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "设置",
3 | "app": "应用设置",
4 | "language": "语言",
5 | "launchAtStartup": "开机启动",
6 | "theme": "全局主题",
7 | "common": "常用设置",
8 | "gridSize": "网格大小",
9 | "developerMode": "开发者模式",
10 | "desktop": "桌面设置",
11 | "proxy": {
12 | "title": "代理设置",
13 | "tips": "如果代理没有生效,请尝试刷新组件",
14 | "port": "代理端口",
15 | "protocol": "代理协议",
16 | "server": "代理服务器",
17 | "clear": "清除代理"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/i18n/tray/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "appVersion": "Version",
3 | "systemVersion": "System",
4 | "fullDetail": "Detail",
5 | "runningWidgets": "Running Widgets",
6 | "addWidget": "Widgets",
7 | "settings": {
8 | "title": "Settings"
9 | },
10 | "checkUpdates": "Update",
11 | "shareApp": "Share App",
12 | "exit": "Exit",
13 | "suggestions": "Suggestions & Feedback",
14 | "infoCopied": "Info Copied",
15 | "downloadLinkCopied": "Download link copied to clipboard",
16 | "restartWidgets": "Restart",
17 | "restartWidgetsConfirm": "Restart all widgets?",
18 | "yes": "Yes",
19 | "no": "No"
20 | }
21 |
--------------------------------------------------------------------------------
/src/i18n/tray/zh.json:
--------------------------------------------------------------------------------
1 | {
2 | "appVersion": "应用版本",
3 | "systemVersion": "系统版本",
4 | "fullDetail": "详细信息",
5 | "runningWidgets": "运行中的组件",
6 | "addWidget": "添加组件",
7 | "settings": {
8 | "title": "设置"
9 | },
10 | "checkUpdates": "检测更新",
11 | "shareApp": "分享应用",
12 | "exit": "退出",
13 | "suggestions": "建议与反馈",
14 | "infoCopied": "已复制信息",
15 | "downloadLinkCopied": "已复制下载链接到剪贴板",
16 | "restartWidgets": "重启组件",
17 | "restartWidgetsConfirm": "是否重启所有组件?",
18 | "yes": "是",
19 | "no": "否"
20 | }
21 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body *,
2 | page view {
3 | box-sizing: border-box;
4 | flex-shrink: 0;
5 | user-select: none;
6 | }
7 |
8 | body {
9 | margin: 0;
10 | overflow: hidden;
11 | }
12 |
13 | button {
14 | margin: 0;
15 | padding: 0;
16 | border: 1px solid transparent;
17 | outline: none;
18 | background-color: transparent;
19 | }
20 |
21 | .flex {
22 | display: flex;
23 | }
24 |
25 | .flex-1 {
26 | flex: 1 1 0%;
27 | }
28 |
29 | .gap-1 {
30 | gap: 0.25rem;
31 | }
32 |
33 | .gap-2 {
34 | gap: 0.5rem;
35 | }
36 |
37 | .justify-center {
38 | justify-content: center;
39 | }
40 |
41 | .items-center {
42 | align-items: center;
43 | }
44 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import dayjs from 'dayjs'
3 | import 'animate.css'
4 | import { WidgetJsPlugin } from '@widget-js/vue3'
5 | import '@widget-js/vue3/dist/style.css'
6 | import 'element-plus/dist/index.css'
7 | import { createPinia } from 'pinia'
8 | import { MotionPlugin } from '@vueuse/motion'
9 | import ElementPlus from 'element-plus'
10 | import './index.css'
11 | import router from './router'
12 | import 'dayjs/locale/zh-cn.js'
13 | import App from './App.vue'
14 | import 'virtual:uno.css'
15 | import '@icon-park/vue-next/styles/index.css'
16 | import 'element-plus/theme-chalk/src/message-box.scss'
17 | import 'element-plus/theme-chalk/src/message.scss'
18 | import 'element-plus/theme-chalk/src/loading.scss'
19 |
20 | import { i18n } from '@/i18n/i18n'
21 |
22 | dayjs.locale('cn')
23 |
24 | const pinia = createPinia()
25 | const app = createApp(App)
26 | app.use(ElementPlus)
27 | app.use(WidgetJsPlugin)
28 | app.use(MotionPlugin)
29 | app.use(i18n)
30 | app.use(router)
31 | app.use(pinia)
32 | app.mount('#app')
33 |
--------------------------------------------------------------------------------
/src/model/AppVersion.ts:
--------------------------------------------------------------------------------
1 | export class AppVersion {
2 | version!: string
3 | createdAt!: string
4 | releaseNote!: string
5 | downloadLink!: string
6 | updateElectron = false
7 | updateWindowsApi = false
8 | }
9 |
--------------------------------------------------------------------------------
/src/model/FeatureWall.ts:
--------------------------------------------------------------------------------
1 | export interface FeatureWall {
2 | id: number
3 | title: string
4 |
5 | description: string
6 |
7 | // 点赞次数
8 | likes: number
9 |
10 | // 预览图片
11 | previewImage: string
12 |
13 | // 打赏二维码
14 | rewardQRCode: string
15 |
16 | createTime: Date
17 |
18 | updateTime: Date
19 | }
20 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import {
3 | createRouter,
4 | createWebHashHistory,
5 | } from 'vue-router'
6 | import WidgetRouter from '@/widgets/widget-router'
7 |
8 | /**
9 | * 组件路由都以 /widget/开头,e.g. /widget/countdown
10 | * 组件设置路由都以 /widget/config/开头,e.g. /widget/config/countdown
11 | * webpackChunkName: 和路由名称保持一致
12 | */
13 | const routes: RouteRecordRaw[] = [
14 | ...WidgetRouter,
15 | {
16 | path: '/countdown/list',
17 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.quick_search" */ '../countdown/CountdownList.vue'),
18 | },
19 |
20 | {
21 | path: '/',
22 | name: 'home',
23 | component: import('@/views/add/AddWidgetView.vue'),
24 | },
25 | {
26 | path: '/setting',
27 | name: 'setting',
28 | component: () => import('@/views/settings/SettingView.vue'),
29 | },
30 | {
31 | path: '/setting/app/runtime',
32 | name: 'AppRunTime',
33 | component: () => import('@/views/settings/AppRuntimeView.vue'),
34 | },
35 | {
36 | path: '/manager',
37 | name: 'manager',
38 | component: () => import('@/views/manager/ManagerView.vue'),
39 | },
40 | {
41 | path: '/add',
42 | name: 'add',
43 | component: () => import('../views/add/AddWidgetView.vue'),
44 | },
45 | {
46 | path: '/failed',
47 | name: 'failed',
48 | component: () => import('../views/desktop/WidgetFailed.vue'),
49 | },
50 | {
51 | path: '/loading',
52 | name: 'loading',
53 | component: () => import('../views/desktop/Loading.vue'),
54 | },
55 | {
56 | path: '/desktop/grid',
57 | name: 'grid',
58 | component: () => import('../views/desktop/Grid.vue'),
59 | },
60 | {
61 | path: '/desktop/tray',
62 | name: 'tray',
63 | component: () => import('../views/desktop/TrayGuide.vue'),
64 | },
65 | {
66 | path: '/tray/menu',
67 | name: 'TrayMenu',
68 | component: () => import('../views/tray/TrayMenuView.vue'),
69 | },
70 | {
71 | path: '/check-update',
72 | name: 'check-update',
73 | component: () =>
74 | import('../views/update/CheckUpdateView.vue'),
75 | },
76 | ]
77 |
78 | const router = createRouter({
79 | history: createWebHashHistory(),
80 | routes,
81 | })
82 | export default router
83 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | declare module '*.vue' {
3 | import type {DefineComponent} from 'vue'
4 | const component: DefineComponent<{}, {}, any>
5 | export default component
6 | }
7 | declare module "*.png" {
8 | const value: string;
9 | export default value;
10 | }
11 |
--------------------------------------------------------------------------------
/src/util/LunarUtils.ts:
--------------------------------------------------------------------------------
1 | import type { Lunar, Solar } from 'lunar-typescript'
2 |
3 | export class LunarUtils {
4 | private static CHINESE_NUMBER = '〇一二三四五六七八九十'
5 | static getLunarMonthText(month: number): string {
6 | const arr: string[] = []
7 | if (month < 0) {
8 | arr.push('闰')
9 | }
10 | if (month == 10) {
11 | arr.push('十')
12 | }
13 | else {
14 | if (month > 10) {
15 | arr.push('十')
16 | }
17 | arr.push(this.CHINESE_NUMBER[Math.abs(month) % 10])
18 | }
19 |
20 | arr.push('月')
21 | return arr.join('')
22 | }
23 |
24 | /**
25 | * 1-10 初一 初二 初三 初四 初五 初六 初七 初八 初九 初十
26 | * 11-20 十一 十二 十三 十四 十五 十六 十七 十八 十九 二十
27 | * 21-30 廿一 廿二 廿三 廿四 廿五 廿六 廿七 廿八 廿九 三十
28 | * @param day
29 | */
30 | static getLunarDayText(day: number) {
31 | const arr: string[] = []
32 | if (day < 10) {
33 | arr.push('初', this.CHINESE_NUMBER[day % 10])
34 | }
35 | else if (day == 10) {
36 | arr.push('初十')
37 | }
38 | else if (day === 20) {
39 | arr.push('二十')
40 | }
41 | else if (day > 20 && day < 30) {
42 | arr.push('廿', this.CHINESE_NUMBER[day % 10])
43 | }
44 | else if (day === 30) {
45 | arr.push('三十')
46 | }
47 | else {
48 | arr.push('十', this.CHINESE_NUMBER[day % 10])
49 | }
50 | return arr.join('')
51 | }
52 |
53 | static lunarToDate(lunar: Lunar): Date {
54 | return this.solarToDate(lunar.getSolar())
55 | }
56 |
57 | static solarToDate(solar: Solar): Date {
58 | return new Date(solar.getYear(), solar.getMonth() - 1, solar.getDay())
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/util/TimeUtils.ts:
--------------------------------------------------------------------------------
1 | export async function delay(ms: number) {
2 | return new Promise(resolve => setTimeout(resolve, ms))
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/TimeUtils.ts:
--------------------------------------------------------------------------------
1 | export function delay(ms: number) {
2 | return new Promise(resolve => setTimeout(resolve, ms))
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/VersionUtils.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import semver from 'semver'
3 | import { AppApi } from '@widget-js/core'
4 | import consola from 'consola'
5 | import type { AppVersion } from '@/model/AppVersion'
6 |
7 | export default class VersionUtils {
8 | static checkNewVersion(onNewVersion: (version: AppVersion) => void, onError?: (error) => void, onFinally?: () => void) {
9 | axios.get('https://widget-fun.oss-cn-hangzhou.aliyuncs.com/version/version.json')
10 | .then(async (response) => {
11 | // handle success
12 | if (response.status == 200) {
13 | const data = response.data as AppVersion
14 | const currentVersion = await AppApi.getVersion()
15 | consola.info('current:', currentVersion, 'server:', data.version)
16 | if (semver.gt(data.version, currentVersion)) {
17 | consola.info('New version detected:', data.version)
18 | consola.info('Download Link:', data.downloadLink)
19 | onNewVersion(data)
20 | }
21 | }
22 | })
23 | .catch((error) => {
24 | onError?.(error)
25 | })
26 | .finally(() => {
27 | onFinally?.()
28 | })
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/utils/WidgetUtil.ts:
--------------------------------------------------------------------------------
1 | import type { SocialType } from '@widget-js/core'
2 |
3 | export default class WidgetUtil {
4 | static getSocialLinkIcon(socialName: SocialType) {
5 | switch (socialName) {
6 | case 'github':
7 | return 'https://widgetjs.cn/image/logo/github.png'
8 | case 'bilibili':
9 | return 'https://widgetjs.cn/image/logo/bilibili.png'
10 | case 'discord':
11 | return 'https://widgetjs.cn/image/logo/discord.png'
12 | case 'tiktok':
13 | case 'douyin':
14 | return 'https://widgetjs.cn/image/logo/douyin.png'
15 | case 'email':
16 | return 'https://widgetjs.cn/image/logo/email.png'
17 | case 'qq':
18 | return 'https://widgetjs.cn/image/logo/qq.png'
19 | case 'gitee':
20 | return 'https://widgetjs.cn/image/logo/gitee.png'
21 | case 'youtube':
22 | return 'https://widgetjs.cn/image/logo/youtube.png'
23 | case 'wechat':
24 | return 'https://widgetjs.cn/image/logo/wechat.png'
25 | default:
26 | return ''
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/views/Loading.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/src/views/add/WidgetContainer.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
53 |
54 |
55 |
133 |
--------------------------------------------------------------------------------
/src/views/add/WidgetTags.vue:
--------------------------------------------------------------------------------
1 |
34 |
35 |
36 |
37 |
38 |
39 | {{ t(item.labelKey) }}
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/views/add/feature/FeatureWallList.vue:
--------------------------------------------------------------------------------
1 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | 提交你的需求
40 |
41 |
42 |
43 |
44 |
45 |
47 |
--------------------------------------------------------------------------------
/src/views/add/feature/FeatureWallListItem.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 |
36 |
42 |
43 |
44 | {{ model.title }}
45 |
46 |
47 | {{ model.description }}
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 打赏
62 |
63 |
64 |
65 |
66 |
67 |
68 | 赞同 ({{ model.likes }})
69 |
70 |
71 |
72 |
73 |
74 |
77 |
--------------------------------------------------------------------------------
/src/views/desktop/GridSystemDrawer.ts:
--------------------------------------------------------------------------------
1 | import type { GridSystem } from '@/views/desktop/GridSystem'
2 |
3 | export class GridSystemDrawer {
4 | private gridContext: CanvasRenderingContext2D
5 | gridSystem: GridSystem
6 |
7 | constructor(gridSystem: GridSystem) {
8 | this.gridSystem = gridSystem
9 | const canvas = document.getElementById('canvas') as HTMLCanvasElement
10 | this.gridContext = canvas.getContext('2d') as CanvasRenderingContext2D
11 | this.drawGrid()
12 | }
13 |
14 | drawGrid() {
15 | const height = this.gridSystem.getHeight()
16 | const width = this.gridSystem.getWidth()
17 | this.gridContext.save()
18 | this.gridContext.translate(this.gridSystem.left, this.gridSystem.top)
19 | this.gridContext.roundRect(0, 0, width, height, 8)
20 |
21 | for (let i = 1; i < this.gridSystem.horizontalCellCount; i++) {
22 | const x = (i * this.gridSystem.cellSize)
23 | this.gridContext.moveTo(x, 0)
24 | this.gridContext.lineTo(x, height)
25 | this.gridContext.stroke()
26 | }
27 |
28 | for (let i = 1; i < this.gridSystem.verticalCellCount; i++) {
29 | const y = (i * this.gridSystem.cellSize)
30 | this.gridContext.moveTo(0, y)
31 | this.gridContext.lineTo(width, y)
32 | this.gridContext.stroke()
33 | }
34 |
35 | this.gridContext.restore()
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/views/desktop/Loading.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
{{ t("loading") }}
12 |
13 |
14 |
15 |
16 |
73 |
--------------------------------------------------------------------------------
/src/views/desktop/TrayGuide.vue:
--------------------------------------------------------------------------------
1 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
49 |
--------------------------------------------------------------------------------
/src/views/desktop/WidgetFailed.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
43 |
44 |
45 |
{{ t('network.failed', { msg: route.query.errorCode }) }}
46 |
47 | {{ desc }}
48 |
49 |
50 |
51 |
52 |
53 |
76 |
--------------------------------------------------------------------------------
/src/views/manager/DeployedWidgetCard.vue:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | {{ t('manager.title') }}:{{ widget.getTitle(locale) }}
50 |
51 |
52 | {{ t('manager.name') }}:{{ deployedWidget.name }}
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | 鼠标穿透
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
85 |
--------------------------------------------------------------------------------
/src/views/manager/DeployedWidgetList.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
--------------------------------------------------------------------------------
/src/views/manager/ManagerView.vue:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
--------------------------------------------------------------------------------
/src/views/overlap/OverlapGuide.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
9 |

14 |
鼠标右击弹出菜单
15 |
16 |
17 |
18 |
37 |
--------------------------------------------------------------------------------
/src/views/settings/AiSettingPanel.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
--------------------------------------------------------------------------------
/src/views/settings/AppRuntimeView.vue:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | {{ key }}: {{ simpleInfo[key] }}
16 |
17 |
18 |
19 |
20 |
21 |
22 |
25 |
--------------------------------------------------------------------------------
/src/views/settings/ProxySettingPanel.vue:
--------------------------------------------------------------------------------
1 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | HTTP
60 |
61 |
62 | HTTPS
63 |
64 |
65 | SOCK4
66 |
67 |
68 | SOCK5
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | {{ t('settings.proxy.clear') }}
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
99 |
--------------------------------------------------------------------------------
/src/views/settings/SettingSection.vue:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 | {{ title }}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
32 |
--------------------------------------------------------------------------------
/src/views/settings/theme/ThemeSettingPanel.vue:
--------------------------------------------------------------------------------
1 |
32 |
33 |
34 |
35 |
36 |
52 |
53 |
54 |
55 |
71 |
--------------------------------------------------------------------------------
/src/views/settings/theme/ThemeTag.ts:
--------------------------------------------------------------------------------
1 | import type { WidgetTheme } from '@widget-js/core'
2 |
3 | export interface ThemeTag {
4 | name: string
5 | value: string
6 | theme: WidgetTheme
7 | }
8 |
--------------------------------------------------------------------------------
/src/views/settings/theme/ThemeTags.vue:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
43 |
44 | {{ t(item.name) }}
45 |
46 |
47 |
48 |
49 |
52 |
--------------------------------------------------------------------------------
/src/views/tray/SocialLinks.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
44 |
45 |
46 |
65 |
--------------------------------------------------------------------------------
/src/views/update/CheckUpdateView.vue:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {{ error }}
73 |
74 |
75 |
76 | {{ t('update.alreadyLatestVersion') }}
77 |
78 |
79 | {{ t('update.newVersionDetect') }} {{ appVersion.version }}
80 | {{ appVersion.releaseNote }}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
95 |
96 |
97 |
98 |
99 |
100 |
112 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | // /
2 |
--------------------------------------------------------------------------------
/src/widgets/birthday-list/BirthdayList.widget.ts:
--------------------------------------------------------------------------------
1 | import { Widget, WidgetKeyword } from '@widget-js/core'
2 |
3 | const name = 'cn.widgetjs.widgets.birthday_list'
4 | // 组件标题
5 | const title = { 'zh-CN': '生日列表' }
6 | // 组件描述
7 | const desc = { 'zh-CN': '自动倒计时的生日列表' }
8 | // 组件关键词
9 | const keywords = [WidgetKeyword.RECOMMEND]
10 | const path = '/widget/birthday_list'
11 | const BirthdayListWidgetDefine = new Widget({
12 | name,
13 | title,
14 | description: desc,
15 | keywords,
16 | lang: 'zh-CN',
17 | width: 4,
18 | previewImage: '/images/preview_birthday_list.png',
19 | height: 4,
20 | minWidth: 3,
21 | maxWidth: 4,
22 | minHeight: 3,
23 | categories: ['countdown'],
24 | maxHeight: 6,
25 | disabled: true,
26 | socialLinks: [
27 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
28 | ],
29 | path,
30 | configPagePath: '/widget/config/birthday_list?frame=true&transparent=false',
31 | })
32 |
33 | export default BirthdayListWidgetDefine
34 |
--------------------------------------------------------------------------------
/src/widgets/birthday-list/BirthdayListWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import BirthdayListWidgetDefine from '@/widgets/birthday-list/BirthdayList.widget'
3 |
4 | const BirthdayListWidgetRoutes: RouteRecordRaw[] = [
5 | {
6 | path: BirthdayListWidgetDefine.path,
7 | name: `${BirthdayListWidgetDefine.name}`,
8 | component: () => import(/* webpackChunkName: "cn.widgetjs.widgets.birthday_list" */ './BirthdayListWidgetView.vue'),
9 | },
10 | {
11 | path: BirthdayListWidgetDefine.configPagePath!.split('?')[0],
12 | name: `${BirthdayListWidgetDefine.name}.config`,
13 | component: () =>
14 | import(/* webpackChunkName: "cn.widgetjs.widgets.birthday_list.config" */ './BirthdayListConfigView.vue'),
15 | },
16 | ]
17 |
18 | export default BirthdayListWidgetRoutes
19 |
--------------------------------------------------------------------------------
/src/widgets/birthday-list/BirthdayListWidgetView.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/widgets/birthday-list/images/balloon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/birthday-list/images/balloon.png
--------------------------------------------------------------------------------
/src/widgets/birthday-list/model/BirthdayListData.ts:
--------------------------------------------------------------------------------
1 | import { WidgetData } from '@widget-js/core'
2 | import BirthdayListWidgetDefine from '@/widgets/birthday-list/BirthdayList.widget'
3 |
4 | export interface BirthdayPeople {
5 | name: string
6 | month: number
7 | day: number
8 | type: string
9 | qty: number
10 | /**
11 | * 创建的时间戳,用于排序使用
12 | */
13 | createdAt: number
14 | }
15 |
16 | export default class BirthdayListData extends WidgetData {
17 | peopleList: BirthdayPeople[] = []
18 | title = '生日列表'
19 |
20 | constructor() {
21 | super(BirthdayListWidgetDefine.name)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/widgets/countdown/Countdown.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const name = 'cn.widgetjs.widgets.countdown'
7 | // 组件标题
8 | const title = { 'zh-CN': '倒计时' }
9 | // 组件描述
10 | const description = { 'zh-CN': '简单的倒计时组件,支持农历' }
11 | // 组件关键词
12 | const keywords = [WidgetKeyword.RECOMMEND]
13 | // 组件路由地址
14 | const url = '/widget/countdown'
15 | // 配置页路由地址
16 | // 组件关键词
17 | const CountdownWidgetDefine = new Widget({
18 | path: url,
19 | configPagePath: '/widget/config/countdown?frame=true&transparent=false&width=600&height=500',
20 | name,
21 | title,
22 | description,
23 | categories: ['countdown'],
24 | keywords,
25 | lang: 'zh-CN',
26 | previewImage: '/images/preview_countdown.png',
27 | width: 2,
28 | height: 2,
29 | minWidth: 2,
30 | maxWidth: 4,
31 | minHeight: 2,
32 | maxHeight: 4,
33 | disabled: true,
34 | socialLinks: [
35 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
36 | ],
37 | })
38 |
39 | export default CountdownWidgetDefine
40 |
--------------------------------------------------------------------------------
/src/widgets/countdown/CountdownWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import CountdownWidgetDefine from './Countdown.widget'
3 |
4 | const url = CountdownWidgetDefine.path
5 | const name = CountdownWidgetDefine.name
6 |
7 | const configUrl = CountdownWidgetDefine.configPagePath!.split('?')[0]
8 |
9 | const CountdownWidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.countdown" */ './CountdownWidgetView.vue'),
14 | },
15 | {
16 | path: configUrl,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.countdown.config" */ './CountdownConfigView.vue'),
19 | },
20 | ]
21 |
22 | export default CountdownWidgetRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/countdown/CountdownWidgetView.vue:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
37 |
--------------------------------------------------------------------------------
/src/widgets/countdown/model/CountdownModel.ts:
--------------------------------------------------------------------------------
1 | import { WidgetData } from '@widget-js/core'
2 | import dayjs from 'dayjs'
3 | import { DateType } from '@/countdown/Event'
4 |
5 | export class CountdownModel extends WidgetData {
6 | static DEFAULT_DATE = dayjs().set('year', dayjs().get('year') + 1).set('month', 0).set('date', 1).toDate()
7 | title = '新年'
8 | date: string = CountdownModel.DEFAULT_DATE.toISOString()
9 | dateType = DateType.SOLAR
10 |
11 | constructor(name: string, id?: string) {
12 | super(name, id)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/widgets/countdown2/Countdown2.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const name = 'cn.widgetjs.widgets.countdown2'
7 | // 组件标题
8 | const title = { 'zh-CN': '倒计时' }
9 | // 组件描述
10 | const description = { 'zh-CN': '日历样式的倒计时组件' }
11 | // 组件关键词
12 | const keywords = [WidgetKeyword.RECOMMEND]
13 | // 组件路由地址
14 | const url = '/widget/countdown2'
15 | // 组件关键词
16 | const Countdown2WidgetDefine = new Widget({
17 | path: url,
18 | configPagePath: '/widget/config/countdown2?frame=true&transparent=false',
19 | name,
20 | title,
21 | description,
22 | categories: ['countdown'],
23 | keywords,
24 | previewImage: '/images/preview_countdown2.png',
25 | lang: 'zh-CN',
26 | width: 2,
27 | height: 2,
28 | disabled: true,
29 | minWidth: 2,
30 | maxWidth: 4,
31 | minHeight: 2,
32 | maxHeight: 4,
33 | socialLinks: [
34 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
35 | ],
36 | })
37 |
38 | export default Countdown2WidgetDefine
39 |
--------------------------------------------------------------------------------
/src/widgets/countdown2/Countdown2ConfigView.vue:
--------------------------------------------------------------------------------
1 |
90 |
91 |
92 |
99 |
100 |
101 |
102 |
103 |
104 |
110 |
111 | {{ dateStr }}
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/widgets/countdown2/Countdown2WidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import Countdown2WidgetDefine from './Countdown2.widget'
3 |
4 | const url = Countdown2WidgetDefine.path
5 | const name = Countdown2WidgetDefine.name
6 |
7 | const configUrl = Countdown2WidgetDefine.configPagePath!.split('?')[0]
8 |
9 | const Countdown2WidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.countdown2" */ './Countdown2WidgetView.vue'),
14 | },
15 | {
16 | path: configUrl!,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.countdown2.config" */ './Countdown2ConfigView.vue'),
19 | },
20 | ]
21 |
22 | export default Countdown2WidgetRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/countdown2/Countdown2WidgetView.vue:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
36 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/DynamicIsland.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | DeployMode,
3 | Widget,
4 | WidgetKeyword,
5 | } from '@widget-js/core'
6 |
7 | const name = 'cn.widgetjs.widgets.dynamic_island'
8 | // 组件标题
9 | const title = { 'zh-CN': '久坐提醒' }
10 | // 组件描述
11 | const description = { 'zh-CN': '设置间隔,定时提醒,适合长期久坐的人群' }
12 | // 组件关键词
13 | const keywords = [WidgetKeyword.RECOMMEND]
14 | // 组件路由地址
15 | const url = '/widget/dynamic_island'
16 | // 组件关键词
17 | const DynamicIslandWidgetDefine = new Widget({
18 | path: url,
19 | configPagePath: '/widget/config/dynamic_island?frame=true&transparent=false',
20 | name,
21 | title,
22 | description,
23 | keywords,
24 | categories: ['utilities'],
25 | lang: 'zh-CN',
26 | width: 6,
27 | height: 4,
28 | minWidth: 6,
29 | maxWidth: 6,
30 | minHeight: 4,
31 | maxHeight: 4,
32 | previewImage: '/images/preview_sit_reminder.png',
33 | supportDeployMode: DeployMode.BACKGROUND,
34 | socialLinks: [
35 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
36 | ],
37 | })
38 |
39 | export default DynamicIslandWidgetDefine
40 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/DynamicIslandWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import DynamicIslandWidgetDefine from './DynamicIsland.widget'
3 |
4 | const url = DynamicIslandWidgetDefine.path
5 | const name = DynamicIslandWidgetDefine.name
6 |
7 | const DynamicIslandWidgetRoutes: RouteRecordRaw[] = [
8 | {
9 | path: url,
10 | name: `${name}`,
11 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.dynamic_island" */ './DynamicIslandWidgetView.vue'),
12 | },
13 | {
14 | path: '/widget/dynamic_island/call',
15 | name: `${name}.call`,
16 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.dynamic_island.call" */ './components/PhoneCallNotification.vue'),
17 | },
18 | ]
19 |
20 | export default DynamicIslandWidgetRoutes
21 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/components/AdvanceCountdownNotification.vue:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
30 |
31 | {{ title }}
32 |
33 |
{{ message }}
34 |
35 |
{{ minutes }} min
36 |
37 |
38 |
39 |
102 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/components/CountingNotification.vue:
--------------------------------------------------------------------------------
1 |
60 |
61 |
62 |
63 |
64 |
65 | {{ message }}
66 |
67 |
68 |
{{ timeString }}
69 |
72 |
73 |
74 |
75 |
127 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/components/CustomUrlNotification.vue:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
19 |
20 |
21 |
33 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/components/MessageNotification.vue:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 | {{ message }}
18 |
19 |
20 |
21 |
22 |
65 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/components/VoiceBar.vue:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
70 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/model/Demo.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AppNotification,
3 | WidgetApi,
4 | } from '@widget-js/core'
5 | import dayjs from 'dayjs'
6 |
7 | export const SitReminderDemo = new AppNotification({
8 | type: 'reminder',
9 | message: '您已经连续使用电脑45分钟',
10 | title: '久坐提醒',
11 | icon: 'computer_line',
12 | cancelButtonText: '知道了',
13 | backgroundColor: 'black',
14 | confirmButtonText: '休息一下',
15 | })
16 |
17 | export const AdvanceCountdownDemo = new AppNotification({
18 | type: 'advance-countdown',
19 | title: '新年倒计时',
20 | message: '恭喜发财',
21 | backgroundColor: 'black',
22 | targetTime: dayjs().add(1, 'hour').toISOString(),
23 | })
24 |
25 | export async function getZhangYuGe() {
26 | const notification = new AppNotification({ message: '下班提醒' })
27 | const packageUrl = await WidgetApi.getWidgetPackageUrl('cn.widgetjs.widgets')
28 | notification.avatar = `${packageUrl}/images/zhangyuge.jpg`
29 | notification.title = '章鱼哥'
30 | notification.type = 'call'
31 | notification.backgroundColor = 'black'
32 | return notification
33 | }
34 |
35 | export async function getTeaCall() {
36 | const notification = new AppNotification({ message: '饮茶提醒' })
37 | const packageUrl = await WidgetApi.getWidgetPackageUrl('cn.widgetjs.widgets')
38 | notification.avatar = `${packageUrl}/images/avatar/elvis.png`
39 | notification.title = '饮茶哥'
40 | notification.type = 'call'
41 | notification.backgroundColor = 'black'
42 | return notification
43 | }
44 |
45 | export function getCountdownDemo() {
46 | return new AppNotification({
47 | type: 'countdown',
48 | message: '倒计时',
49 | backgroundColor: 'rgba(0,0,0,0.5)',
50 | targetTime: dayjs().add(1, 'hour').toISOString(),
51 | })
52 | }
53 |
54 | export const ErrorDemo = new AppNotification({
55 | type: 'error',
56 | message: '错误信息',
57 | })
58 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/model/NotificationState.ts:
--------------------------------------------------------------------------------
1 | export enum NotificationState {
2 | HIDE = 'hide',
3 | SMALL = 'small',
4 | NORMAL = 'normal',
5 | LARGE = 'large',
6 | }
7 |
--------------------------------------------------------------------------------
/src/widgets/dynamic-island/scss/notification.scss:
--------------------------------------------------------------------------------
1 | $notification-width: 350px
2 |
--------------------------------------------------------------------------------
/src/widgets/key-stroke/KeyStroke.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | DeployMode,
3 | Widget,
4 | WidgetKeyword,
5 | } from '@widget-js/core'
6 |
7 | const name = 'cn.widgetjs.widgets.key_stroke'
8 | // 组件标题
9 | const title = { 'zh-CN': '键盘演示' }
10 | // 组件描述
11 | const description = { 'zh-CN': '在屏幕显示每一次快捷键敲击' }
12 | // 组件关键词
13 | const keywords = [WidgetKeyword.RECOMMEND]
14 | // 组件路由地址
15 | const url = '/widget/key_stroke'
16 | // 组件关键词
17 | const KeyStrokeWidgetDefine = new Widget({
18 | name,
19 | title,
20 | description,
21 | keywords,
22 | lang: 'zh-CN',
23 | width: 4,
24 | height: 3,
25 | disabled: true,
26 | minWidth: 4,
27 | maxWidth: 4,
28 | minHeight: 3,
29 | maxHeight: 3,
30 | supportDeployMode: DeployMode.BACKGROUND,
31 | backgroundThrottling: false,
32 | permissions: ['keyboard'],
33 | movable: false,
34 | categories: ['utilities'],
35 | previewImage: '/images/preview_keystroke.png',
36 | socialLinks: [
37 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
38 | ],
39 | path: url,
40 | })
41 |
42 | export default KeyStrokeWidgetDefine
43 |
--------------------------------------------------------------------------------
/src/widgets/key-stroke/KeyStrokeWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import KeyStrokeWidgetDefine from './KeyStroke.widget'
3 |
4 | const url = KeyStrokeWidgetDefine.path
5 | const name = KeyStrokeWidgetDefine.name
6 |
7 | const KeyStrokeWidgetRoutes: RouteRecordRaw[] = [
8 | {
9 | path: url,
10 | name: `${name}`,
11 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.key_stroke" */ './KeyStrokeWidgetView.vue'),
12 | },
13 | ]
14 |
15 | export default KeyStrokeWidgetRoutes
16 |
--------------------------------------------------------------------------------
/src/widgets/key-stroke/KeyStrokeWidgetView.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
--------------------------------------------------------------------------------
/src/widgets/labor-progress/LaborProgress.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const name = 'cn.widgetjs.widgets.labor_progress'
7 | // 组件标题
8 | const title = { 'zh-CN': '打工进度' }
9 | // 组件描述
10 | const description = { 'zh-CN': '打工人,打工魂' }
11 | // 组件关键词
12 | const keywords = [WidgetKeyword.RECOMMEND]
13 | const url = '/widget/labor_progress'
14 |
15 | // 组件关键词
16 | const LaborProgressWidgetDefine = new Widget({
17 | name,
18 | title,
19 | description,
20 | keywords,
21 | lang: 'zh-CN',
22 | width: 4,
23 | categories: ['fun'],
24 | height: 1,
25 | previewImage: '/images/preview_labor_progress.png',
26 | minWidth: 3,
27 | maxWidth: 6,
28 | socialLinks: [
29 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
30 | ],
31 | minHeight: 1,
32 | maxHeight: 2,
33 | path: url,
34 | configPagePath: '/widget/config/labor_progress?frame=true&transparent=false',
35 | })
36 |
37 | export default LaborProgressWidgetDefine
38 |
--------------------------------------------------------------------------------
/src/widgets/labor-progress/LaborProgressConfigView.vue:
--------------------------------------------------------------------------------
1 |
62 |
63 |
64 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/widgets/labor-progress/LaborProgressRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import LaborProgressWidgetDefine from '@/widgets/labor-progress/LaborProgress.widget'
3 |
4 | const LaborProgressWidgetRoutes: RouteRecordRaw[] = [
5 | {
6 | path: LaborProgressWidgetDefine.path,
7 | name: `${LaborProgressWidgetDefine.name}`,
8 | component: () => import(/* webpackChunkName: "cn.widgetjs.widgets.labor_progress" */ './LaborProgressWidgetView.vue'),
9 | },
10 | {
11 | path: LaborProgressWidgetDefine.configPagePath!.split('?')[0],
12 | name: `${LaborProgressWidgetDefine.name}.config`,
13 | component: () => import(/* webpackChunkName: "cn.widgetjs.widgets.labor_progress.config" */ './LaborProgressConfigView.vue'),
14 | },
15 | ]
16 |
17 | export default LaborProgressWidgetRoutes
18 |
--------------------------------------------------------------------------------
/src/widgets/labor-progress/LaborProgressWidgetView.vue:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/face_holding_back_tears_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/face_holding_back_tears_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/face_with_rolling_eyes_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/face_with_rolling_eyes_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/face_with_spiral_eyes_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/face_with_spiral_eyes_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/face_with_steam_from_nose_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/face_with_steam_from_nose_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/knocked-out_face_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/knocked-out_face_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/partying_face_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/partying_face_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/sleeping_face_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/sleeping_face_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/sleepy_face_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/sleepy_face_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/smiling_face_with_sunglasses_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/smiling_face_with_sunglasses_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/star-struck_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/star-struck_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/images/yawning_face_3d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/labor-progress/images/yawning_face_3d.png
--------------------------------------------------------------------------------
/src/widgets/labor-progress/model/EmojiTimeline.ts:
--------------------------------------------------------------------------------
1 | export default class EmojiTimeline {
2 | startPercent: number
3 | endPercent: number
4 |
5 | emoji: string
6 |
7 | title = '-1s'
8 | titleAnimationDuration = 1
9 |
10 | constructor(emoji: string, startPercent: number, endPercent: number, titleAnimationDuration = 1, title = '-1s') {
11 | this.emoji = emoji
12 | this.startPercent = startPercent
13 | this.endPercent = endPercent
14 | this.titleAnimationDuration = titleAnimationDuration
15 | this.title = title
16 | }
17 |
18 | isActivated(percent: number): boolean {
19 | return this.endPercent >= percent && this.startPercent <= percent
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/widgets/labor-progress/model/LaborProgressData.ts:
--------------------------------------------------------------------------------
1 | import { WidgetData } from '@widget-js/core'
2 | import dayjs from 'dayjs'
3 |
4 | export default class LaborProgressData extends WidgetData {
5 | startHour = 9
6 | startMinute = 0
7 | endHour = 18
8 | endMinute = 0
9 |
10 | getStartTime() {
11 | return dayjs().set('hour', this.startHour).set('minute', this.startMinute).set('second', 0).toDate()
12 | }
13 |
14 | getEndTime() {
15 | return dayjs().set('hour', this.endHour).set('minute', this.endMinute).set('second', 0).toDate()
16 | }
17 |
18 | setStartTime(date: Date) {
19 | const d = dayjs(date)
20 | this.startHour = d.hour()
21 | this.startMinute = d.minute()
22 | }
23 |
24 | setEndTime(date: Date) {
25 | const d = dayjs(date)
26 | this.endHour = d.hour()
27 | this.endMinute = d.minute()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/widgets/phone-reminder/PhoneReminder.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BackgroundWidget,
3 | DeployMode,
4 | WidgetKeyword,
5 | } from '@widget-js/core'
6 |
7 | const name = 'cn.widgetjs.widgets.phone_reminder'
8 | // 组件标题
9 | const title = { 'zh-CN': '来电提醒' }
10 | // 组件描述
11 | const description = { 'zh-CN': '用灵动通知加语音,提醒重要事项' }
12 | // 组件关键词
13 | const keywords = [WidgetKeyword.RECOMMEND]
14 | // 组件路由地址
15 | const url = '/widget/phone_reminder'
16 | // 组件关键词
17 | const PhoneReminderWidgetDefine = new BackgroundWidget({
18 | name,
19 | title,
20 | description,
21 | keywords,
22 | lang: 'zh-CN',
23 | supportDeployMode: DeployMode.BACKGROUND,
24 | categories: ['fun'],
25 | previewImage: '/images/preview_phone_reminder.png',
26 | path: url,
27 | socialLinks: [
28 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
29 | ],
30 | configPagePath: '/widget/config/phone_reminder?frame=true&transparent=false',
31 | })
32 |
33 | export default PhoneReminderWidgetDefine
34 |
--------------------------------------------------------------------------------
/src/widgets/phone-reminder/PhoneReminderWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import PhoneReminderWidgetDefine from './PhoneReminder.widget'
3 |
4 | const url = PhoneReminderWidgetDefine.path
5 | const name = PhoneReminderWidgetDefine.name
6 |
7 | const configUrl = PhoneReminderWidgetDefine.configPagePath!.split('?')[0]
8 |
9 | const PhoneReminderWidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.phone_reminder" */ './PhoneReminderWidgetView.vue'),
14 | },
15 | {
16 | path: configUrl,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.phone_reminder.config" */ './PhoneReminderConfigView.vue'),
19 | },
20 | ]
21 |
22 | export default PhoneReminderWidgetRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/phone-reminder/PhoneReminderWidgetView.vue:
--------------------------------------------------------------------------------
1 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/widgets/photo/Photo.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const name = 'cn.widgetjs.widgets.photo'
7 | // 组件标题
8 | const title = { 'zh-CN': '轮播相册' }
9 | // 组件描述
10 | const description = { 'zh-CN': '轮播文件夹内的图片' }
11 | // 组件关键词
12 | const keywords = [WidgetKeyword.RECOMMEND]
13 | // 组件路由地址
14 | const path = '/widget/photo'
15 | // 配置页路由地址
16 | // 组件关键词
17 | const PhotoWidgetDefine = new Widget({
18 | previewImage: '/images/preview_photo.png',
19 | path,
20 | name,
21 | title,
22 | disabled: true,
23 | description,
24 | keywords,
25 | lang: 'zh-CN',
26 | width: 2,
27 | categories: ['photo'],
28 | socialLinks: [
29 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
30 | ],
31 | height: 2,
32 | minWidth: 1,
33 | maxWidth: 6,
34 | minHeight: 1,
35 | maxHeight: 6,
36 | configPagePath: '/widget/config/photo?frame=true&transparent=false',
37 | })
38 |
39 | export default PhotoWidgetDefine
40 |
--------------------------------------------------------------------------------
/src/widgets/photo/PhotoConfigView.vue:
--------------------------------------------------------------------------------
1 |
63 |
64 |
65 |
72 |
73 |
74 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/widgets/photo/PhotoWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import PhotoWidgetDefine from './Photo.widget'
3 |
4 | const url = PhotoWidgetDefine.path
5 | const name = PhotoWidgetDefine.name
6 |
7 | const configUrl = PhotoWidgetDefine.configPagePath!.split('?')[0]
8 |
9 | const PhotoWidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.photo" */ './PhotoWidgetView.vue'),
14 | },
15 | {
16 | path: configUrl!,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.photo.config" */ './PhotoConfigView.vue'),
19 | },
20 | ]
21 |
22 | export default PhotoWidgetRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/photo/PhotoWidgetView.vue:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
52 |
53 |
54 |
59 |
60 |
61 |
62 |
63 |
64 | 点击设置图片文件
65 |
66 |
67 |
68 |
69 | 文件夹内没有找到图片
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
108 |
--------------------------------------------------------------------------------
/src/widgets/photo/assets/photo1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/photo/assets/photo1.jpg
--------------------------------------------------------------------------------
/src/widgets/photo/assets/photo2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/photo/assets/photo2.jpg
--------------------------------------------------------------------------------
/src/widgets/photo/assets/photo3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/widget-js/widgets/396da26cf98b836b00cb780f646f810a9803c172/src/widgets/photo/assets/photo3.jpg
--------------------------------------------------------------------------------
/src/widgets/photo/model/PhotoData.ts:
--------------------------------------------------------------------------------
1 | import { WidgetData } from '@widget-js/core'
2 |
3 | export class PhotoData extends WidgetData {
4 | directory = ''
5 | /**
6 | * 轮播时长,单位毫秒
7 | */
8 | duration = 5000
9 | random = false
10 |
11 | constructor(name: string, id?: string) {
12 | super(name, id)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/BreakView.vue:
--------------------------------------------------------------------------------
1 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
按Esc退出
47 |
48 |
49 |
50 |
87 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/SitReminder.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BackgroundWidget,
3 | DeployMode,
4 | WidgetKeyword,
5 | } from '@widget-js/core'
6 |
7 | const name = 'cn.widgetjs.widgets.sit_reminder'
8 | // 组件标题
9 | const title = { 'zh-CN': '久坐提醒' }
10 | // 组件描述
11 | const description = { 'zh-CN': '设置间隔,定时提醒,适合长期久坐的人群' }
12 | // 组件关键词
13 | const keywords = [WidgetKeyword.RECOMMEND]
14 | // 组件路由地址
15 | const url = '/widget/sit_reminder'
16 | // 组件关键词
17 | const SitReminderWidgetDefine = new BackgroundWidget({
18 | name,
19 | title,
20 | description,
21 | socialLinks: [
22 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
23 | ],
24 | keywords,
25 | lang: 'zh-CN',
26 | categories: ['utilities'],
27 | previewImage: '/images/preview_sit_reminder.png',
28 | supportDeployMode: DeployMode.BACKGROUND,
29 | path: url,
30 | configPagePath: '/widget/config/sit_reminder?frame=true&transparent=false',
31 | })
32 |
33 | export default SitReminderWidgetDefine
34 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/SitReminderConfigView.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
33 |
34 |
35 |
36 |
37 |
38 | 检测阈值:多久没使用鼠标视为离开电脑
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/SitReminderWidget.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/SitReminderWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import SitReminderWidgetDefine from './SitReminder.widget'
3 |
4 | const url = SitReminderWidgetDefine.path
5 | const name = SitReminderWidgetDefine.name
6 |
7 | const configUrl = SitReminderWidgetDefine.configPagePath!.split('?')[0]
8 |
9 | const SitReminderWidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.sit_reminder" */ './SitReminderWidget.vue'),
14 | },
15 | {
16 | path: configUrl!,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.sit_reminder.config" */ './SitReminderConfigView.vue'),
19 | },
20 | {
21 | path: '/widget/sit_reminder/break',
22 | name: `${name}.break`,
23 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.dynamic_island.break" */ './BreakView.vue'),
24 | },
25 | ]
26 |
27 | export default SitReminderWidgetRoutes
28 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/TextSwitcher.vue:
--------------------------------------------------------------------------------
1 |
108 |
109 |
110 |
111 |
112 | {{ text1 }}
113 | {{ text1 }}
114 | {{ text2 }}
115 |
116 |
117 |
118 |
129 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/composition/use-sit-reminder.ts:
--------------------------------------------------------------------------------
1 | import { useWidgetData } from '@widget-js/vue3'
2 | import dayjs from 'dayjs'
3 | import duration from 'dayjs/plugin/duration'
4 | import {
5 | BrowserWindowApi,
6 | DeviceApi,
7 | NotificationApi,
8 | WidgetApiEvent,
9 | WidgetPackageApi,
10 | } from '@widget-js/core'
11 | import {
12 | useIntervalFn,
13 | useStorage,
14 | } from '@vueuse/core'
15 | import { onMounted } from 'vue'
16 | import { SitReminder } from '@/widgets/sit-reminder/model/SitReminder'
17 |
18 | dayjs.extend(duration)
19 |
20 | /**
21 | * 久坐提醒
22 | */
23 | function useSitReminder() {
24 | const sitReminder = new SitReminder()
25 | const cancelBroadcast = `${sitReminder.name}.cancel`
26 | const confirmBroadcast = `${sitReminder.name}.confirm`
27 | let breakUrl = ''
28 | const loadBreakUrl = async (minute: number) => {
29 | const url = await WidgetPackageApi.getEntryUrl('cn.widgetjs.widgets')
30 | breakUrl = `${url}#/widget/sit_reminder/break?win_fullscreen=true&win_always_on_top=true&duration=${minute * 60}`
31 | }
32 | const { widgetData: sitReminderData } = useWidgetData(SitReminder, {
33 | defaultData: sitReminder,
34 | loadDataByWidgetName: true,
35 | widgetName: sitReminder.name,
36 | useBroadcastEvent: [cancelBroadcast, confirmBroadcast, WidgetApiEvent.DATA_CHANGED],
37 | onBroadcastEvent: async (broadcastEvent) => {
38 | if (broadcastEvent.event == confirmBroadcast) {
39 | await BrowserWindowApi.openUrl(breakUrl)
40 | }
41 | },
42 | onDataLoaded() {
43 | loadBreakUrl(sitReminderData.value.breakInterval)
44 | },
45 | })
46 |
47 | const lastUsedAtData = useStorage(`${sitReminder.name}.last_used_at`, dayjs().toISOString())
48 | const usageCount = useStorage(`${sitReminder.name}.usage_count`, 0)
49 | let lastUsedAt = dayjs(lastUsedAtData.value)
50 | const interval = 10
51 | let lastPoint = {
52 | x: 0,
53 | y: 0,
54 | }
55 |
56 | onMounted(() => {
57 | BrowserWindowApi.hide()
58 | })
59 |
60 | useIntervalFn(async () => {
61 | const now = dayjs()
62 |
63 | const duration = dayjs.duration(now.diff(lastUsedAt))
64 | if (duration.asSeconds() > sitReminderData.value.mouseCheckInterval * 60 + interval) {
65 | usageCount.value = 0
66 | }
67 | else {
68 | usageCount.value = usageCount.value + interval
69 | if (usageCount.value < 20 && (await BrowserWindowApi.existsByUrl(breakUrl))) {
70 | usageCount.value = 0
71 | }
72 | }
73 | const point = await DeviceApi.getCursorScreenPoint()
74 | if (point.x != lastPoint.x || point.y != lastPoint.y) {
75 | lastPoint = point
76 | lastUsedAt = now
77 | }
78 | // sitReminderData.value.sitInterval * 60
79 | if (usageCount.value >= sitReminderData.value.sitInterval * 60) {
80 | await NotificationApi.reminder({
81 | title: '久坐提醒',
82 | message: `您已经连续使用电脑${sitReminderData.value.sitInterval}分钟`,
83 | icon: 'computer_line',
84 | confirmButtonText: '休息一下',
85 | cancelButtonText: '知道了',
86 | cancelBroadcast,
87 | confirmBroadcast,
88 | duration: 10000,
89 | })
90 | usageCount.value = 0
91 | }
92 | }, interval * 1000)
93 | }
94 |
95 | export default useSitReminder
96 |
--------------------------------------------------------------------------------
/src/widgets/sit-reminder/model/SitReminder.ts:
--------------------------------------------------------------------------------
1 | import { WidgetData } from '@widget-js/core'
2 | import SitReminderWidgetDefine from '@/widgets/sit-reminder/SitReminder.widget'
3 |
4 | export class SitReminder extends WidgetData {
5 | breakInterval = 5
6 | sitInterval = 30
7 | mouseCheckInterval = 5
8 | name = SitReminderWidgetDefine.name
9 |
10 | constructor() {
11 | super(SitReminderWidgetDefine.name)
12 | }
13 |
14 | getThemeProperties(): Record {
15 | return super.getThemeProperties()
16 | }
17 |
18 | injectThemeProperties() {
19 | super.injectThemeProperties()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/widgets/time-progress/TimeProgress.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const name = 'cn.widgetjs.widgets.time_progress'
7 | const title = { 'zh-CN': '时间进度' }
8 | // 组件标题
9 | const description = { 'zh-CN': '年、月、周、日进度剩余百分比' }
10 | const keywords = [WidgetKeyword.RECOMMEND]
11 | const lang = 'zh-CN'
12 | const TimeProgressWidgetDefine = new Widget({
13 | name,
14 | title,
15 | description,
16 | keywords,
17 | categories: ['time'],
18 | lang,
19 | width: 4,
20 | socialLinks: [
21 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
22 | ],
23 | height: 2,
24 | configPagePath: '/widget/config/time_progress?frame=true&transparent=false&width=600&height=400',
25 | previewImage: '/images/preview_time_progress.png',
26 | path: '/widget/time_progress',
27 | })
28 | export default TimeProgressWidgetDefine
29 |
--------------------------------------------------------------------------------
/src/widgets/time-progress/TimeProgressConfig.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/widgets/time-progress/TimeProgressRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import TimeProgressWidgetDefine from '@/widgets/time-progress/TimeProgress.widget'
3 |
4 | const url = TimeProgressWidgetDefine.path
5 | const name = TimeProgressWidgetDefine.name
6 |
7 | const configUrl = TimeProgressWidgetDefine.configPagePath!.split('?')[0]
8 |
9 | const TimeProgressWidgetDefineRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.time_progress" */ './TimeProgressWidgetView.vue'),
14 | },
15 | {
16 | path: configUrl!,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.time_progress.config" */ './TimeProgressConfig.vue'),
19 | },
20 | ]
21 |
22 | export default TimeProgressWidgetDefineRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/time-progress/images/time_progress_decorate.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/TodoList.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const TodoListWidget = new Widget({
7 | name: 'cn.widgetjs.widgets.todo_list',
8 | title: { 'zh-CN': '待办事项' },
9 | description: { 'zh-CN': 'TODO待办事项' },
10 | keywords: [WidgetKeyword.RECOMMEND],
11 | lang: 'zh-CN',
12 | previewImage: '/images/preview_todo_list.png',
13 | width: 4,
14 | height: 4,
15 | minWidth: 3,
16 | maxWidth: 8,
17 | disabled: true,
18 | categories: ['productivity'],
19 | minHeight: 3,
20 | socialLinks: [
21 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
22 | ],
23 | maxHeight: 10,
24 | path: '/widget/todo_list',
25 | configPagePath: '/widget/config/todo_list?frame=true&transparent=false&width=600&height=500',
26 | })
27 |
28 | export default TodoListWidget
29 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/TodoListConfigView.vue:
--------------------------------------------------------------------------------
1 |
51 |
52 |
53 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/TodoListWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import TodoListWidget from './TodoList.widget'
3 |
4 | const url = TodoListWidget.path
5 | const name = TodoListWidget.name
6 |
7 | const configUrl = TodoListWidget.configPagePath!.split('?')[0]
8 |
9 | const TodoListWidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.todo_list" */ './TodoListWidgetView.vue'),
14 | },
15 | {
16 | path: configUrl!,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.todo_list.config" */ './TodoListConfigView.vue'),
19 | },
20 | ]
21 |
22 | export default TodoListWidgetRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/WidgetBackground.vue:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
31 |
32 |
33 |
79 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/components/EditBox.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
39 |
40 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | 取消
60 |
61 |
62 | 保存
63 |
64 |
65 |
66 |
67 |
68 |
69 |
88 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/components/FinishedTodoList.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/components/TodoItem.vue:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | {{ todo.title }}
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
100 |
--------------------------------------------------------------------------------
/src/widgets/todo-list/components/TodoList.vue:
--------------------------------------------------------------------------------
1 |
36 |
37 |
38 |
49 |
50 |
51 |
59 |
--------------------------------------------------------------------------------
/src/widgets/water-reminder/WaterReminder.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | // TODO 修改组件信息,标题,描述,关键词
7 | const name = 'cn.widgetjs.widgets.water_reminder'
8 | // 组件标题
9 | const title = { 'zh-CN': '喝水提醒' }
10 | // 组件描述
11 | const description = { 'zh-CN': '每天N杯水,养成好习惯' }
12 | // 组件关键词
13 | const keywords = [WidgetKeyword.RECOMMEND]
14 | // 组件路由地址
15 | const url = '/widget/water_reminder'
16 | // 组件关键词
17 | const WaterReminderWidget = new Widget({
18 | name,
19 | title,
20 | description,
21 | keywords,
22 | disabled: true,
23 | lang: 'zh-CN',
24 | previewImage: '/images/preview_water_reminder.png',
25 | width: 2,
26 | categories: ['utilities'],
27 | height: 2,
28 | backgroundThrottling: false,
29 | minWidth: 2,
30 | socialLinks: [
31 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
32 | ],
33 | maxWidth: 2,
34 | minHeight: 2,
35 | maxHeight: 2,
36 | path: url,
37 | configPagePath: '/widget/config/water_reminder?frame=true&transparent=false',
38 | })
39 |
40 | export default WaterReminderWidget
41 |
--------------------------------------------------------------------------------
/src/widgets/water-reminder/WaterReminderConfigView.vue:
--------------------------------------------------------------------------------
1 |
46 |
47 |
48 |
56 |
57 |
58 |
59 |
60 |
61 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/widgets/water-reminder/WaterReminderWidgetRoutes.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import WaterReminderWidget from './WaterReminder.widget'
3 |
4 | const url = WaterReminderWidget.path
5 | const name = WaterReminderWidget.name
6 |
7 | const configUrl = WaterReminderWidget.configPagePath!.split('?')[0]
8 |
9 | const WaterReminderWidgetRoutes: RouteRecordRaw[] = [
10 | {
11 | path: url,
12 | name: `${name}`,
13 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.water_reminder" */ './WaterReminderWidgetView.vue'),
14 | },
15 | {
16 | path: configUrl!,
17 | name: `${name}.config`,
18 | component: () => import(/* webpackChunkName: "com.wisdom.widgets.water_reminder.config" */ './WaterReminderConfigView.vue'),
19 | },
20 | ]
21 |
22 | export default WaterReminderWidgetRoutes
23 |
--------------------------------------------------------------------------------
/src/widgets/water-reminder/WaterReminderWidgetView.vue:
--------------------------------------------------------------------------------
1 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
113 |
--------------------------------------------------------------------------------
/src/widgets/water-reminder/model/WaterReminderModel.ts:
--------------------------------------------------------------------------------
1 | import { WidgetData } from '@widget-js/core'
2 | import dayjs from 'dayjs'
3 | import WaterReminderWidget from '@/widgets/water-reminder/WaterReminder.widget'
4 |
5 | export class WaterReminderModel extends WidgetData {
6 | targetCup = 8
7 | /**
8 | * 提醒间隔
9 | */
10 | interval = 30
11 | history: Record = {}
12 | lastReminderAt: string = dayjs().toISOString()
13 | enableReminder = true
14 |
15 | constructor(id?: string) {
16 | super(WaterReminderWidget.name, id)
17 | }
18 |
19 | getTodayKey(): string {
20 | return dayjs().format('YYYY/MM/DD')
21 | }
22 |
23 | getTodayHistory(): number {
24 | const history = this.history[this.getTodayKey()]
25 | if (history) {
26 | return history
27 | }
28 |
29 | return 0
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/widgets/water-reminder/model/WaveBall.ts:
--------------------------------------------------------------------------------
1 | export class WaveBall {
2 | x = 0 // x轴坐标
3 | y = 0 // y轴坐标
4 | size: number // 大小(直径)
5 | color: string // 颜色
6 | bgColor?: CanvasGradient // 颜色
7 | waveWidth = 0.025 // 波频
8 | waveHeight = 5.6 // 震幅
9 | progress = 0 // 进度
10 | offsetX = [0, 0] // 偏移位置
11 | startX = 0 // 初始位置
12 | vx = [0.05, 0.01] // x轴增加量
13 | ctx: CanvasRenderingContext2D | undefined
14 |
15 | constructor(options: WaveBallOption) {
16 | this.size = options.size ?? 200
17 | this.x = options.x ?? this.size / 2
18 | this.y = options.y ?? this.size / 2
19 | this.progress = options.progress ?? 0
20 | this.color = options.color ?? 'rgba(55, 133, 207, .75)'
21 | return this
22 | }
23 |
24 | render(ctx: CanvasRenderingContext2D) {
25 | this.ctx = ctx
26 | const {
27 | color,
28 | size,
29 | } = this
30 | this.bgColor = ctx.createLinearGradient(size / 2, size / 2, size / 2, size)
31 | this.bgColor!.addColorStop(0, color)
32 | this.bgColor!.addColorStop(1, color)
33 | this.drawBall()
34 | this.drawWave()
35 | return this
36 | }
37 |
38 | drawBall() {
39 | // const {size, ctx, x, y, color} = this;
40 | // ctx!.save();
41 | // ctx!.lineWidth = 4;
42 | // ctx!.strokeStyle = color;
43 | // ctx!.beginPath();
44 | // ctx!.arc(x, y, size / 2, 0, 2 * Math.PI);
45 | // ctx!.stroke();
46 | // ctx!.restore();
47 | }
48 |
49 | drawWave(n = 0) {
50 | this.offsetX[n] += this.vx[n]
51 | const {
52 | startX,
53 | size,
54 | ctx,
55 | offsetX,
56 | x,
57 | y,
58 | bgColor,
59 | waveWidth,
60 | waveHeight,
61 | progress,
62 | } = this
63 | const height = -progress / 100 * size
64 | ctx!.save()
65 | ctx!.translate(x, y)
66 | ctx!.beginPath()
67 | ctx!.arc(0, 0, size / 2, 0, 2 * Math.PI)
68 | ctx!.clip()
69 | ctx!.beginPath()
70 | for (let i = -size / 2; i < size / 2; i++) {
71 | const h = waveHeight * Math.sin((startX + i) * waveWidth + offsetX[n])
72 | ctx!.lineTo(i, h + size / 2 + height)
73 | }
74 | ctx!.lineTo(size / 2, size / 2)
75 | ctx!.lineTo(-size / 2, size / 2)
76 | ctx!.fillStyle = bgColor!
77 | ctx!.fill()
78 | ctx!.restore()
79 | }
80 |
81 | update(progress?: number) {
82 | if (progress != undefined) {
83 | this.progress = progress
84 | }
85 |
86 | this.drawWave(0)
87 | this.drawWave(1)
88 | this.drawBall()
89 | }
90 | }
91 |
92 | interface WaveBallOption {
93 | /**
94 | * x轴坐标
95 | */
96 | x?: number
97 |
98 | /**
99 | * y轴坐标
100 | */
101 | y?: number
102 | /**
103 | * 大小(
104 | */
105 | size?: number
106 | /**
107 | * 颜色
108 | */
109 | color?: string
110 |
111 | /**
112 | * 波频
113 | */
114 | waveWidth?: number
115 | /**
116 | * 震幅
117 | */
118 | waveHeight?: number
119 | /**
120 | * 进度
121 | */
122 | progress?: number
123 | }
124 |
--------------------------------------------------------------------------------
/src/widgets/wave-progress/WaveProgress.widget.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Widget,
3 | WidgetKeyword,
4 | } from '@widget-js/core'
5 |
6 | const name = 'cn.widgetjs.widgets.wave_progress'
7 | const title = { 'zh-CN': '波浪进度' }
8 | // 组件标题
9 | const description = { 'zh-CN': '用波浪显示事件进度' }
10 | // 组件描述
11 | // 组件关键词
12 | const keywords = [WidgetKeyword.RECOMMEND]
13 | const lang = 'zh-CN'
14 | const path = '/widget/wave_progress'
15 | const width = 1
16 | const height = 2
17 | const minWidth = 1
18 | const maxWidth = 3
19 | const minHeight = 2
20 | const maxHeight = 7
21 | const WaveProgressWidgetDefine = new Widget({
22 | path,
23 | configPagePath: '/widget/config/wave_progress?frame=true&transparent=false&width=600&height=390',
24 | name,
25 | title,
26 | categories: ['time'],
27 | description,
28 | keywords,
29 | lang,
30 | width,
31 | height,
32 | maxWidth,
33 | maxHeight,
34 | minWidth,
35 | minHeight,
36 | socialLinks: [
37 | { name: 'github', link: 'https://github.com/widget-js/widgets' },
38 | ],
39 | previewImage: '/images/preview_wave_progress.png',
40 | })
41 | export default WaveProgressWidgetDefine
42 |
--------------------------------------------------------------------------------
/src/widgets/wave-progress/WaveProgressRoute.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import WaveProgressWidgetDefine from '@/widgets/wave-progress/WaveProgress.widget'
3 |
4 | const WaveProgressRoute: RouteRecordRaw[] = [
5 | {
6 | path: WaveProgressWidgetDefine.path,
7 | name: `${WaveProgressWidgetDefine.name}`,
8 | component: () => import(/* webpackChunkName: "cn.widgetjs.widgets.wave_progress" */ './WaveProgressWidgetView.vue'),
9 | },
10 | {
11 | path: WaveProgressWidgetDefine.configPagePath!.split('?')[0],
12 | name: `${WaveProgressWidgetDefine.name}.config`,
13 | component: () => import(/* webpackChunkName: "cn.widgetjs.widgets.wave_progress.config" */ './WaveProgressConfigView.vue'),
14 | },
15 | ]
16 |
17 | export default WaveProgressRoute
18 |
--------------------------------------------------------------------------------
/src/widgets/wave-progress/WaveProgressWidgetView.vue:
--------------------------------------------------------------------------------
1 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
--------------------------------------------------------------------------------
/src/widgets/wave-progress/model/WaveProgressData.ts:
--------------------------------------------------------------------------------
1 | export enum ProgressType {
2 | today = 0,
3 | toWeek = 1,
4 | toMonth = 2,
5 | toYear = 3,
6 | custom = 4,
7 | }
8 |
9 | export interface WaveProgressData {
10 | // 类型
11 | progressType: ProgressType
12 |
13 | // 事件名称
14 | eventName: string
15 |
16 | startDate?: string
17 |
18 | endDate?: string
19 | }
20 |
21 | export const DefaultWaveProgressData: WaveProgressData = {
22 | progressType: ProgressType.today,
23 | eventName: '今天',
24 | startDate: new Date().toISOString(),
25 | endDate: new Date().toISOString(),
26 | }
27 |
--------------------------------------------------------------------------------
/src/widgets/widget-router.ts:
--------------------------------------------------------------------------------
1 | import type { RouteRecordRaw } from 'vue-router'
2 | import TodoListWidgetRoutes from './todo-list/TodoListWidgetRoutes'
3 | import CountdownWidgetRoutes from './countdown/CountdownWidgetRoutes'
4 | import Countdown2WidgetRoutes from './countdown2/Countdown2WidgetRoutes'
5 | import PhoneReminderWidgetRoutes from './phone-reminder/PhoneReminderWidgetRoutes'
6 | import WaterReminderWidgetRoutes from './water-reminder/WaterReminderWidgetRoutes'
7 | import KeyStrokeWidgetRoutes from './key-stroke/KeyStrokeWidgetRoutes'
8 | import PhotoWidgetRoutes from './photo/PhotoWidgetRoutes'
9 | import SitReminderWidgetRoutes from './sit-reminder/SitReminderWidgetRoutes'
10 | import DynamicIslandWidgetRoutes from '@/widgets/dynamic-island/DynamicIslandWidgetRoutes'
11 | import BirthdayListWidgetRoutes from '@/widgets/birthday-list/BirthdayListWidgetRoutes'
12 | import LaborProgressWidgetRoutes from '@/widgets/labor-progress/LaborProgressRoutes'
13 | import WaveProgressRoute from '@/widgets/wave-progress/WaveProgressRoute'
14 | import TimeProgressWidgetRoutes from '@/widgets/time-progress/TimeProgressRoutes'
15 |
16 | // FBI WANING! IMPORT PLACE, DONT DELETE THIS LINE
17 |
18 | const WidgetRouter: RouteRecordRaw[] = [
19 | ...LaborProgressWidgetRoutes,
20 | ...WaveProgressRoute,
21 | ...TimeProgressWidgetRoutes,
22 | ...BirthdayListWidgetRoutes,
23 | ...DynamicIslandWidgetRoutes,
24 | ...TodoListWidgetRoutes,
25 | ...CountdownWidgetRoutes,
26 | ...Countdown2WidgetRoutes,
27 | ...PhoneReminderWidgetRoutes,
28 | ...WaterReminderWidgetRoutes,
29 | ...KeyStrokeWidgetRoutes,
30 | // ...CollectionWidgetRoutes,
31 | ...PhotoWidgetRoutes,
32 | ...SitReminderWidgetRoutes,
33 | // FBI WANING! ROUTE PLACE, DONT DELETE THIS LINE
34 | ]
35 | export default WidgetRouter
36 |
--------------------------------------------------------------------------------
/test/dayjs.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from 'vitest'
2 | import dayjs from 'dayjs'
3 | import { Solar } from 'lunar-typescript'
4 |
5 | describe('dayjs', () => {
6 | it('isValid', () => {
7 | const time = dayjs('08:44', 'HH:mm')
8 | expect(time.isValid()).toBeFalsy()
9 | const date = dayjs('1996-08-17 08:44', 'YYYY-MM-DD HH:mm')
10 | expect(date.isValid()).toBeTruthy()
11 |
12 | console.log(Solar.fromDate(date.toDate()).toFullString())
13 | })
14 | })
15 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "jsx": "preserve",
5 | "lib": [
6 | "esnext",
7 | "dom",
8 | "dom.iterable",
9 | "scripthost"
10 | ],
11 | "useDefineForClassFields": true,
12 | "emitDecoratorMetadata": true,
13 | "experimentalDecorators": true,
14 | "baseUrl": ".",
15 | "module": "commonjs",
16 | "moduleResolution": "node",
17 | "paths": {
18 | "@/*": [
19 | "src/*"
20 | ]
21 | },
22 | "resolveJsonModule": true,
23 | "types": [
24 | "element-plus/global",
25 | "vue"
26 | ],
27 | "strict": true,
28 | "noImplicitAny": false,
29 | "noImplicitThis": false,
30 | "noEmit": true,
31 | "removeComments": true,
32 | "sourceMap": true,
33 | "allowSyntheticDefaultImports": true,
34 | "esModuleInterop": true,
35 | "forceConsistentCasingInFileNames": true,
36 | "isolatedModules": true,
37 | "skipLibCheck": true
38 | },
39 | "references": [
40 | {
41 | "path": "./tsconfig.node.json"
42 | }
43 | ],
44 | "include": [
45 | "src/**/*.ts",
46 | "src/**/*.tsx",
47 | "src/**/*.vue",
48 | "src/**/*.widget.ts",
49 | "src/**/*.stories.ts",
50 | "tests/**/*.ts",
51 | "tests/**/*.tsx",
52 | "auto-imports.d.ts"
53 | ],
54 | "exclude": [
55 | "node_modules"
56 | ]
57 | }
58 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "target": "ESNext",
5 | "module": "ESNext",
6 | "moduleResolution": "Node",
7 | "allowSyntheticDefaultImports": true
8 | },
9 | "include": [
10 | "vite.config.ts",
11 | "script/*.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/uno.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'unocss'
2 |
3 | export default defineConfig({
4 | })
5 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 | import { defineConfig } from 'vite'
3 | import vue from '@vitejs/plugin-vue'
4 | import AutoImport from 'unplugin-auto-import/vite'
5 | import Components from 'unplugin-vue-components/vite'
6 | import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
7 | import widget from '@widget-js/vite-plugin-widget'
8 | import checker from 'vite-plugin-checker'
9 | import UnoCSS from 'unocss/vite'
10 |
11 | export default defineConfig({
12 | base: './',
13 | server: { port: 8085 },
14 | build: {
15 | rollupOptions: {
16 | output: {
17 | entryFileNames: 'assets/[name].js',
18 | chunkFileNames: 'assets/[name].js',
19 | assetFileNames: 'assets/[name].[ext]',
20 | },
21 | },
22 | },
23 | plugins: [vue(), UnoCSS(), widget(), checker({ typescript: true }), AutoImport({ resolvers: [ElementPlusResolver()] }), Components({ resolvers: [ElementPlusResolver()] })],
24 | resolve: {
25 | alias: [{
26 | find: '@',
27 | replacement: path.resolve(__dirname, 'src'),
28 | }],
29 | },
30 | })
31 |
--------------------------------------------------------------------------------
/widget.package.ts:
--------------------------------------------------------------------------------
1 | import { WidgetPackage } from '@widget-js/core'
2 |
3 | export default new WidgetPackage({
4 | name: 'cn.widgetjs.widgets',
5 | author: 'Widget JS',
6 | homepage: 'https://widgetjs.cn',
7 | description: { 'zh-CN': '内置基础组件' },
8 | entry: 'index.html',
9 | title: { 'zh-CN': '内置基础组件' },
10 | version: '0.0.1',
11 | hash: true,
12 | devOptions: {
13 | folder: './src/widgets/',
14 | route: true,
15 | devUrl: 'http://localhost:5174',
16 | },
17 | widgets: [],
18 | permissions: [],
19 | })
20 |
--------------------------------------------------------------------------------