From 3f595978644195781452d4d07379f2552ffdfd7d Mon Sep 17 00:00:00 2001 From: Joel Jacob Stephen <70131076+JoelJacobStephen@users.noreply.github.com> Date: Tue, 28 Feb 2023 13:13:27 +0530 Subject: [PATCH] feat: introducing self hosted admin dashboard package (#12) Co-authored-by: Andrew Bastin Co-authored-by: Anwarul Islam --- packages/hoppscotch-cli/README.md | 19 +- packages/hoppscotch-common/package.json | 2 +- packages/hoppscotch-common/src/App.vue | 2 +- .../hoppscotch-common/src/components.d.ts | 12 - .../src/components/app/DeveloperOptions.vue | 6 +- .../src/components/app/Footer.vue | 42 +- .../src/components/app/Header.vue | 18 +- .../src/components/app/Interceptor.vue | 9 +- .../src/components/app/Options.vue | 28 +- .../src/components/app/PowerSearch.vue | 4 +- .../src/components/app/Share.vue | 4 +- .../src/components/app/Shortcuts.vue | 4 +- .../src/components/app/ShortcutsPrompt.vue | 2 +- .../src/components/app/Sidenav.vue | 4 +- .../src/components/app/Support.vue | 18 +- .../src/components/collections/Add.vue | 8 +- .../src/components/collections/AddFolder.vue | 8 +- .../src/components/collections/AddRequest.vue | 8 +- .../src/components/collections/Collection.vue | 16 +- .../src/components/collections/Edit.vue | 8 +- .../src/components/collections/EditFolder.vue | 8 +- .../components/collections/EditRequest.vue | 8 +- .../components/collections/ImportExport.vue | 18 +- .../components/collections/MyCollections.vue | 10 +- .../src/components/collections/Request.vue | 10 +- .../components/collections/SaveRequest.vue | 8 +- .../collections/TeamCollections.vue | 16 +- .../src/components/collections/TeamSelect.vue | 16 +- .../components/collections/graphql/Add.vue | 8 +- .../collections/graphql/AddFolder.vue | 12 +- .../collections/graphql/AddRequest.vue | 12 +- .../collections/graphql/Collection.vue | 18 +- .../components/collections/graphql/Edit.vue | 8 +- .../collections/graphql/EditFolder.vue | 8 +- .../collections/graphql/EditRequest.vue | 8 +- .../components/collections/graphql/Folder.vue | 16 +- .../collections/graphql/ImportExport.vue | 14 +- .../collections/graphql/Request.vue | 12 +- .../components/collections/graphql/index.vue | 8 +- .../src/components/collections/index.vue | 14 +- .../components/environments/ChooseType.vue | 20 +- .../components/environments/ImportExport.vue | 16 +- .../src/components/environments/index.vue | 18 +- .../components/environments/my/Details.vue | 16 +- .../environments/my/Environment.vue | 18 +- .../src/components/environments/my/index.vue | 8 +- .../components/environments/teams/Details.vue | 18 +- .../environments/teams/Environment.vue | 18 +- .../components/environments/teams/index.vue | 16 +- .../src/components/firebase/Login.vue | 24 +- .../src/components/firebase/Logout.vue | 4 +- .../src/components/graphql/Authorization.vue | 37 +- .../src/components/graphql/Request.vue | 2 +- .../src/components/graphql/RequestOptions.vue | 66 +- .../src/components/graphql/Response.vue | 8 +- .../src/components/graphql/Sidebar.vue | 54 +- .../src/components/history/graphql/Card.vue | 6 +- .../src/components/history/index.vue | 16 +- .../src/components/history/rest/Card.vue | 4 +- .../src/components/http/Authorization.vue | 37 +- .../src/components/http/Body.vue | 10 +- .../src/components/http/BodyParameters.vue | 20 +- .../src/components/http/CodegenModal.vue | 18 +- .../src/components/http/Headers.vue | 30 +- .../src/components/http/ImportCurl.vue | 18 +- .../components/http/OAuth2Authorization.vue | 2 +- .../src/components/http/Parameters.vue | 20 +- .../src/components/http/PreRequestScript.vue | 8 +- .../src/components/http/RawBody.vue | 10 +- .../components/http/ReqChangeConfirmModal.vue | 10 +- .../src/components/http/Request.vue | 29 +- .../src/components/http/RequestOptions.vue | 28 +- .../src/components/http/ResponseMeta.vue | 2 +- .../src/components/http/Sidebar.vue | 20 +- .../src/components/http/TestResult.vue | 8 +- .../src/components/http/TestResultReport.vue | 2 +- .../src/components/http/Tests.vue | 8 +- .../src/components/http/URLEncodedParams.vue | 20 +- .../src/components/lenses/HeadersRenderer.vue | 2 +- .../lenses/HeadersRendererEntry.vue | 2 +- .../lenses/ResponseBodyRenderer.vue | 16 +- .../lenses/renderers/HTMLLensRenderer.vue | 8 +- .../lenses/renderers/ImageLensRenderer.vue | 2 +- .../lenses/renderers/JSONLensRenderer.vue | 18 +- .../lenses/renderers/PDFLensRenderer.vue | 2 +- .../lenses/renderers/RawLensRenderer.vue | 6 +- .../lenses/renderers/XMLLensRenderer.vue | 6 +- .../src/components/profile/Shortcode.vue | 6 +- .../src/components/profile/Shortcodes.vue | 8 +- .../src/components/profile/UserDelete.vue | 12 +- .../src/components/realtime/Communication.vue | 20 +- .../components/realtime/ConnectionConfig.vue | 12 +- .../src/components/realtime/Log.vue | 8 +- .../src/components/realtime/LogEntry.vue | 26 +- .../src/components/realtime/Subscription.vue | 12 +- .../src/components/smart/AccentModePicker.vue | 2 +- .../src/components/smart/ChangeLanguage.vue | 8 +- .../src/components/smart/ColorModePicker.vue | 2 +- .../src/components/smart/FontSizePicker.vue | 4 +- .../src/components/smart/Tree.vue | 2 +- .../src/components/smart/TreeBranch.vue | 2 +- .../src/components/tab/Primary.vue | 4 +- .../src/components/tab/Secondary.vue | 4 +- .../src/components/teams/Add.vue | 8 +- .../src/components/teams/Edit.vue | 22 +- .../src/components/teams/Invite.vue | 39 +- .../src/components/teams/Modal.vue | 4 +- .../src/components/teams/Team.vue | 16 +- .../src/components/teams/index.vue | 6 +- .../src/composables/settings.ts | 14 +- .../src/helpers/fb/collections.ts | 2 + .../src/helpers/fb/settings.ts | 4 +- .../helpers/strategies/ExtensionStrategy.ts | 2 +- packages/hoppscotch-common/src/modules/ui.ts | 5 +- .../src/newstore/DispatchingStore.ts | 25 +- .../src/newstore/RESTSession.ts | 10 +- .../src/newstore/SocketIOSession.ts | 2 +- .../src/newstore/WebSocketSession.ts | 2 +- .../src/newstore/collections.ts | 10 +- .../src/newstore/environments.ts | 3 +- .../hoppscotch-common/src/newstore/history.ts | 6 +- .../src/newstore/localstate.ts | 12 +- .../src/newstore/settings.ts | 48 +- packages/hoppscotch-common/src/pages/_.vue | 9 +- .../hoppscotch-common/src/pages/enter.vue | 2 +- .../hoppscotch-common/src/pages/join-team.vue | 12 +- .../hoppscotch-common/src/pages/profile.vue | 36 +- .../hoppscotch-common/src/pages/r/_id.vue | 6 +- .../hoppscotch-common/src/pages/realtime.vue | 8 +- .../src/pages/realtime/mqtt.vue | 18 +- .../src/pages/realtime/socketio.vue | 37 +- .../src/pages/realtime/sse.vue | 2 +- .../src/pages/realtime/websocket.vue | 26 +- .../hoppscotch-common/src/pages/settings.vue | 42 +- packages/hoppscotch-common/src/shims.d.ts | 12 +- packages/hoppscotch-common/tsconfig.json | 2 +- packages/hoppscotch-sh-admin/.gitignore | 30 + .../assets/scss/styles.scss | 570 ++++ .../assets/scss/themes.scss | 307 +++ packages/hoppscotch-sh-admin/gql-codegen.yml | 13 + packages/hoppscotch-sh-admin/index.html | 17 + packages/hoppscotch-sh-admin/package.json | 57 + packages/hoppscotch-sh-admin/public/cover.jpg | Bin 0 -> 41798 bytes .../hoppscotch-sh-admin/public/favicon.ico | Bin 0 -> 4286 bytes packages/hoppscotch-sh-admin/public/vite.svg | 1 + packages/hoppscotch-sh-admin/src/App.vue | 28 + .../hoppscotch-sh-admin/src/components.d.ts | 52 + .../src/components/app/Header.vue | 92 + .../src/components/app/Modal.vue | 89 + .../src/components/app/Sidebar.vue | 100 + .../src/components/teams/AddMembers.vue | 83 + .../src/composables/useSidebar.ts | 13 + .../gql/queries/GetCollectionChildren.graphql | 8 + .../helpers/backend/gql/queries/Me.graphql | 9 + .../src/layouts/default.vue | 15 + .../hoppscotch-sh-admin/src/layouts/empty.vue | 5 + packages/hoppscotch-sh-admin/src/main.ts | 45 + .../src/pages/dashboard.vue | 83 + .../hoppscotch-sh-admin/src/pages/index.vue | 114 + .../src/pages/settings.vue | 5 + .../src/pages/teams/AddTeam.vue | 37 + .../src/pages/teams/details.vue | 144 + .../src/pages/teams/index.vue | 173 ++ .../src/pages/users/AddUser.vue | 125 + .../src/pages/users/details.vue | 126 + .../src/pages/users/index.vue | 265 ++ .../src/pages/users/invited.vue | 226 ++ .../hoppscotch-sh-admin/src/shims-vue.d.ts | 5 + .../hoppscotch-sh-admin/src/vite-env.d.ts | 3 + packages/hoppscotch-sh-admin/tsconfig.json | 91 + .../hoppscotch-sh-admin/tsconfig.node.json | 9 + packages/hoppscotch-sh-admin/vite.config.ts | 51 + packages/hoppscotch-sh-admin/windi.config.ts | 65 + packages/hoppscotch-ui/README.md | 31 +- packages/hoppscotch-ui/histoire.config.ts | 5 +- packages/hoppscotch-ui/package.json | 25 +- .../hoppscotch-ui/src/assets/scss/styles.scss | 440 --- packages/hoppscotch-ui/src/components.d.ts | 37 - .../src/components/button/Primary.vue | 47 +- .../src/components/button/Secondary.vue | 42 +- .../src/components/button/index.ts | 2 + .../hoppscotch-ui/src/components/index.ts | 49 +- .../src/components/smart/Anchor.vue | 24 +- .../src/components/smart/AutoComplete.vue | 39 +- .../src/components/smart/ConfirmModal.vue | 32 +- .../src/components/smart/Expand.vue | 28 +- .../src/components/smart/Item.vue | 59 +- .../src/components/smart/Link.vue | 27 +- .../src/components/smart/Modal.vue | 5 +- .../src/components/smart/Radio.vue | 11 +- .../src/components/smart/RadioGroup.vue | 12 +- .../src/components/smart/SlideOver.vue | 25 +- .../src/components/smart/Spinner.vue | 8 +- .../src/components/smart/Tabs.vue | 4 +- .../src/components/smart/Windows.vue | 107 +- .../src/components/smart/index.ts | 20 + packages/hoppscotch-ui/src/index.ts | 35 +- packages/hoppscotch-ui/src/plugin.ts | 30 + .../src/stories/Anchor.story.vue | 19 +- .../src/stories/AutoComplete.story.vue | 27 +- .../src/stories/Button.story.vue | 8 +- .../src/stories/Checkbox.story.vue | 4 +- .../src/stories/ConfirmModal.story.vue | 9 +- .../src/stories/Expand.story.vue | 20 + .../hoppscotch-ui/src/stories/Item.story.vue | 6 +- .../hoppscotch-ui/src/stories/Link.story.vue | 12 +- .../hoppscotch-ui/src/stories/Modal.story.vue | 8 +- .../src/stories/ProgressRing.story.vue | 9 +- .../hoppscotch-ui/src/stories/Radio.story.vue | 5 +- .../src/stories/SlideOver.story.vue | 7 +- .../src/stories/Spinner.story.vue | 6 +- .../hoppscotch-ui/src/stories/Tab.story.vue | 13 +- .../src/stories/Toggle.story.vue | 3 +- .../src/stories/Window.story.vue | 23 +- packages/hoppscotch-ui/tsconfig.json | 41 +- packages/hoppscotch-ui/vite.config.ts | 48 +- packages/hoppscotch-web/package.json | 1 + packages/hoppscotch-web/vite.config.ts | 10 +- pnpm-lock.yaml | 2456 ++++++++++++++++- 219 files changed, 6737 insertions(+), 1967 deletions(-) create mode 100644 packages/hoppscotch-sh-admin/.gitignore create mode 100644 packages/hoppscotch-sh-admin/assets/scss/styles.scss create mode 100644 packages/hoppscotch-sh-admin/assets/scss/themes.scss create mode 100644 packages/hoppscotch-sh-admin/gql-codegen.yml create mode 100644 packages/hoppscotch-sh-admin/index.html create mode 100644 packages/hoppscotch-sh-admin/package.json create mode 100644 packages/hoppscotch-sh-admin/public/cover.jpg create mode 100644 packages/hoppscotch-sh-admin/public/favicon.ico create mode 100644 packages/hoppscotch-sh-admin/public/vite.svg create mode 100644 packages/hoppscotch-sh-admin/src/App.vue create mode 100644 packages/hoppscotch-sh-admin/src/components.d.ts create mode 100644 packages/hoppscotch-sh-admin/src/components/app/Header.vue create mode 100644 packages/hoppscotch-sh-admin/src/components/app/Modal.vue create mode 100644 packages/hoppscotch-sh-admin/src/components/app/Sidebar.vue create mode 100644 packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue create mode 100644 packages/hoppscotch-sh-admin/src/composables/useSidebar.ts create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/GetCollectionChildren.graphql create mode 100644 packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/Me.graphql create mode 100644 packages/hoppscotch-sh-admin/src/layouts/default.vue create mode 100644 packages/hoppscotch-sh-admin/src/layouts/empty.vue create mode 100644 packages/hoppscotch-sh-admin/src/main.ts create mode 100644 packages/hoppscotch-sh-admin/src/pages/dashboard.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/index.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/settings.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/teams/details.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/teams/index.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/users/AddUser.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/users/details.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/users/index.vue create mode 100644 packages/hoppscotch-sh-admin/src/pages/users/invited.vue create mode 100644 packages/hoppscotch-sh-admin/src/shims-vue.d.ts create mode 100644 packages/hoppscotch-sh-admin/src/vite-env.d.ts create mode 100644 packages/hoppscotch-sh-admin/tsconfig.json create mode 100644 packages/hoppscotch-sh-admin/tsconfig.node.json create mode 100644 packages/hoppscotch-sh-admin/vite.config.ts create mode 100644 packages/hoppscotch-sh-admin/windi.config.ts delete mode 100644 packages/hoppscotch-ui/src/components.d.ts create mode 100644 packages/hoppscotch-ui/src/components/button/index.ts create mode 100644 packages/hoppscotch-ui/src/components/smart/index.ts create mode 100644 packages/hoppscotch-ui/src/plugin.ts create mode 100644 packages/hoppscotch-ui/src/stories/Expand.story.vue diff --git a/packages/hoppscotch-cli/README.md b/packages/hoppscotch-cli/README.md index 9e806c009..420af5315 100644 --- a/packages/hoppscotch-cli/README.md +++ b/packages/hoppscotch-cli/README.md @@ -1,4 +1,17 @@ -# Hoppscotch CLI ALPHA +
+ + Hoppscotch Logo + +
+
+ +# Hoppscotch CLI ALPHA + +
A CLI to run Hoppscotch test scripts in CI environments. @@ -33,7 +46,7 @@ hopp [options or commands] arguments #### Options: ##### `-e ` / `--env ` - - Accepts path to env.json with contents in below format: + - Accepts path to env.json with contents in below format: ```json { "ENV1":"value1", @@ -41,7 +54,7 @@ hopp [options or commands] arguments } ``` - You can now access those variables using `pw.env.get('')` - + Taking the above example, `pw.env.get("ENV1")` will return `"value1"` ## Install diff --git a/packages/hoppscotch-common/package.json b/packages/hoppscotch-common/package.json index 34c92fb88..57e35b399 100644 --- a/packages/hoppscotch-common/package.json +++ b/packages/hoppscotch-common/package.json @@ -90,7 +90,7 @@ "vue-pdf-embed": "^1.1.4", "vue-router": "^4.0.16", "vue-tippy": "6.0.0-alpha.58", - "vuedraggable": "^4.1.0", + "vuedraggable-es": "^4.1.1", "wonka": "^4.0.15", "workbox-window": "^6.5.4", "yargs-parser": "^21.1.1" diff --git a/packages/hoppscotch-common/src/App.vue b/packages/hoppscotch-common/src/App.vue index de03b4aa4..8cf3e8e26 100644 --- a/packages/hoppscotch-common/src/App.vue +++ b/packages/hoppscotch-common/src/App.vue @@ -4,7 +4,7 @@ v-if="isLoadingInitialRoute" class="flex flex-col items-center justify-center min-h-screen" > - + diff --git a/packages/hoppscotch-common/src/components.d.ts b/packages/hoppscotch-common/src/components.d.ts index 3b7ae649d..e0268dcf4 100644 --- a/packages/hoppscotch-common/src/components.d.ts +++ b/packages/hoppscotch-common/src/components.d.ts @@ -97,18 +97,6 @@ declare module '@vue/runtime-core' { HttpTestResultReport: typeof import('./components/http/TestResultReport.vue')['default'] HttpTests: typeof import('./components/http/Tests.vue')['default'] HttpURLEncodedParams: typeof import('./components/http/URLEncodedParams.vue')['default'] - IconLucideArrowLeft: typeof import('~icons/lucide/arrow-left')['default'] - IconLucideCheckCircle: typeof import('~icons/lucide/check-circle')['default'] - IconLucideChevronRight: typeof import('~icons/lucide/chevron-right')['default'] - IconLucideGlobe: typeof import('~icons/lucide/globe')['default'] - IconLucideInbox: typeof import('~icons/lucide/inbox')['default'] - IconLucideInfo: typeof import('~icons/lucide/info')['default'] - IconLucideLayers: typeof import('~icons/lucide/layers')['default'] - IconLucideLoader: typeof import('~icons/lucide/loader')['default'] - IconLucideMinus: typeof import('~icons/lucide/minus')['default'] - IconLucideSearch: typeof import('~icons/lucide/search')['default'] - IconLucideUser: typeof import('~icons/lucide/user')['default'] - IconLucideUsers: typeof import('~icons/lucide/users')['default'] LensesHeadersRenderer: typeof import('./components/lenses/HeadersRenderer.vue')['default'] LensesHeadersRendererEntry: typeof import('./components/lenses/HeadersRendererEntry.vue')['default'] LensesRenderersHTMLLensRenderer: typeof import('./components/lenses/renderers/HTMLLensRenderer.vue')['default'] diff --git a/packages/hoppscotch-common/src/components/app/DeveloperOptions.vue b/packages/hoppscotch-common/src/components/app/DeveloperOptions.vue index f2f63346f..a94977acf 100644 --- a/packages/hoppscotch-common/src/components/app/DeveloperOptions.vue +++ b/packages/hoppscotch-common/src/components/app/DeveloperOptions.vue @@ -1,5 +1,5 @@ - + diff --git a/packages/hoppscotch-common/src/components/app/Header.vue b/packages/hoppscotch-common/src/components/app/Header.vue index f20e619cc..539d994c3 100644 --- a/packages/hoppscotch-common/src/components/app/Header.vue +++ b/packages/hoppscotch-common/src/components/app/Header.vue @@ -10,7 +10,7 @@ paddingLeft: platform.ui?.appHeader?.paddingLeft?.value, }" > -
- - - -
- +
- - - {{ t("layout.name") }} - - {{ t("support.title") }} - - - - {{ t("settings.follow") }} - - - - - - - + + + + diff --git a/packages/hoppscotch-sh-admin/package.json b/packages/hoppscotch-sh-admin/package.json new file mode 100644 index 000000000..db3751f20 --- /dev/null +++ b/packages/hoppscotch-sh-admin/package.json @@ -0,0 +1,57 @@ +{ + "name": "hoppscotch-sh-admin", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "pnpm exec npm-run-all -p -l dev:*", + "dev:vite": "vite", + "dev:gql-codegen": "graphql-codegen --require dotenv/config --config gql-codegen.yml --watch dotenv_config_path=\"../../.env\"", + "build": "vue-tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@hoppscotch/ui": "workspace:^", + "@types/cors": "^2.8.13", + "@types/express": "^4.17.15", + "@urql/vue": "^1.0.4", + "@vueuse/core": "^9.10.0", + "cors": "^2.8.5", + "express": "^4.18.2", + "express-graphql": "^0.12.0", + "graphql": "^16.6.0", + "ts-node-dev": "^2.0.0", + "unplugin-icons": "^0.14.9", + "unplugin-vue-components": "^0.21.0", + "vue": "^3.2.6", + "vue-router": "4" + }, + "devDependencies": { + "@graphql-codegen/cli": "3.0.0", + "@graphql-codegen/client-preset": "^2.0.0", + "@graphql-codegen/introspection": "3.0.0", + "@graphql-codegen/typed-document-node": "^2.3.1", + "@graphql-codegen/typescript": "3.0.0", + "@graphql-codegen/typescript-document-nodes": "3.0.0", + "@graphql-codegen/typescript-operations": "3.0.0", + "@graphql-codegen/urql-introspection": "2.2.1", + "@vitejs/plugin-vue": "^1.6.0", + "@vue/compiler-sfc": "^3.2.6", + "graphql-tag": "^2.12.6", + "npm-run-all": "^4.1.5", + "sass": "^1.57.1", + "ts-node": "^10.9.1", + "typescript": "^4.9.3", + "vite": "^2.5.1", + "vite-plugin-pages": "^0.26.0", + "vite-plugin-vue-layouts": "^0.7.0", + "vite-plugin-windicss": "^1.8.8", + "vue-tsc": "^0.3.0", + "windicss": "^3.5.6" + }, + "prettier": { + "singleQuote": true, + "semi": true + } +} diff --git a/packages/hoppscotch-sh-admin/public/cover.jpg b/packages/hoppscotch-sh-admin/public/cover.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a514cd311ae161342bb43cff12c64bf7a1d1b66 GIT binary patch literal 41798 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 literal 0 HcmV?d00001 diff --git a/packages/hoppscotch-sh-admin/public/vite.svg b/packages/hoppscotch-sh-admin/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/packages/hoppscotch-sh-admin/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/hoppscotch-sh-admin/src/App.vue b/packages/hoppscotch-sh-admin/src/App.vue new file mode 100644 index 000000000..630f83112 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/App.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/packages/hoppscotch-sh-admin/src/components.d.ts b/packages/hoppscotch-sh-admin/src/components.d.ts new file mode 100644 index 000000000..f6b43a8b5 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components.d.ts @@ -0,0 +1,52 @@ +// generated by unplugin-vue-components +// We suggest you to commit this file into source control +// Read more: https://github.com/vuejs/core/pull/3399 +import '@vue/runtime-core' + +export {} + +declare module '@vue/runtime-core' { + export interface GlobalComponents { + AppHeader: typeof import('./components/app/Header.vue')['default'] + AppModal: typeof import('./components/app/Modal.vue')['default'] + AppSidebar: typeof import('./components/app/Sidebar.vue')['default'] + ButtonPrimary: typeof import('./../../hoppscotch-ui/src/components/button/Primary.vue')['default'] + ButtonSecondary: typeof import('./../../hoppscotch-ui/src/components/button/Secondary.vue')['default'] + HoppSmartExpand: typeof import('@hoppscotch/ui')['HoppSmartExpand'] + IconLucideBell: typeof import('~icons/lucide/bell')['default'] + IconLucideLayoutDashboard: typeof import('~icons/lucide/layout-dashboard')['default'] + IconLucideLineChart: typeof import('~icons/lucide/line-chart')['default'] + IconLucideLock: typeof import('~icons/lucide/lock')['default'] + IconLucideMenu: typeof import('~icons/lucide/menu')['default'] + IconLucideSettings: typeof import('~icons/lucide/settings')['default'] + IconLucideSidebarClose: typeof import('~icons/lucide/sidebar-close')['default'] + IconLucideSidebarOpen: typeof import('~icons/lucide/sidebar-open')['default'] + IconLucideUser: typeof import('~icons/lucide/user')['default'] + IconLucideUserCog: typeof import('~icons/lucide/user-cog')['default'] + IconLucideUsers: typeof import('~icons/lucide/users')['default'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + SmartAnchor: typeof import('./../../hoppscotch-ui/src/components/smart/Anchor.vue')['default'] + SmartAutoComplete: typeof import('./../../hoppscotch-ui/src/components/smart/AutoComplete.vue')['default'] + SmartCheckbox: typeof import('./../../hoppscotch-ui/src/components/smart/Checkbox.vue')['default'] + SmartConfirmModal: typeof import('./../../hoppscotch-ui/src/components/smart/ConfirmModal.vue')['default'] + SmartExpand: typeof import('./../../hoppscotch-ui/src/components/smart/Expand.vue')['default'] + SmartFileChip: typeof import('./../../hoppscotch-ui/src/components/smart/FileChip.vue')['default'] + SmartIntersection: typeof import('./../../hoppscotch-ui/src/components/smart/Intersection.vue')['default'] + SmartItem: typeof import('./../../hoppscotch-ui/src/components/smart/Item.vue')['default'] + SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default'] + SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default'] + SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default'] + SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default'] + SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default'] + SmartSlideOver: typeof import('./../../hoppscotch-ui/src/components/smart/SlideOver.vue')['default'] + SmartSpinner: typeof import('./../../hoppscotch-ui/src/components/smart/Spinner.vue')['default'] + SmartTab: typeof import('./../../hoppscotch-ui/src/components/smart/Tab.vue')['default'] + SmartTabs: typeof import('./../../hoppscotch-ui/src/components/smart/Tabs.vue')['default'] + SmartToggle: typeof import('./../../hoppscotch-ui/src/components/smart/Toggle.vue')['default'] + SmartWindow: typeof import('./../../hoppscotch-ui/src/components/smart/Window.vue')['default'] + SmartWindows: typeof import('./../../hoppscotch-ui/src/components/smart/Windows.vue')['default'] + TeamsAddMembers: typeof import('./components/teams/AddMembers.vue')['default'] + } + +} diff --git a/packages/hoppscotch-sh-admin/src/components/app/Header.vue b/packages/hoppscotch-sh-admin/src/components/app/Header.vue new file mode 100644 index 000000000..b9eaf6bd3 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/app/Header.vue @@ -0,0 +1,92 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/components/app/Modal.vue b/packages/hoppscotch-sh-admin/src/components/app/Modal.vue new file mode 100644 index 000000000..92256ed7f --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/app/Modal.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/packages/hoppscotch-sh-admin/src/components/app/Sidebar.vue b/packages/hoppscotch-sh-admin/src/components/app/Sidebar.vue new file mode 100644 index 000000000..72945df1b --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/app/Sidebar.vue @@ -0,0 +1,100 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue b/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue new file mode 100644 index 000000000..d26c77163 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/components/teams/AddMembers.vue @@ -0,0 +1,83 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/composables/useSidebar.ts b/packages/hoppscotch-sh-admin/src/composables/useSidebar.ts new file mode 100644 index 000000000..26aa607bc --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/composables/useSidebar.ts @@ -0,0 +1,13 @@ +import { ref } from 'vue'; + +/** isOpen is used to indicate whether the sidebar is now visible on the screen */ +const isOpen = ref(false); +/** isExpanded is used to indicate whether the sidebar is now expanded to also include page names or the sidebar is compressed to show just the icons */ +const isExpanded = ref(true); + +export function useSidebar() { + return { + isOpen, + isExpanded, + }; +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/GetCollectionChildren.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/GetCollectionChildren.graphql new file mode 100644 index 000000000..0dac0aa74 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/GetCollectionChildren.graphql @@ -0,0 +1,8 @@ +query GetCollectionChildren($collectionID: ID!, $cursor: String) { + collection(collectionID: $collectionID) { + children(cursor: $cursor) { + id + title + } + } +} diff --git a/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/Me.graphql b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/Me.graphql new file mode 100644 index 000000000..0ebb2f444 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/helpers/backend/gql/queries/Me.graphql @@ -0,0 +1,9 @@ +query Me { + me { + uid + displayName + photoURL + isAdmin + createdOn + } +} diff --git a/packages/hoppscotch-sh-admin/src/layouts/default.vue b/packages/hoppscotch-sh-admin/src/layouts/default.vue new file mode 100644 index 000000000..80f6dbbfa --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/layouts/default.vue @@ -0,0 +1,15 @@ + diff --git a/packages/hoppscotch-sh-admin/src/layouts/empty.vue b/packages/hoppscotch-sh-admin/src/layouts/empty.vue new file mode 100644 index 000000000..a14d0c32c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/layouts/empty.vue @@ -0,0 +1,5 @@ + diff --git a/packages/hoppscotch-sh-admin/src/main.ts b/packages/hoppscotch-sh-admin/src/main.ts new file mode 100644 index 000000000..3e9c28958 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/main.ts @@ -0,0 +1,45 @@ +import { createApp } from 'vue'; +import urql, { createClient } from '@urql/vue'; +import App from './App.vue'; +import '../assets/scss/themes.scss'; +import '../assets/scss/styles.scss'; +import '@hoppscotch/ui/style.css'; +import 'virtual:windi.css'; +import { + createRouter, + createWebHashHistory, + createWebHistory, +} from 'vue-router'; + +import { setupLayouts } from 'virtual:generated-layouts'; +import generatedRoutes from 'virtual:generated-pages'; + +import { plugin as HoppUIPlugin, HoppUIPluginOptions } from '@hoppscotch/ui'; + +const options: HoppUIPluginOptions = { + /* Define options here */ +}; + +const routes = setupLayouts(generatedRoutes); + +const app = createApp(App).use( + urql, + createClient({ + url: import.meta.env.VITE_BACKEND_GQL_URL, + fetchOptions: () => { + return { + credentials: 'include', + }; + }, + }) +); + +app.use(HoppUIPlugin, options); +app.use( + createRouter({ + history: createWebHistory(), + routes, + }) +); + +app.mount('#app'); diff --git a/packages/hoppscotch-sh-admin/src/pages/dashboard.vue b/packages/hoppscotch-sh-admin/src/pages/dashboard.vue new file mode 100644 index 000000000..fee72ce44 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/dashboard.vue @@ -0,0 +1,83 @@ + diff --git a/packages/hoppscotch-sh-admin/src/pages/index.vue b/packages/hoppscotch-sh-admin/src/pages/index.vue new file mode 100644 index 000000000..153bc8855 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/index.vue @@ -0,0 +1,114 @@ + + + + + +meta: + layout: empty + diff --git a/packages/hoppscotch-sh-admin/src/pages/settings.vue b/packages/hoppscotch-sh-admin/src/pages/settings.vue new file mode 100644 index 000000000..98edf30cf --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/settings.vue @@ -0,0 +1,5 @@ + diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue b/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue new file mode 100644 index 000000000..7496247ea --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/teams/AddTeam.vue @@ -0,0 +1,37 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/details.vue b/packages/hoppscotch-sh-admin/src/pages/teams/details.vue new file mode 100644 index 000000000..38e057d4a --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/teams/details.vue @@ -0,0 +1,144 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/pages/teams/index.vue b/packages/hoppscotch-sh-admin/src/pages/teams/index.vue new file mode 100644 index 000000000..4d983581b --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/teams/index.vue @@ -0,0 +1,173 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/pages/users/AddUser.vue b/packages/hoppscotch-sh-admin/src/pages/users/AddUser.vue new file mode 100644 index 000000000..dd31e1e00 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/users/AddUser.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/packages/hoppscotch-sh-admin/src/pages/users/details.vue b/packages/hoppscotch-sh-admin/src/pages/users/details.vue new file mode 100644 index 000000000..9bf062571 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/users/details.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/packages/hoppscotch-sh-admin/src/pages/users/index.vue b/packages/hoppscotch-sh-admin/src/pages/users/index.vue new file mode 100644 index 000000000..6876213f8 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/users/index.vue @@ -0,0 +1,265 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/pages/users/invited.vue b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue new file mode 100644 index 000000000..8a611379c --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/pages/users/invited.vue @@ -0,0 +1,226 @@ + + + diff --git a/packages/hoppscotch-sh-admin/src/shims-vue.d.ts b/packages/hoppscotch-sh-admin/src/shims-vue.d.ts new file mode 100644 index 000000000..87bc1fa54 --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/shims-vue.d.ts @@ -0,0 +1,5 @@ +declare module '*.vue' { + import { defineComponent } from 'vue'; + const Component: ReturnType; + export default Component; +} diff --git a/packages/hoppscotch-sh-admin/src/vite-env.d.ts b/packages/hoppscotch-sh-admin/src/vite-env.d.ts new file mode 100644 index 000000000..9d639f64f --- /dev/null +++ b/packages/hoppscotch-sh-admin/src/vite-env.d.ts @@ -0,0 +1,3 @@ +/// +/// +/// diff --git a/packages/hoppscotch-sh-admin/tsconfig.json b/packages/hoppscotch-sh-admin/tsconfig.json new file mode 100644 index 000000000..20d96d963 --- /dev/null +++ b/packages/hoppscotch-sh-admin/tsconfig.json @@ -0,0 +1,91 @@ +// { +// "compilerOptions": { +// "target": "ESNext", +// "useDefineForClassFields": true, +// "module": "ESNext", +// "moduleResolution": "Node", +// "strict": true, +// "jsx": "preserve", +// "resolveJsonModule": true, +// "isolatedModules": true, +// "esModuleInterop": true, +// "lib": ["ESNext", "DOM"], +// "skipLibCheck": true, +// "noEmit": true +// }, +// "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], +// "references": [{ "path": "./tsconfig.node.json" }] +// } + +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + // "outDir": "./", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + + /* Advanced Options */ + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/packages/hoppscotch-sh-admin/tsconfig.node.json b/packages/hoppscotch-sh-admin/tsconfig.node.json new file mode 100644 index 000000000..9d31e2aed --- /dev/null +++ b/packages/hoppscotch-sh-admin/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/hoppscotch-sh-admin/vite.config.ts b/packages/hoppscotch-sh-admin/vite.config.ts new file mode 100644 index 000000000..c5eae879e --- /dev/null +++ b/packages/hoppscotch-sh-admin/vite.config.ts @@ -0,0 +1,51 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import { FileSystemIconLoader } from 'unplugin-icons/loaders'; +import Icons from 'unplugin-icons/vite'; +import IconResolver from 'unplugin-icons/resolver'; +import Components from 'unplugin-vue-components/vite'; +import WindiCSS from 'vite-plugin-windicss'; +import Pages from 'vite-plugin-pages'; +import Layouts from 'vite-plugin-vue-layouts'; +import path from 'path'; + +// https://vitejs.dev/config/ +export default defineConfig({ + envDir: path.resolve(__dirname, "../../"), + server: { + port: 3100, + }, + plugins: [ + vue(), + Pages({ + dirs: './src/pages', + routeStyle: 'nuxt', + }), + Layouts({ + defaultLayout: 'default', + layoutsDirs: 'src/layouts', + }), + WindiCSS({ + root: path.resolve(__dirname), + }), + Components({ + dts: './src/components.d.ts', + dirs: ['./src/components', '../hoppscotch-ui/src/components'], + directoryAsNamespace: true, + resolvers: [ + IconResolver({ + prefix: 'icon', + customCollections: ['hopp', 'auth', 'brands'], + }), + (compName: string) => { + if (compName.startsWith("Hopp")) + return { name: compName, from: "@hoppscotch/ui" } + else return undefined + }, + ], + }), + Icons({ + compiler: 'vue3', + }), + ], +}); diff --git a/packages/hoppscotch-sh-admin/windi.config.ts b/packages/hoppscotch-sh-admin/windi.config.ts new file mode 100644 index 000000000..99de3576c --- /dev/null +++ b/packages/hoppscotch-sh-admin/windi.config.ts @@ -0,0 +1,65 @@ +import { defineConfig } from 'windicss/helpers'; + +export default defineConfig({ + theme: { + container: { + center: true, + }, + extend: { + inset: { + upperPrimaryStickyFold: 'var(--upper-primary-sticky-fold)', + upperSecondaryStickyFold: 'var(--upper-secondary-sticky-fold)', + upperTertiaryStickyFold: 'var(--upper-tertiary-sticky-fold)', + upperMobilePrimaryStickyFold: 'var(--upper-mobile-primary-sticky-fold)', + upperMobileSecondaryStickyFold: + 'var(--upper-mobile-secondary-sticky-fold)', + upperMobileStickyFold: 'var(--upper-mobile-sticky-fold)', + upperMobileTertiaryStickyFold: + 'var(--upper-mobile-tertiary-sticky-fold)', + lowerPrimaryStickyFold: 'var(--lower-primary-sticky-fold)', + lowerSecondaryStickyFold: 'var(--lower-secondary-sticky-fold)', + lowerTertiaryStickyFold: 'var(--lower-tertiary-sticky-fold)', + sidebarPrimaryStickyFold: 'var(--sidebar-primary-sticky-fold)', + }, + colors: { + primary: 'var(--primary-color)', + primaryLight: 'var(--primary-light-color)', + primaryDark: 'var(--primary-dark-color)', + primaryContrast: 'var(--primary-contrast-color)', + secondary: 'var(--secondary-color)', + secondaryLight: 'var(--secondary-light-color)', + secondaryDark: 'var(--secondary-dark-color)', + accent: 'var(--accent-color)', + accentLight: 'var(--accent-light-color)', + accentDark: 'var(--accent-dark-color)', + accentContrast: 'var(--accent-contrast-color)', + divider: 'var(--divider-color)', + dividerLight: 'var(--divider-light-color)', + dividerDark: 'var(--divider-dark-color)', + error: 'var(--error-color)', + tooltip: 'var(--tooltip-color)', + popover: 'var(--popover-color)', + gradientFrom: 'var(--gradient-from-color)', + gradientVia: 'var(--gradient-via-color)', + gradientTo: 'var(--gradient-to-color)', + }, + fontFamily: { + sans: 'var(--font-sans)', + mono: 'var(--font-mono)', + icon: 'var(--font-icon)', + }, + fontSize: { + tiny: 'var(--font-size-tiny)', + body: 'var(--font-size-body)', + }, + lineHeight: { + body: 'var(--line-height-body)', + }, + cursor: { + nsResize: 'ns-resize', + grab: 'grab', + grabbing: 'grabbing', + }, + }, + }, +}); diff --git a/packages/hoppscotch-ui/README.md b/packages/hoppscotch-ui/README.md index 8f1885799..765dd7207 100644 --- a/packages/hoppscotch-ui/README.md +++ b/packages/hoppscotch-ui/README.md @@ -1,24 +1,15 @@ -
- - - - - - - + +
-
- -# Hoppscotch UI +# Hoppscotch UI ALPHA
@@ -28,7 +19,7 @@ Welcome to hoppscotch-ui, a collection of presentational components for our web To use the components in project, simply name the component with `directory` name as alias: -For example `Primary Button` component is in `button` directory and the file name is `Primary.vue`. So, use that you have to write `` +For example `Primary Button` component is in `button` directory and the file name is `Primary.vue`. So, use that you have to write `` ## Histoire diff --git a/packages/hoppscotch-ui/histoire.config.ts b/packages/hoppscotch-ui/histoire.config.ts index 88fb23b11..5ba0ebc71 100644 --- a/packages/hoppscotch-ui/histoire.config.ts +++ b/packages/hoppscotch-ui/histoire.config.ts @@ -9,9 +9,12 @@ export default defineConfig({ light: "/logo.png", dark: "/logo.png", }, - // logoHref: "https://ui.hoppscotch.io", + logoHref: "https://ui.hoppscotch.io", favicon: 'favicon.ico', }, setupFile: "histoire.setup.ts", plugins: [HstVue()], + viteIgnorePlugins: [ + 'vite:dts' + ] }) diff --git a/packages/hoppscotch-ui/package.json b/packages/hoppscotch-ui/package.json index 66dd846f1..4a3c91c89 100644 --- a/packages/hoppscotch-ui/package.json +++ b/packages/hoppscotch-ui/package.json @@ -2,13 +2,20 @@ "name": "@hoppscotch/ui", "private": true, "version": "0.0.1", + "type": "module", "scripts": { "build": "vite build", "story:dev": "histoire dev", "story:build": "histoire build", "story:preview": "histoire preview", + "do-build-prod": "pnpm run build", + "postinstall": "pnpm run build", "do-build-ui": "pnpm run story:build" }, + "peerDependencies": { + "vue": "^3.2.25", + "vue-router": "^4.0.16" + }, "dependencies": { "@hoppscotch/vue-toasted": "^0.1.0", "@lezer/highlight": "^1.0.0", @@ -30,11 +37,10 @@ "url": "^0.11.0", "util": "^0.12.4", "vite-plugin-eslint": "^1.8.1", - "vue": "^3.2.25", "vue-github-button": "^3.0.3", "vue-router": "^4.0.16", "vue-tippy": "6.0.0-alpha.58", - "vuedraggable": "^4.1.0" + "vuedraggable-es": "^4.1.1" }, "devDependencies": { "@esbuild-plugins/node-globals-polyfill": "^0.1.1", @@ -60,10 +66,11 @@ "rollup-plugin-polyfill-node": "^0.10.1", "sass": "^1.53.0", "typescript": "^4.5.4", - "unplugin-icons": "^0.14.9", + "unplugin-icons": "^0.15.3", "unplugin-vue-components": "^0.21.0", "vite": "^3.2.3", "vite-plugin-checker": "^0.5.1", + "vite-plugin-dts": "2.0.0-beta.3", "vite-plugin-fonts": "^0.6.0", "vite-plugin-html-config": "^1.0.10", "vite-plugin-inspect": "^0.7.4", @@ -72,12 +79,20 @@ "vite-plugin-pwa": "^0.13.1", "vite-plugin-vue-layouts": "^0.7.0", "vite-plugin-windicss": "^1.8.8", + "vue": "^3.2.25", "vue-loader": "^16.8.3", + "vue-router": "^4.0.16", "vue-tsc": "^0.38.2", "windicss": "^3.5.6" }, "files": [ - "src", "dist" - ] + ], + "module": "./dist/index.es.js", + "main": "./dist/index.es.js", + "exports": { + ".": "./dist/index.es.js", + "./style.css": "./dist/style.css" + }, + "types": "./dist/index.d.ts" } diff --git a/packages/hoppscotch-ui/src/assets/scss/styles.scss b/packages/hoppscotch-ui/src/assets/scss/styles.scss index b38b0c9c7..8605dab2a 100644 --- a/packages/hoppscotch-ui/src/assets/scss/styles.scss +++ b/packages/hoppscotch-ui/src/assets/scss/styles.scss @@ -1,64 +1,3 @@ -* { - @apply backface-hidden; - @apply before:backface-hidden; - @apply after:backface-hidden; - @apply selection:bg-accentDark; - @apply selection:text-accentContrast; -} - -:root { - @apply antialiased; - accent-color: var(--accent-color); - font-variant-ligatures: common-ligatures; -} - -::-webkit-scrollbar-track { - @apply bg-transparent; - @apply border-solid border-l border-dividerLight border-t-0 border-b-0 border-r-0; -} - -::-webkit-scrollbar-thumb { - @apply bg-divider bg-clip-content; - @apply rounded-full; - @apply border-solid border-transparent border-4; - @apply hover:bg-dividerDark; - @apply hover:bg-clip-content; -} - -::-webkit-scrollbar { - @apply w-4; - @apply h-0; -} - -input::placeholder, -textarea::placeholder, -.cm-placeholder { - @apply text-secondary; - @apply opacity-50; -} - -input, -textarea { - @apply text-secondaryDark; - @apply font-medium; -} - -html { - scroll-behavior: smooth; -} - -body { - @apply bg-primary; - @apply text-secondary text-body; - @apply font-medium; - @apply select-none; - @apply overflow-x-hidden; - @apply leading-body; - animation: fade 300ms forwards; - -webkit-tap-highlight-color: transparent; - -webkit-touch-callout: none; -} - @keyframes fade { 0% { @apply opacity-0; @@ -130,89 +69,6 @@ a { } } -.cm-tooltip { - .tippy-box { - @apply shadow-none; - @apply fixed; - @apply inline-flex; - @apply -mt-8; - } -} - -.tippy-box[data-theme~="tooltip"] { - @apply bg-tooltip; - @apply border-solid border-tooltip; - @apply rounded; - @apply shadow; - - .tippy-content { - @apply flex; - @apply text-tiny text-primary; - @apply font-semibold; - @apply py-1 px-2; - @apply truncate; - @apply leading-normal; - @apply items-center; - - kbd { - @apply hidden; - @apply font-sans; - @apply bg-gray-500/45; - @apply text-primaryLight; - @apply rounded-sm; - @apply px-1; - @apply my-0 ml-1; - @apply truncate; - @apply sm:inline-flex; - } - - .env-icon { - @apply transition; - @apply inline-flex; - @apply items-center; - } - } - - .tippy-svg-arrow { - svg:first-child { - @apply fill-tooltip; - } - - svg:last-child { - @apply fill-tooltip; - } - } -} - -.tippy-box[data-theme~="popover"] { - @apply bg-popover; - @apply border-solid border-dividerDark; - @apply rounded; - @apply shadow-lg; - - .tippy-content { - @apply flex flex-col; - @apply max-h-56; - @apply items-stretch; - @apply overflow-y-auto; - @apply text-secondary text-body; - @apply p-2; - @apply leading-normal; - @apply focus:outline-none; - scroll-behavior: smooth; - } - - .tippy-svg-arrow { - svg:first-child { - @apply fill-dividerDark; - } - - svg:last-child { - @apply fill-popover; - } - } -} - [data-v-tippy] { @apply flex flex-1; } @@ -246,243 +102,6 @@ hr { @apply focus-visible:border-dividerDark; } -input, -select, -textarea, -button { - @apply truncate; - @apply transition; - @apply text-body; - @apply leading-body; - @apply focus:outline-none; - @apply disabled:cursor-not-allowed; -} - -.input[type="file"], -.input[type="radio"], -#installPWA { - @apply hidden; -} - -.floating-input ~ label { - @apply absolute; - @apply px-2 py-0.5; - @apply m-2; - @apply rounded; - @apply transition; - @apply origin-top-left; -} - -.floating-input:focus-within ~ label, -.floating-input:not(:placeholder-shown) ~ label { - @apply bg-primary; - @apply transform; - @apply origin-top-left; - @apply scale-75; - @apply translate-x-1 -translate-y-4; -} - -.floating-input:focus-within ~ label { - @apply text-secondaryDark; -} - -.floating-input ~ .end-actions { - @apply absolute; - @apply right-0.2; - @apply inset-y-0; - @apply flex; - @apply items-center; -} - -.floating-input:has(~ .end-actions) { - @apply pr-12; -} - -pre.ace_editor { - @apply font-mono; - @apply resize-none; - @apply z-0; -} - -.select { - @apply appearance-none; - @apply cursor-pointer; - - &::-ms-expand { - @apply hidden; - } -} - -.select-wrapper { - @apply flex flex-1; - @apply relative; - @apply after:absolute; - @apply after:flex; - @apply after:inset-y-0; - @apply after:items-center; - @apply after:justify-center; - @apply after:pointer-events-none; - @apply after:font-icon; - @apply after:text-secondaryLight; - @apply after:right-3; - @apply after:content-["\e313"]; -} - -.info-response { - @apply text-pink-500; -} - -.success-response { - @apply text-green-500; -} - -.redir-response { - @apply text-yellow-500; -} - -.cl-error-response { - @apply text-red-500; -} - -.sv-error-response { - @apply text-red-600; -} - -.missing-data-response { - @apply text-secondaryLight; -} - -.toasted-container { - @apply max-w-md; - - .toasted { - &.toasted-primary { - @apply px-4 py-2; - @apply bg-tooltip; - @apply border-secondaryDark; - @apply text-primary text-body; - @apply justify-between; - @apply shadow-lg; - @apply font-semibold; - @apply transition; - @apply leading-body; - @apply sm:rounded; - @apply sm:border; - - .action { - @apply relative; - @apply flex flex-shrink-0; - @apply text-body; - @apply px-4; - @apply my-1; - @apply ml-auto; - @apply normal-case; - @apply font-semibold; - @apply leading-body; - @apply tracking-normal; - @apply rounded; - @apply last:ml-4; - @apply sm:ml-8; - @apply before:absolute; - @apply before:bg-current; - @apply before:opacity-10; - @apply before:inset-0; - @apply before:transition; - @apply before:content-DEFAULT; - @apply hover:no-underline; - @apply hover:before:opacity-20; - } - } - - &.info { - @apply bg-accent; - @apply text-accentContrast; - @apply border-accentDark; - } - - &.error { - @apply bg-red-200; - @apply text-red-800; - @apply border-red-400; - } - - &.success { - @apply bg-green-200; - @apply text-green-800; - @apply border-green-400; - } - } -} - -.smart-splitter .splitpanes__splitter { - @apply relative; - @apply before:absolute; - @apply before:inset-0; - @apply before:bg-accentLight; - @apply before:opacity-0; - @apply before:z-20; - @apply before:transition; - @apply before:content-DEFAULT; - @apply hover:before:opacity-100; -} - -.no-splitter .splitpanes__splitter { - @apply relative; -} - -.smart-splitter.splitpanes--vertical > .splitpanes__splitter { - @apply w-0; - @apply before:-left-0.5; - @apply before:-right-0.5; - @apply before:h-full; - @apply bg-divider; -} - -.smart-splitter.splitpanes--horizontal > .splitpanes__splitter { - @apply h-0; - @apply before:-top-0.5; - @apply before:-bottom-0.5; - @apply before:w-full; - @apply bg-divider; -} - -.no-splitter.splitpanes--vertical > .splitpanes__splitter { - @apply w-0; - @apply pointer-events-none; - @apply bg-dividerLight; -} - -.no-splitter.splitpanes--horizontal > .splitpanes__splitter { - @apply h-0; - @apply pointer-events-none; - @apply bg-dividerLight; -} - -.cm-focused { - @apply select-auto; - @apply outline-none #{!important}; - - .cm-activeLine { - @apply bg-primaryLight; - } - - .cm-activeLineGutter { - @apply bg-primaryDark; - } -} - -.cm-editor { - .cm-line::selection { - @apply bg-accentDark #{!important}; - @apply text-accentContrast #{!important}; - } - - .cm-line ::selection { - @apply bg-accentDark #{!important}; - @apply text-accentContrast #{!important}; - } -} - .shortcut-key { @apply inline-flex; @apply font-sans; @@ -499,62 +118,3 @@ pre.ace_editor { @apply shadow-sm; @apply - - - + ]" :disabled="disabled" :tabindex="loading ? '-1' : '0'" role="button"> + + {{ label }}
- + {{ key }}
- - + + -
+ diff --git a/packages/hoppscotch-ui/src/components/smart/Tabs.vue b/packages/hoppscotch-ui/src/components/smart/Tabs.vue index 54623cd83..5105e1a42 100644 --- a/packages/hoppscotch-ui/src/components/smart/Tabs.vue +++ b/packages/hoppscotch-ui/src/components/smart/Tabs.vue @@ -212,8 +212,8 @@ const selectTab = (id: string) => { @apply inline-flex; @apply items-center; @apply justify-center; - @apply w-5; - @apply h-4; + @apply px-1 py-0.75; + @apply min-w-4; @apply ml-2; @apply text-8px; @apply border border-divider; diff --git a/packages/hoppscotch-ui/src/components/smart/Windows.vue b/packages/hoppscotch-ui/src/components/smart/Windows.vue index 9b142a554..15e4cb549 100644 --- a/packages/hoppscotch-ui/src/components/smart/Windows.vue +++ b/packages/hoppscotch-ui/src/components/smart/Windows.vue @@ -1,71 +1,37 @@ + diff --git a/packages/hoppscotch-ui/src/stories/AutoComplete.story.vue b/packages/hoppscotch-ui/src/stories/AutoComplete.story.vue index 61be821fa..e4ee06227 100644 --- a/packages/hoppscotch-ui/src/stories/AutoComplete.story.vue +++ b/packages/hoppscotch-ui/src/stories/AutoComplete.story.vue @@ -1,28 +1,21 @@ diff --git a/packages/hoppscotch-ui/src/stories/Checkbox.story.vue b/packages/hoppscotch-ui/src/stories/Checkbox.story.vue index bfc1c37fa..77c7a898d 100644 --- a/packages/hoppscotch-ui/src/stories/Checkbox.story.vue +++ b/packages/hoppscotch-ui/src/stories/Checkbox.story.vue @@ -1,12 +1,14 @@ diff --git a/packages/hoppscotch-ui/src/stories/Item.story.vue b/packages/hoppscotch-ui/src/stories/Item.story.vue index 875f460ef..1af65a19c 100644 --- a/packages/hoppscotch-ui/src/stories/Item.story.vue +++ b/packages/hoppscotch-ui/src/stories/Item.story.vue @@ -1,7 +1,11 @@ + + diff --git a/packages/hoppscotch-ui/src/stories/Link.story.vue b/packages/hoppscotch-ui/src/stories/Link.story.vue index 74f579d5a..e83d6feec 100644 --- a/packages/hoppscotch-ui/src/stories/Link.story.vue +++ b/packages/hoppscotch-ui/src/stories/Link.story.vue @@ -1,18 +1,20 @@ diff --git a/packages/hoppscotch-ui/src/stories/Modal.story.vue b/packages/hoppscotch-ui/src/stories/Modal.story.vue index ebfb081c5..34e50fcb0 100644 --- a/packages/hoppscotch-ui/src/stories/Modal.story.vue +++ b/packages/hoppscotch-ui/src/stories/Modal.story.vue @@ -1,15 +1,11 @@ diff --git a/packages/hoppscotch-ui/src/stories/Radio.story.vue b/packages/hoppscotch-ui/src/stories/Radio.story.vue index 778065843..1d9af6978 100644 --- a/packages/hoppscotch-ui/src/stories/Radio.story.vue +++ b/packages/hoppscotch-ui/src/stories/Radio.story.vue @@ -1,16 +1,17 @@ diff --git a/packages/hoppscotch-ui/src/stories/Tab.story.vue b/packages/hoppscotch-ui/src/stories/Tab.story.vue index 28415baec..dd0484073 100644 --- a/packages/hoppscotch-ui/src/stories/Tab.story.vue +++ b/packages/hoppscotch-ui/src/stories/Tab.story.vue @@ -1,19 +1,20 @@