@scalar/api-client 2.38.2 → 2.38.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/{AddressBar-B4xnl66I.js → AddressBar-CX8xiYoe.js} +4 -4
- package/dist/{AddressBar-B4xnl66I.js.map → AddressBar-CX8xiYoe.js.map} +1 -1
- package/dist/{App-BVH4lIe8.js → App-BpNPKHmM.js} +4 -4
- package/dist/{App-BVH4lIe8.js.map → App-BpNPKHmM.js.map} +1 -1
- package/dist/{App-CvClwSlM.js → App-Ckirvnv1.js} +2 -2
- package/dist/{App-CvClwSlM.js.map → App-Ckirvnv1.js.map} +1 -1
- package/dist/{CodeInput-C-igR77V.js → CodeInput-BN7uw3Bh.js} +2 -2
- package/dist/{CodeInput-C-igR77V.js.map → CodeInput-BN7uw3Bh.js.map} +1 -1
- package/dist/{Collection-4MT9WmDD.js → Collection-ChAxs3rz.js} +2 -2
- package/dist/{Collection-4MT9WmDD.js.map → Collection-ChAxs3rz.js.map} +1 -1
- package/dist/{CollectionAuthentication-MHWQpw74.js → CollectionAuthentication-BDpvv8cA.js} +5 -5
- package/dist/{CollectionAuthentication-MHWQpw74.js.map → CollectionAuthentication-BDpvv8cA.js.map} +1 -1
- package/dist/{CollectionEnvironment-Dw35vIqo.js → CollectionEnvironment-dwisJ-h5.js} +4 -4
- package/dist/{CollectionEnvironment-Dw35vIqo.js.map → CollectionEnvironment-dwisJ-h5.js.map} +1 -1
- package/dist/{CollectionOverview-TUdDIu5f.js → CollectionOverview-CJ9-Vmei.js} +3 -3
- package/dist/{CollectionOverview-TUdDIu5f.js.map → CollectionOverview-CJ9-Vmei.js.map} +1 -1
- package/dist/{CollectionServers-BrjTCfDe.js → CollectionServers-BWkIGwz4.js} +5 -5
- package/dist/{CollectionServers-BrjTCfDe.js.map → CollectionServers-BWkIGwz4.js.map} +1 -1
- package/dist/{CollectionSettings-HVSlp2Gv.js → CollectionSettings-CqUUYOym.js} +2 -2
- package/dist/{CollectionSettings-HVSlp2Gv.js.map → CollectionSettings-CqUUYOym.js.map} +1 -1
- package/dist/{CommandPalette-CL8k4CoN.js → CommandPalette-BiA0IgO8.js} +2 -2
- package/dist/{CommandPalette-CL8k4CoN.js.map → CommandPalette-BiA0IgO8.js.map} +1 -1
- package/dist/{Cookies-DbOKTi1f.js → Cookies-CNRSxP8J.js} +8 -8
- package/dist/{Cookies-DbOKTi1f.js.map → Cookies-CNRSxP8J.js.map} +1 -1
- package/dist/{DataTableInput-yaU5g-kP.js → DataTableInput-SkIUPlrB.js} +2 -2
- package/dist/{DataTableInput-yaU5g-kP.js.map → DataTableInput-SkIUPlrB.js.map} +1 -1
- package/dist/{Environment-DJatRQIg.js → Environment-D_CbZk0A.js} +5 -5
- package/dist/{Environment-DJatRQIg.js.map → Environment-D_CbZk0A.js.map} +1 -1
- package/dist/{EnvironmentModal-DBEJ4Kzj.js → EnvironmentModal-CcyqnPc2.js} +2 -2
- package/dist/{EnvironmentModal-DBEJ4Kzj.js.map → EnvironmentModal-CcyqnPc2.js.map} +1 -1
- package/dist/{Form-CSKzyHGO.js → Form-bA4bV_oA.js} +3 -3
- package/dist/{Form-CSKzyHGO.js.map → Form-bA4bV_oA.js.map} +1 -1
- package/dist/{ImportCollection-DfX1UQ5u.js → ImportCollection-BIYMxB9Q.js} +2 -2
- package/dist/{ImportCollection-DfX1UQ5u.js.map → ImportCollection-BIYMxB9Q.js.map} +1 -1
- package/dist/{MainLayout-BEFMl1ud.js → MainLayout-oMIJ5QXF.js} +3 -3
- package/dist/{MainLayout-BEFMl1ud.js.map → MainLayout-oMIJ5QXF.js.map} +1 -1
- package/dist/{Modal-sQ9vH6MN.js → Modal-DkOa_KK0.js} +2 -2
- package/dist/{Modal-sQ9vH6MN.js.map → Modal-DkOa_KK0.js.map} +1 -1
- package/dist/{Request-gscRsGQ8.js → Request-BWfYWyBa.js} +10 -10
- package/dist/{Request-gscRsGQ8.js.map → Request-BWfYWyBa.js.map} +1 -1
- package/dist/{RequestAuth-BzBfIysT.js → RequestAuth-BU6ubH-c.js} +3 -3
- package/dist/{RequestAuth-BzBfIysT.js.map → RequestAuth-BU6ubH-c.js.map} +1 -1
- package/dist/{RequestRoot-3Bj8JZD-.js → RequestRoot-7xhK5_qr.js} +7 -7
- package/dist/{RequestRoot-3Bj8JZD-.js.map → RequestRoot-7xhK5_qr.js.map} +1 -1
- package/dist/{RequestSection-HhdJj9hW.js → RequestSection-Bx8UHW-k.js} +4 -4
- package/dist/{RequestSection-HhdJj9hW.js.map → RequestSection-Bx8UHW-k.js.map} +1 -1
- package/dist/{ResponseSection-DMJ0tw8E.js → ResponseSection-CLrgLMN_.js} +3 -3
- package/dist/{ResponseSection-DMJ0tw8E.js.map → ResponseSection-CLrgLMN_.js.map} +1 -1
- package/dist/{Server-DnA_BzPS.js → Server-BS4zjUdO.js} +2 -2
- package/dist/{Server-DnA_BzPS.js.map → Server-BS4zjUdO.js.map} +1 -1
- package/dist/{Settings-CYZzdJPO.js → Settings-BuLKHzRY.js} +2 -2
- package/dist/{Settings-CYZzdJPO.js.map → Settings-BuLKHzRY.js.map} +1 -1
- package/dist/{Sidebar-C6AdX6-N.js → Sidebar-Xl9_nFXX.js} +2 -2
- package/dist/{Sidebar-C6AdX6-N.js.map → Sidebar-Xl9_nFXX.js.map} +1 -1
- package/dist/components/AddressBar/index.js +3 -3
- package/dist/components/CodeInput/index.js +1 -1
- package/dist/components/CommandPalette/index.js +1 -1
- package/dist/components/DataTable/index.js +2 -2
- package/dist/components/ImportCollection/index.js +1 -1
- package/dist/components/Server/index.js +1 -1
- package/dist/components/Sidebar/index.js +1 -1
- package/dist/components/index.js +4 -4
- package/dist/{components-CSxJTn6F.js → components-DfJHvSLM.js} +2 -2
- package/dist/{components-CSxJTn6F.js.map → components-DfJHvSLM.js.map} +1 -1
- package/dist/get-resolved-url-SybDPV0U.js +85 -0
- package/dist/get-resolved-url-SybDPV0U.js.map +1 -0
- package/dist/{get-server-url-o3On8CEr.js → get-server-url-UVN-dx79.js} +1 -1
- package/dist/{get-server-url-o3On8CEr.js.map → get-server-url-UVN-dx79.js.map} +1 -1
- package/dist/index.js +5 -5
- package/dist/layouts/App/index.js +3 -3
- package/dist/layouts/Modal/index.js +1 -1
- package/dist/layouts/Web/index.js +4 -4
- package/dist/libs/index.js +1 -1
- package/dist/{operation-block-BnMIKAOh.js → operation-block-DE-hoO03.js} +67 -17
- package/dist/operation-block-DE-hoO03.js.map +1 -0
- package/dist/{operation-code-sample-ZUTueV3v.js → operation-code-sample-xgx4qi2H.js} +22 -10
- package/dist/operation-code-sample-xgx4qi2H.js.map +1 -0
- package/dist/{request-block-DwsGy64Q.js → request-block-N7dPFyrG.js} +4 -4
- package/dist/{request-block-DwsGy64Q.js.map → request-block-N7dPFyrG.js.map} +1 -1
- package/dist/{scalar-address-bar-block--Vs6IBU1.js → scalar-address-bar-block-BbysOhkE.js} +2 -2
- package/dist/{scalar-address-bar-block--Vs6IBU1.js.map → scalar-address-bar-block-BbysOhkE.js.map} +1 -1
- package/dist/{scalar-auth-selector-block-DI3DLag9.js → scalar-auth-selector-block-Bs79QOMA.js} +12 -9
- package/dist/scalar-auth-selector-block-Bs79QOMA.js.map +1 -0
- package/dist/store/index.js +1 -1
- package/dist/{store-DpSUVhjp.js → store-DaPoVtIS.js} +15 -15
- package/dist/{store-DpSUVhjp.js.map → store-DaPoVtIS.js.map} +1 -1
- package/dist/style.css +1 -1
- package/dist/v2/blocks/operation-block/OperationBlock.vue.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/helpers/apply-allow-reserved-to-url.d.ts +6 -0
- package/dist/v2/blocks/operation-block/helpers/apply-allow-reserved-to-url.d.ts.map +1 -0
- package/dist/v2/blocks/operation-block/helpers/build-request-body.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/helpers/build-request-parameters.d.ts +1 -0
- package/dist/v2/blocks/operation-block/helpers/build-request-parameters.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/helpers/build-request.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/helpers/get-resolved-url.d.ts +2 -1
- package/dist/v2/blocks/operation-block/helpers/get-resolved-url.d.ts.map +1 -1
- package/dist/v2/blocks/operation-block/index.js +11 -11
- package/dist/v2/blocks/operation-code-sample/helpers/operation-to-har/process-body.d.ts.map +1 -1
- package/dist/v2/blocks/operation-code-sample/index.js +1 -1
- package/dist/v2/blocks/request-block/helpers/get-default-headers.d.ts.map +1 -1
- package/dist/v2/blocks/request-block/index.js +5 -5
- package/dist/v2/blocks/response-block/index.js +2 -2
- package/dist/v2/blocks/scalar-address-bar-block/index.js +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/extract-security-scheme-secrets.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/helpers/security-scheme.d.ts.map +1 -1
- package/dist/v2/blocks/scalar-auth-selector-block/index.js +3 -3
- package/dist/v2/constants.d.ts +3 -0
- package/dist/v2/constants.d.ts.map +1 -0
- package/dist/v2/features/app/components/index.js +4 -4
- package/dist/v2/features/app/index.js +14 -14
- package/dist/v2/features/app/index.js.map +1 -1
- package/dist/v2/features/collection/components/Authentication.vue.d.ts.map +1 -1
- package/dist/v2/features/modal/index.js +10 -10
- package/dist/v2/features/operation/Operation.vue.d.ts.map +1 -1
- package/dist/v2/features/operation/helpers/get-selected-security.d.ts +6 -1
- package/dist/v2/features/operation/helpers/get-selected-security.d.ts.map +1 -1
- package/dist/v2/features/operation/index.js +10 -10
- package/dist/views/Request/RequestSection/RequestAuth/index.js +3 -3
- package/dist/views/Request/RequestSection/index.js +4 -4
- package/dist/views/Request/ResponseSection/index.js +3 -3
- package/dist/views/Request/components/index.js +1 -1
- package/package.json +13 -13
- package/dist/get-resolved-url-BUCwrBzc.js +0 -30
- package/dist/get-resolved-url-BUCwrBzc.js.map +0 -1
- package/dist/operation-block-BnMIKAOh.js.map +0 -1
- package/dist/operation-code-sample-ZUTueV3v.js.map +0 -1
- package/dist/scalar-auth-selector-block-DI3DLag9.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImportCollection-DfX1UQ5u.js","names":[],"sources":["../src/components/ImportCollection/utils/workspace-store-is-empty.ts","../src/components/ImportCollection/DropEventListener.vue","../src/components/ImportCollection/DropEventListener.vue","../src/components/ImportCollection/hooks/useUrlPrefetcher.ts","../src/components/ImportCollection/utils/is-url.ts","../src/components/ImportCollection/utils/import-collection.ts","../src/components/ImportCollection/ImportNowButton.vue","../src/components/ImportCollection/ImportNowButton.vue","../src/components/ImportCollection/PrefetchError.vue","../src/components/ImportCollection/PrefetchError.vue","../src/components/ImportCollection/utils/is-document.ts","../src/components/ImportCollection/utils/get-openapi-version.ts","../src/components/ImportCollection/WorkspaceSelector.vue","../src/components/ImportCollection/WorkspaceSelector.vue","../src/components/ImportCollection/ImportCollectionModal.vue","../src/components/ImportCollection/ImportCollectionModal.vue","../src/components/ImportCollection/PasteEventListener.vue","../src/components/ImportCollection/PasteEventListener.vue","../src/components/ImportCollection/UrlQueryParameterChecker.vue","../src/components/ImportCollection/UrlQueryParameterChecker.vue","../src/components/ImportCollection/ImportCollectionListener.vue","../src/components/ImportCollection/ImportCollectionListener.vue"],"sourcesContent":["import type { WorkspaceStore } from '@/store'\n\n/**\n * Checks whether the store is empty.\n */\nexport function workspaceStoreIsEmpty(store: WorkspaceStore) {\n const hasSingleWorkspace = Object.keys(store.workspaces).length === 1\n const hasSingleCollection = Object.keys(store.collections).length === 1\n\n return hasSingleWorkspace && hasSingleCollection\n}\n","<script lang=\"ts\" setup>\nimport { ScalarIcon } from '@scalar/components'\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'drop'): void\n}>()\n\nconst isDragging = ref<boolean>(false)\n\nlet dragCounter = 0\n\n// Register event listeners\nonMounted(() => {\n document.addEventListener('dragenter', handleDragEnter)\n document.addEventListener('dragleave', handleDragLeave)\n document.addEventListener('dragover', handleDragOver)\n document.addEventListener('drop', handleDrop)\n})\n\n// Unregister event listeners\nonBeforeUnmount(() => {\n document.removeEventListener('dragenter', handleDragEnter)\n document.removeEventListener('dragover', handleDragOver)\n document.removeEventListener('dragleave', handleDragLeave)\n document.removeEventListener('drop', handleDrop)\n})\n\nfunction isFromApp(event: DragEvent): boolean {\n return event.dataTransfer?.types.includes('text/html') ?? false\n}\n\n// Drop\nfunction handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragging.value = false\n dragCounter = 0\n\n // Prevent emitting for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n // Text\n const droppedText = event.dataTransfer.getData('text').replace(/^blob:/, '')\n\n if (droppedText) {\n emit('input', droppedText, null, 'drop')\n }\n // Files\n else if (event.dataTransfer.files.length > 0) {\n const file = event.dataTransfer.files[0]\n if (!file) {\n return\n }\n\n const reader = new FileReader()\n\n reader.onload = (e) => {\n if (e.target && typeof e.target.result === 'string') {\n emit('input', e.target.result, null, 'drop')\n }\n }\n\n reader.readAsText(file)\n }\n }\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n}\n\nfunction handleDragLeave(event: DragEvent) {\n event.preventDefault()\n dragCounter--\n\n if (dragCounter === 0) {\n isDragging.value = false\n }\n}\n\nfunction handleDragEnter(event: DragEvent) {\n event.preventDefault()\n dragCounter++\n\n // Prevent displaying the draggable UI for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n const items = event.dataTransfer.items\n for (const item of items) {\n if (\n item?.kind === 'string' ||\n item?.type?.includes('json') ||\n item?.type?.includes('yml') ||\n item?.type?.includes('yaml')\n ) {\n isDragging.value = true\n return\n }\n }\n }\n isDragging.value = false\n}\n</script>\n\n<template>\n <transition\n enterActiveClass=\"transition-opacity duration-200\"\n enterFromClass=\"opacity-0\"\n leaveActiveClass=\"transition-opacity duration-200\"\n leaveToClass=\"opacity-0\">\n <div\n v-if=\"isDragging\"\n class=\"bg-b-2 fixed right-1/2 bottom-1/2 z-50 h-64 w-64 translate-x-1/2 translate-y-1/2 rounded-xl border transition-opacity duration-200 md:right-10 md:bottom-10 md:translate-x-0 md:translate-y-0\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <div>\n <ScalarIcon\n icon=\"Download\"\n size=\"xl\"\n thickness=\"2\" />\n </div>\n <div class=\"text-c-1 m-4 text-center\">\n Drop your OpenAPI document here\n </div>\n </div>\n </div>\n </transition>\n</template>\n","<script lang=\"ts\" setup>\nimport { ScalarIcon } from '@scalar/components'\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'drop'): void\n}>()\n\nconst isDragging = ref<boolean>(false)\n\nlet dragCounter = 0\n\n// Register event listeners\nonMounted(() => {\n document.addEventListener('dragenter', handleDragEnter)\n document.addEventListener('dragleave', handleDragLeave)\n document.addEventListener('dragover', handleDragOver)\n document.addEventListener('drop', handleDrop)\n})\n\n// Unregister event listeners\nonBeforeUnmount(() => {\n document.removeEventListener('dragenter', handleDragEnter)\n document.removeEventListener('dragover', handleDragOver)\n document.removeEventListener('dragleave', handleDragLeave)\n document.removeEventListener('drop', handleDrop)\n})\n\nfunction isFromApp(event: DragEvent): boolean {\n return event.dataTransfer?.types.includes('text/html') ?? false\n}\n\n// Drop\nfunction handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragging.value = false\n dragCounter = 0\n\n // Prevent emitting for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n // Text\n const droppedText = event.dataTransfer.getData('text').replace(/^blob:/, '')\n\n if (droppedText) {\n emit('input', droppedText, null, 'drop')\n }\n // Files\n else if (event.dataTransfer.files.length > 0) {\n const file = event.dataTransfer.files[0]\n if (!file) {\n return\n }\n\n const reader = new FileReader()\n\n reader.onload = (e) => {\n if (e.target && typeof e.target.result === 'string') {\n emit('input', e.target.result, null, 'drop')\n }\n }\n\n reader.readAsText(file)\n }\n }\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n}\n\nfunction handleDragLeave(event: DragEvent) {\n event.preventDefault()\n dragCounter--\n\n if (dragCounter === 0) {\n isDragging.value = false\n }\n}\n\nfunction handleDragEnter(event: DragEvent) {\n event.preventDefault()\n dragCounter++\n\n // Prevent displaying the draggable UI for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n const items = event.dataTransfer.items\n for (const item of items) {\n if (\n item?.kind === 'string' ||\n item?.type?.includes('json') ||\n item?.type?.includes('yml') ||\n item?.type?.includes('yaml')\n ) {\n isDragging.value = true\n return\n }\n }\n }\n isDragging.value = false\n}\n</script>\n\n<template>\n <transition\n enterActiveClass=\"transition-opacity duration-200\"\n enterFromClass=\"opacity-0\"\n leaveActiveClass=\"transition-opacity duration-200\"\n leaveToClass=\"opacity-0\">\n <div\n v-if=\"isDragging\"\n class=\"bg-b-2 fixed right-1/2 bottom-1/2 z-50 h-64 w-64 translate-x-1/2 translate-y-1/2 rounded-xl border transition-opacity duration-200 md:right-10 md:bottom-10 md:translate-x-0 md:translate-y-0\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <div>\n <ScalarIcon\n icon=\"Download\"\n size=\"xl\"\n thickness=\"2\" />\n </div>\n <div class=\"text-c-1 m-4 text-center\">\n Drop your OpenAPI document here\n </div>\n </div>\n </div>\n </transition>\n</template>\n","import { redirectToProxy } from '@scalar/helpers/url/redirect-to-proxy'\nimport { resolve } from '@scalar/import'\nimport { fetchWithProxyFallback } from '@scalar/oas-utils/helpers'\nimport { reactive } from 'vue'\n\nimport { isUrl } from '@/libs'\n\ntype PrefetchResult = {\n state: 'idle' | 'loading'\n content: string | null\n input: string | null\n url: string | null\n error: string | null\n}\n\n/**\n * Vue composable for URL prefetching\n */\nexport function useUrlPrefetcher() {\n const prefetchResult = reactive<PrefetchResult>({\n state: 'idle',\n content: null,\n url: null,\n input: null,\n error: null,\n })\n\n function resetPrefetchResult() {\n Object.assign(prefetchResult, {\n state: 'idle',\n content: null,\n url: null,\n input: null,\n error: null,\n })\n }\n\n async function prefetchUrl(input: string | null, proxyUrl?: string) {\n if (!input) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: null,\n }\n }\n\n try {\n // If we try hard enough, we might find the actual OpenAPI document URL even if the input isn't one directly.\n const urlOrDocument = await resolve(input, {\n fetch: (url) => {\n return fetch(proxyUrl ? redirectToProxy(proxyUrl, url) : url, {\n cache: 'no-cache',\n })\n },\n })\n\n // If the input is an object, we're done\n if (typeof urlOrDocument === 'object' && urlOrDocument !== null) {\n const json = JSON.stringify(urlOrDocument, null, 2)\n\n return {\n state: 'idle',\n content: json,\n url: null,\n error: null,\n }\n }\n\n // Nothing was found.\n if (urlOrDocument === undefined) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: `Could not find an OpenAPI document in ${input}`,\n }\n }\n\n if (!isUrl(urlOrDocument)) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: 'Oops, we got invalid content for the given URL.',\n }\n }\n\n const url = urlOrDocument\n\n // Okay, we've got an URL. Let's fetch it:\n const result = await fetchWithProxyFallback(url, {\n proxyUrl,\n cache: 'no-cache',\n })\n\n if (!result.ok) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: `Couldn't fetch ${url}, got error ${[result.status, result.statusText].join(' ').trim()}.`,\n }\n }\n\n const content = await result.text()\n\n return {\n state: 'idle',\n content,\n url,\n error: null,\n }\n } catch (error: any) {\n console.error('[prefetchDocument]', error)\n\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: error.message,\n }\n }\n }\n\n async function prefetchUrlAndUpdateState(input: string | null, proxyUrl?: string) {\n Object.assign(prefetchResult, {\n state: 'loading',\n content: null,\n url: null,\n input,\n error: null,\n })\n\n const result = await prefetchUrl(input, proxyUrl)\n Object.assign(prefetchResult, result)\n return result\n }\n\n return {\n prefetchResult,\n prefetchUrl: prefetchUrlAndUpdateState,\n resetPrefetchResult,\n }\n}\n","/**\n * Checks whether the given string is an URL\n **/\nexport function isUrl(input: string | null): boolean {\n // Quick check for null or undefined\n if (!input) {\n return false\n }\n\n // Trim whitespace\n const trimmed = input.trim()\n\n // If it's an URL, it must start with http:// or https://\n if (!trimmed.startsWith('http://') && !trimmed.startsWith('https://')) {\n return false\n }\n\n // But it must have more than just the protocol\n return trimmed.replace(/^https?:\\/\\//, '').length > 0\n}\n","import type { Collection } from '@scalar/oas-utils/entities/spec'\nimport type { Workspace } from '@scalar/oas-utils/entities/workspace'\n\nimport { isUrl } from '@/components/ImportCollection/utils/is-url'\nimport type { WorkspaceStore } from '@/store'\n\nexport async function importCollection({\n store,\n workspace,\n source,\n watchMode,\n onSuccess,\n onError,\n}: {\n store: WorkspaceStore\n workspace: Workspace | undefined\n source: string | null | undefined\n watchMode: boolean\n onSuccess: (collection: Collection | undefined) => void\n onError: (error: Error) => void\n}) {\n try {\n if (source && workspace) {\n if (isUrl(source)) {\n const [error, entities] = await store.importSpecFromUrl(source, workspace.uid, {\n proxyUrl: workspace.proxyUrl,\n watchMode: watchMode,\n })\n\n if (!error) {\n onSuccess(entities?.collection)\n }\n\n return\n }\n\n const entities = await store.importSpecFile(source, workspace.uid)\n\n onSuccess(entities?.collection)\n }\n } catch (error) {\n onError(error as Error)\n }\n}\n","<script lang=\"ts\" setup>\nimport { ScalarButton } from '@scalar/components'\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport { importCollection } from './utils/import-collection'\n\nconst { source, watchMode = true } = defineProps<{\n source?: string | null\n variant?: 'button' | 'link'\n watchMode?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst router = useRouter()\nconst store = useWorkspace()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection() {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source: source,\n watchMode: watchMode,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n emit('importFinished')\n }\n },\n onError(error) {\n console.error('[importCollection]', error)\n\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n },\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <template v-if=\"source\">\n <!-- Button -->\n <ScalarButton\n v-if=\"variant === 'button'\"\n class=\"mt-3 h-fit w-full rounded-lg px-6 py-2.5 font-bold\"\n size=\"md\"\n type=\"button\"\n @click=\"handleImportCollection\">\n Import Collection\n </ScalarButton>\n <!-- Link -->\n <ScalarButton\n v-else\n class=\"h-fit rounded-lg px-6 py-2.5 text-[21px] font-bold\"\n size=\"md\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"handleImportCollection\">\n Try it in the browser\n </ScalarButton>\n <!-- <a\n v-else\n class=\"no-underline text-sm\"\n href=\"#\"\n @click=\"importCollection\">\n Try it in the browser\n </a> -->\n </template>\n</template>\n","<script lang=\"ts\" setup>\nimport { ScalarButton } from '@scalar/components'\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport { importCollection } from './utils/import-collection'\n\nconst { source, watchMode = true } = defineProps<{\n source?: string | null\n variant?: 'button' | 'link'\n watchMode?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst router = useRouter()\nconst store = useWorkspace()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection() {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source: source,\n watchMode: watchMode,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n emit('importFinished')\n }\n },\n onError(error) {\n console.error('[importCollection]', error)\n\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n },\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <template v-if=\"source\">\n <!-- Button -->\n <ScalarButton\n v-if=\"variant === 'button'\"\n class=\"mt-3 h-fit w-full rounded-lg px-6 py-2.5 font-bold\"\n size=\"md\"\n type=\"button\"\n @click=\"handleImportCollection\">\n Import Collection\n </ScalarButton>\n <!-- Link -->\n <ScalarButton\n v-else\n class=\"h-fit rounded-lg px-6 py-2.5 text-[21px] font-bold\"\n size=\"md\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"handleImportCollection\">\n Try it in the browser\n </ScalarButton>\n <!-- <a\n v-else\n class=\"no-underline text-sm\"\n href=\"#\"\n @click=\"importCollection\">\n Try it in the browser\n </a> -->\n </template>\n</template>\n","<script setup lang=\"ts\">\nimport { isUrl } from '@/libs'\n\ndefineProps<{\n url?: string | null\n}>()\n</script>\n\n<template>\n <div class=\"w-full text-center text-sm font-medium break-words\">\n We couldn't find an OpenAPI document at the provided URL. Please download\n and import the\n <a\n v-if=\"url && isUrl(url)\"\n :href=\"url\"\n rel=\"noopener nofollow\"\n target=\"_blank\"\n v-text=\"'OpenAPI document manually'\" />\n <span\n v-else\n v-text=\"'OpenAPI document manually'\" />.\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { isUrl } from '@/libs'\n\ndefineProps<{\n url?: string | null\n}>()\n</script>\n\n<template>\n <div class=\"w-full text-center text-sm font-medium break-words\">\n We couldn't find an OpenAPI document at the provided URL. Please download\n and import the\n <a\n v-if=\"url && isUrl(url)\"\n :href=\"url\"\n rel=\"noopener nofollow\"\n target=\"_blank\"\n v-text=\"'OpenAPI document manually'\" />\n <span\n v-else\n v-text=\"'OpenAPI document manually'\" />.\n </div>\n</template>\n","/** Checks whether the given string could be an OpenAPI document */\nexport function isDocument(input: string | null): boolean {\n // Return false for null, undefined, empty strings, or whitespace-only strings\n if (!input || input.trim().length === 0) {\n return false\n }\n\n const trimmed = input.trim()\n\n // Return false if it looks like a URL (starts with http:// or https://)\n if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {\n return false\n }\n\n return true\n}\n","import { parse } from 'yaml'\n\nimport { isDocument } from './is-document'\n\n/**\n * Get the Swagger/OpenAPI version and format from the given string\n */\nexport function getOpenApiVersion(input: string | null) {\n if (!isDocument(input)) {\n return false\n }\n\n try {\n const result = JSON.parse(input ?? '')\n\n if (typeof result?.openapi === 'string') {\n return `OpenAPI ${result.openapi} JSON`\n }\n\n if (typeof result?.swagger === 'string') {\n return `Swagger ${result.swagger} JSON`\n }\n\n return false\n } catch {\n //\n }\n\n try {\n const result = parse(input ?? '')\n\n if (typeof result?.openapi === 'string') {\n return `OpenAPI ${result.openapi} YAML`\n }\n\n if (typeof result?.swagger === 'string') {\n return `Swagger ${result.swagger} YAML`\n }\n\n return false\n } catch {\n //\n }\n\n return false\n}\n","<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n ScalarModal,\n useModal,\n} from '@scalar/components'\nimport { useToasts } from '@scalar/use-toasts'\nimport { ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaces, workspaceMutators } = useWorkspace()\nconst { push } = useRouter()\n\nconst modal = useModal()\nconst { toast } = useToasts()\nconst workspaceName = ref('')\n\nconst updateSelected = (uid: string) => {\n if (uid === activeWorkspace.value?.uid) {\n return\n }\n\n push({\n name: 'workspace',\n params: {\n workspace: uid,\n },\n })\n}\n\nconst handleCreateWorkspace = () => {\n if (!workspaceName.value.trim()) {\n toast('Please enter a name before creating a workspace.', 'error')\n return\n }\n\n const newWorkspace = workspaceMutators.add({\n name: workspaceName.value,\n })\n\n toast(`Created new workspace '${newWorkspace.name}'`)\n\n push({\n name: 'workspace',\n params: {\n workspace: newWorkspace.uid,\n },\n })\n\n workspaceName.value = ''\n modal.hide()\n}\n</script>\n<template>\n <div class=\"flex w-[inherit] items-center text-base\">\n <ScalarDropdown>\n <ScalarButton\n class=\"hover:bg-b-2 text-c-3 line-clamp-1 h-full w-fit justify-start px-1.5 py-1 font-normal\"\n variant=\"ghost\">\n <div class=\"m-0 flex items-center gap-1 text-sm font-medium\">\n <h2 class=\"line-clamp-1 w-[calc(100%-10px)] text-left text-xs\">\n {{ activeWorkspace?.name }}\n </h2>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </div>\n </ScalarButton>\n\n <!-- Workspace list -->\n <template #items>\n <ScalarDropdownItem\n v-for=\"(workspace, uid) in workspaces\"\n :key=\"uid\"\n class=\"group/item flex w-full items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"updateSelected(uid)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeWorkspace?.uid === uid\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"overflow-hidden text-ellipsis\">{{\n workspace.name\n }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider />\n\n <!-- Add new workspace -->\n <ScalarDropdownItem\n class=\"flex items-center gap-1.5\"\n @click=\"modal.show()\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>New Workspace</span>\n </ScalarDropdownItem>\n </template>\n </ScalarDropdown>\n </div>\n <ScalarModal\n bodyClass=\"m-0 p-1 rounded-lg border-t-0\"\n class=\"z-overlay absolute\"\n :size=\"'xxs'\"\n :state=\"modal\"\n variant=\"form\">\n <form\n class=\"flex gap-1\"\n @submit.prevent=\"handleCreateWorkspace\">\n <input\n v-model=\"workspaceName\"\n class=\"min-h-8 w-full flex-1 border-none p-1.5 text-sm outline-none\"\n placeholder=\"New Workspace\"\n type=\"text\" />\n <ScalarButton\n class=\"max-h-8 p-0 px-3 text-xs\"\n :disabled=\"!workspaceName.trim()\"\n type=\"submit\">\n Continue\n </ScalarButton>\n </form>\n </ScalarModal>\n</template>\n","<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n ScalarModal,\n useModal,\n} from '@scalar/components'\nimport { useToasts } from '@scalar/use-toasts'\nimport { ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaces, workspaceMutators } = useWorkspace()\nconst { push } = useRouter()\n\nconst modal = useModal()\nconst { toast } = useToasts()\nconst workspaceName = ref('')\n\nconst updateSelected = (uid: string) => {\n if (uid === activeWorkspace.value?.uid) {\n return\n }\n\n push({\n name: 'workspace',\n params: {\n workspace: uid,\n },\n })\n}\n\nconst handleCreateWorkspace = () => {\n if (!workspaceName.value.trim()) {\n toast('Please enter a name before creating a workspace.', 'error')\n return\n }\n\n const newWorkspace = workspaceMutators.add({\n name: workspaceName.value,\n })\n\n toast(`Created new workspace '${newWorkspace.name}'`)\n\n push({\n name: 'workspace',\n params: {\n workspace: newWorkspace.uid,\n },\n })\n\n workspaceName.value = ''\n modal.hide()\n}\n</script>\n<template>\n <div class=\"flex w-[inherit] items-center text-base\">\n <ScalarDropdown>\n <ScalarButton\n class=\"hover:bg-b-2 text-c-3 line-clamp-1 h-full w-fit justify-start px-1.5 py-1 font-normal\"\n variant=\"ghost\">\n <div class=\"m-0 flex items-center gap-1 text-sm font-medium\">\n <h2 class=\"line-clamp-1 w-[calc(100%-10px)] text-left text-xs\">\n {{ activeWorkspace?.name }}\n </h2>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </div>\n </ScalarButton>\n\n <!-- Workspace list -->\n <template #items>\n <ScalarDropdownItem\n v-for=\"(workspace, uid) in workspaces\"\n :key=\"uid\"\n class=\"group/item flex w-full items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"updateSelected(uid)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeWorkspace?.uid === uid\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"overflow-hidden text-ellipsis\">{{\n workspace.name\n }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider />\n\n <!-- Add new workspace -->\n <ScalarDropdownItem\n class=\"flex items-center gap-1.5\"\n @click=\"modal.show()\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>New Workspace</span>\n </ScalarDropdownItem>\n </template>\n </ScalarDropdown>\n </div>\n <ScalarModal\n bodyClass=\"m-0 p-1 rounded-lg border-t-0\"\n class=\"z-overlay absolute\"\n :size=\"'xxs'\"\n :state=\"modal\"\n variant=\"form\">\n <form\n class=\"flex gap-1\"\n @submit.prevent=\"handleCreateWorkspace\">\n <input\n v-model=\"workspaceName\"\n class=\"min-h-8 w-full flex-1 border-none p-1.5 text-sm outline-none\"\n placeholder=\"New Workspace\"\n type=\"text\" />\n <ScalarButton\n class=\"max-h-8 p-0 px-3 text-xs\"\n :disabled=\"!workspaceName.trim()\"\n type=\"submit\">\n Continue\n </ScalarButton>\n </form>\n </ScalarModal>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon, ScalarModal, useModal } from '@scalar/components'\nimport { isLocalUrl } from '@scalar/oas-utils/helpers'\nimport { normalize } from '@scalar/openapi-parser'\nimport type { OpenAPI } from '@scalar/openapi-types'\nimport {\n getThemeStyles,\n themeIds,\n type IntegrationThemeId,\n} from '@scalar/themes'\nimport { useColorMode } from '@scalar/use-hooks/useColorMode'\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport WatchModeToggle from '@/components/CommandPalette/WatchModeToggle.vue'\nimport { useUrlPrefetcher } from '@/components/ImportCollection/hooks/useUrlPrefetcher'\nimport ImportNowButton from '@/components/ImportCollection/ImportNowButton.vue'\nimport IntegrationLogo from '@/components/ImportCollection/IntegrationLogo.vue'\nimport PrefetchError from '@/components/ImportCollection/PrefetchError.vue'\nimport { getOpenApiVersion } from '@/components/ImportCollection/utils/get-openapi-version'\nimport { isDocument } from '@/components/ImportCollection/utils/is-document'\nimport { isUrl } from '@/components/ImportCollection/utils/is-url'\nimport WorkspaceSelector from '@/components/ImportCollection/WorkspaceSelector.vue'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst props = defineProps<{\n source: string | null\n integration: string | null\n eventType: 'drop' | 'paste' | 'query' | null\n}>()\n\nconst emits = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaceMutators, events } = useWorkspace()\n\nconst { prefetchResult, prefetchUrl, resetPrefetchResult } = useUrlPrefetcher()\n\nconst modalState = useModal()\n\nconst watchMode = ref<boolean>(true)\n\n/** Close modal when a keyboard shortcut is pressed */\nevents.hotKeys.on(() => modalState.hide())\n\n/** Try to make the retrieved content an OpenAPI document */\nconst openApiDocument = computed(() => {\n try {\n return normalize(\n prefetchResult.content || props.source || '',\n ) as OpenAPI.Document\n } catch {\n return undefined\n }\n})\n\n/** Title from the OpenAPI document */\nconst title = computed(() => openApiDocument.value?.info?.title)\n\n/** The OpenAPI/Swagger version */\nconst version = computed(() =>\n getOpenApiVersion(prefetchResult.content || props.source || ''),\n)\n\nconst { darkLightMode } = useColorMode()\nconst { currentRoute } = useRouter()\n\n/** Grab light and dark logos from the url query params */\nconst companyLogo = computed(() => {\n try {\n const query = currentRoute.value.query\n const logo =\n darkLightMode.value === 'dark' ? query.dark_logo : query.light_logo\n\n if (logo) {\n return decodeURIComponent(logo as string)\n }\n } catch {\n // No harm no foul\n }\n\n return null\n})\n\n/** Open/close modal on events */\nwatch(\n () => props.source,\n async (value) => {\n resetPrefetchResult()\n\n if (isUrl(value)) {\n // For drop & paste events only:\n const isDropOrPasteEvent =\n props.eventType && ['paste', 'drop'].includes(props.eventType)\n\n if (isDropOrPasteEvent) {\n // Check whether the URL is pointing to an OpenAPI document\n const { error } = await prefetchUrl(\n value,\n activeWorkspace.value?.proxyUrl,\n )\n\n if (error) {\n modalState.hide()\n } else {\n modalState.show()\n }\n\n return\n }\n\n // Query parameters:\n void prefetchUrl(value, activeWorkspace.value?.proxyUrl)\n\n modalState.show()\n\n return\n }\n\n if (!value) {\n modalState.hide()\n } else if (isDocument(value) && getOpenApiVersion(value)) {\n modalState.show()\n } else {\n modalState.hide()\n }\n },\n)\n\nconst hasUrl = computed(() => !!props.source && isUrl(props.source))\nconst hasContent = computed(() => !!props.source && isDocument(props.source))\n\n/** Show the integration icon only for local URLs */\nconst shouldShowIntegrationIcon = computed(() => {\n return prefetchResult.url && isLocalUrl(prefetchResult.url)\n})\n\n// Function to add/remove class from body\nconst toggleBodyClass = (add: boolean) => {\n document.body.classList.remove('has-no-import-url')\n\n if (add && (hasUrl.value || hasContent.value) && modalState.open) {\n document.body.classList.add('has-import-url')\n } else {\n document.body.classList.remove('has-import-url')\n }\n}\n\n/** Toggles the 'has-import-url' class on the body element */\nconst closeModal = () => {\n document.body.classList.remove('has-import-url')\n document.body.classList.add('has-no-import-url')\n}\n\n// Watch for changes in the modal state\nwatch(\n () => modalState.open,\n (isOpen) => {\n if (isOpen) {\n toggleBodyClass(true)\n } else {\n closeModal()\n }\n },\n)\n\n// Watch for changes in the source prop\nwatch(\n () => props.source,\n () => {\n toggleBodyClass(true)\n },\n)\n\n// Add class on mount if URL exists and modal is visible\nonMounted(() => {\n toggleBodyClass(true)\n})\n\n// Remove classes on unmount\nonUnmounted(() => {\n document.body.classList.remove('has-import-url')\n document.body.classList.remove('has-no-import-url')\n})\nconst themeStyleTag = computed(\n () =>\n activeWorkspace.value &&\n shouldShowIntegrationIcon.value &&\n props.integration &&\n `<style>${getThemeStyles(props.integration as IntegrationThemeId)}</style>`,\n)\n\nfunction handleImportFinished() {\n // If the integration is not a valid theme id, set the theme to default\n const isIntegrationThemeId = (value: string): value is IntegrationThemeId =>\n themeIds.includes(value as IntegrationThemeId)\n\n const integrationThemeId =\n props.integration && isIntegrationThemeId(props.integration)\n ? props.integration\n : 'default'\n\n if (shouldShowIntegrationIcon.value) {\n workspaceMutators.edit(\n activeWorkspace.value?.uid,\n 'themeId',\n integrationThemeId,\n )\n }\n emits('importFinished')\n}\n</script>\n\n<template>\n <ScalarModal\n size=\"full\"\n :state=\"modalState\">\n <div\n v-if=\"themeStyleTag\"\n v-html=\"themeStyleTag\" />\n <div\n class=\"relative flex h-screen flex-col justify-center overflow-hidden px-6 md:px-0\">\n <div class=\"section-flare\">\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n </div>\n <!-- Wait until the URL is fetched -->\n <div\n class=\"m-auto flex w-full max-w-[380px] flex-col items-center rounded-xl border px-8 py-8 transition-opacity\"\n :class=\"{ 'opacity-0': prefetchResult.state === 'loading' }\">\n <!-- Prefetch error -->\n <!-- Or: Document doesn't even have an OpenAPI/Swagger version, something is probably wrong -->\n <template\n v-if=\"\n prefetchResult.error && prefetchResult.state === 'idle' && !version\n \">\n <!-- Heading -->\n <div class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n No OpenAPI document found\n </div>\n <PrefetchError :url=\"prefetchResult?.input || props.source\" />\n </template>\n <!-- Success -->\n <template v-else>\n <!-- Integration Logo -->\n <div\n v-if=\"shouldShowIntegrationIcon\"\n class=\"mb-2 flex items-center justify-center p-1\">\n <div class=\"size-10 rounded-xl\">\n <IntegrationLogo :integration=\"integration\" />\n </div>\n </div>\n\n <!-- Company Logo -->\n <img\n v-else-if=\"companyLogo\"\n alt=\"Logo\"\n class=\"mb-2 w-full object-contain\"\n :src=\"companyLogo\" />\n\n <!-- Title -->\n <div\n v-if=\"!companyLogo\"\n class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n {{ title || 'Untitled Collection' }}\n </div>\n\n <div class=\"text-c-1 text-center text-sm font-medium text-balance\">\n Import the OpenAPI document to instantly send API requests. No\n signup required.\n </div>\n\n <!-- Actions -->\n <template v-if=\"version\">\n <div class=\"z-10 inline-flex w-full flex-col items-center gap-2\">\n <ImportNowButton\n :source=\"\n prefetchResult?.url ?? prefetchResult?.content ?? source\n \"\n variant=\"button\"\n :watchMode=\"watchMode\"\n @importFinished=\"handleImportFinished\" />\n </div>\n <!-- Select the workspace -->\n <div class=\"flex justify-center\">\n <div\n class=\"text-c-3 inline-flex items-center px-4 py-1 text-xs font-medium\">\n Import to: <WorkspaceSelector />\n </div>\n </div>\n <!-- Watch Mode -->\n <template v-if=\"prefetchResult?.url\">\n <div class=\"mt-5 overflow-hidden border-t pt-4 text-sm\">\n <div class=\"flex items-center justify-center\">\n <WatchModeToggle\n v-model=\"watchMode\"\n :disableToolTip=\"true\" />\n </div>\n <div\n class=\"text-c-3 pt-0 text-center text-xs font-medium text-balance\">\n Automatically update your API client when the OpenAPI document\n content changes.\n </div>\n </div>\n </template>\n </template>\n </template>\n </div>\n <!-- Download Link -->\n <div class=\"flex flex-col items-center justify-center pb-8\">\n <div class=\"flex flex-col items-center text-center\">\n <div\n class=\"mb-2 flex h-10 w-10 items-center justify-center rounded-[10px] border\">\n <a\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n </div>\n <span class=\"text-c-2 text-sm leading-snug font-medium\">\n <a\n class=\"hover:text-c-1 mb-1 inline-block underline-offset-2\"\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n Download Desktop App\n </a>\n <br />\n free · open-source · offline first\n </span>\n </div>\n </div>\n </div>\n </ScalarModal>\n</template>\n<style>\n@reference \"@/style.css\";\n\n@variant md {\n .has-no-import-url,\n .has-import-url {\n max-width: 100dvw;\n overflow-x: hidden;\n contain: paint;\n }\n .has-no-import-url .scalar-client > main {\n opacity: 1;\n background: var(--scalar-background-1);\n animation: transform-restore-layout ease-in-out 0.3s forwards;\n }\n .has-import-url .scalar-client > main {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n animation: transform-fade-layout ease-in-out 0.3s forwards;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: 12px;\n overflow: hidden;\n z-index: 10000;\n }\n .has-import-url .scalar-client .sidenav {\n display: none;\n }\n .has-no-import-url .scalar-app,\n .has-import-url .scalar-app {\n background: var(--scalar-background-1) !important;\n }\n}\n@keyframes transform-fade-layout {\n 0% {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 10px, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n}\n@keyframes transform-restore-layout {\n 0% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(1) translate3d(0, 0, 0);\n }\n}\n.openapi-color {\n color: var(--scalar-color-green);\n}\n.section-flare {\n position: fixed;\n top: 0;\n right: -50dvw;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ScalarIcon, ScalarModal, useModal } from '@scalar/components'\nimport { isLocalUrl } from '@scalar/oas-utils/helpers'\nimport { normalize } from '@scalar/openapi-parser'\nimport type { OpenAPI } from '@scalar/openapi-types'\nimport {\n getThemeStyles,\n themeIds,\n type IntegrationThemeId,\n} from '@scalar/themes'\nimport { useColorMode } from '@scalar/use-hooks/useColorMode'\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport WatchModeToggle from '@/components/CommandPalette/WatchModeToggle.vue'\nimport { useUrlPrefetcher } from '@/components/ImportCollection/hooks/useUrlPrefetcher'\nimport ImportNowButton from '@/components/ImportCollection/ImportNowButton.vue'\nimport IntegrationLogo from '@/components/ImportCollection/IntegrationLogo.vue'\nimport PrefetchError from '@/components/ImportCollection/PrefetchError.vue'\nimport { getOpenApiVersion } from '@/components/ImportCollection/utils/get-openapi-version'\nimport { isDocument } from '@/components/ImportCollection/utils/is-document'\nimport { isUrl } from '@/components/ImportCollection/utils/is-url'\nimport WorkspaceSelector from '@/components/ImportCollection/WorkspaceSelector.vue'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst props = defineProps<{\n source: string | null\n integration: string | null\n eventType: 'drop' | 'paste' | 'query' | null\n}>()\n\nconst emits = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaceMutators, events } = useWorkspace()\n\nconst { prefetchResult, prefetchUrl, resetPrefetchResult } = useUrlPrefetcher()\n\nconst modalState = useModal()\n\nconst watchMode = ref<boolean>(true)\n\n/** Close modal when a keyboard shortcut is pressed */\nevents.hotKeys.on(() => modalState.hide())\n\n/** Try to make the retrieved content an OpenAPI document */\nconst openApiDocument = computed(() => {\n try {\n return normalize(\n prefetchResult.content || props.source || '',\n ) as OpenAPI.Document\n } catch {\n return undefined\n }\n})\n\n/** Title from the OpenAPI document */\nconst title = computed(() => openApiDocument.value?.info?.title)\n\n/** The OpenAPI/Swagger version */\nconst version = computed(() =>\n getOpenApiVersion(prefetchResult.content || props.source || ''),\n)\n\nconst { darkLightMode } = useColorMode()\nconst { currentRoute } = useRouter()\n\n/** Grab light and dark logos from the url query params */\nconst companyLogo = computed(() => {\n try {\n const query = currentRoute.value.query\n const logo =\n darkLightMode.value === 'dark' ? query.dark_logo : query.light_logo\n\n if (logo) {\n return decodeURIComponent(logo as string)\n }\n } catch {\n // No harm no foul\n }\n\n return null\n})\n\n/** Open/close modal on events */\nwatch(\n () => props.source,\n async (value) => {\n resetPrefetchResult()\n\n if (isUrl(value)) {\n // For drop & paste events only:\n const isDropOrPasteEvent =\n props.eventType && ['paste', 'drop'].includes(props.eventType)\n\n if (isDropOrPasteEvent) {\n // Check whether the URL is pointing to an OpenAPI document\n const { error } = await prefetchUrl(\n value,\n activeWorkspace.value?.proxyUrl,\n )\n\n if (error) {\n modalState.hide()\n } else {\n modalState.show()\n }\n\n return\n }\n\n // Query parameters:\n void prefetchUrl(value, activeWorkspace.value?.proxyUrl)\n\n modalState.show()\n\n return\n }\n\n if (!value) {\n modalState.hide()\n } else if (isDocument(value) && getOpenApiVersion(value)) {\n modalState.show()\n } else {\n modalState.hide()\n }\n },\n)\n\nconst hasUrl = computed(() => !!props.source && isUrl(props.source))\nconst hasContent = computed(() => !!props.source && isDocument(props.source))\n\n/** Show the integration icon only for local URLs */\nconst shouldShowIntegrationIcon = computed(() => {\n return prefetchResult.url && isLocalUrl(prefetchResult.url)\n})\n\n// Function to add/remove class from body\nconst toggleBodyClass = (add: boolean) => {\n document.body.classList.remove('has-no-import-url')\n\n if (add && (hasUrl.value || hasContent.value) && modalState.open) {\n document.body.classList.add('has-import-url')\n } else {\n document.body.classList.remove('has-import-url')\n }\n}\n\n/** Toggles the 'has-import-url' class on the body element */\nconst closeModal = () => {\n document.body.classList.remove('has-import-url')\n document.body.classList.add('has-no-import-url')\n}\n\n// Watch for changes in the modal state\nwatch(\n () => modalState.open,\n (isOpen) => {\n if (isOpen) {\n toggleBodyClass(true)\n } else {\n closeModal()\n }\n },\n)\n\n// Watch for changes in the source prop\nwatch(\n () => props.source,\n () => {\n toggleBodyClass(true)\n },\n)\n\n// Add class on mount if URL exists and modal is visible\nonMounted(() => {\n toggleBodyClass(true)\n})\n\n// Remove classes on unmount\nonUnmounted(() => {\n document.body.classList.remove('has-import-url')\n document.body.classList.remove('has-no-import-url')\n})\nconst themeStyleTag = computed(\n () =>\n activeWorkspace.value &&\n shouldShowIntegrationIcon.value &&\n props.integration &&\n `<style>${getThemeStyles(props.integration as IntegrationThemeId)}</style>`,\n)\n\nfunction handleImportFinished() {\n // If the integration is not a valid theme id, set the theme to default\n const isIntegrationThemeId = (value: string): value is IntegrationThemeId =>\n themeIds.includes(value as IntegrationThemeId)\n\n const integrationThemeId =\n props.integration && isIntegrationThemeId(props.integration)\n ? props.integration\n : 'default'\n\n if (shouldShowIntegrationIcon.value) {\n workspaceMutators.edit(\n activeWorkspace.value?.uid,\n 'themeId',\n integrationThemeId,\n )\n }\n emits('importFinished')\n}\n</script>\n\n<template>\n <ScalarModal\n size=\"full\"\n :state=\"modalState\">\n <div\n v-if=\"themeStyleTag\"\n v-html=\"themeStyleTag\" />\n <div\n class=\"relative flex h-screen flex-col justify-center overflow-hidden px-6 md:px-0\">\n <div class=\"section-flare\">\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n </div>\n <!-- Wait until the URL is fetched -->\n <div\n class=\"m-auto flex w-full max-w-[380px] flex-col items-center rounded-xl border px-8 py-8 transition-opacity\"\n :class=\"{ 'opacity-0': prefetchResult.state === 'loading' }\">\n <!-- Prefetch error -->\n <!-- Or: Document doesn't even have an OpenAPI/Swagger version, something is probably wrong -->\n <template\n v-if=\"\n prefetchResult.error && prefetchResult.state === 'idle' && !version\n \">\n <!-- Heading -->\n <div class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n No OpenAPI document found\n </div>\n <PrefetchError :url=\"prefetchResult?.input || props.source\" />\n </template>\n <!-- Success -->\n <template v-else>\n <!-- Integration Logo -->\n <div\n v-if=\"shouldShowIntegrationIcon\"\n class=\"mb-2 flex items-center justify-center p-1\">\n <div class=\"size-10 rounded-xl\">\n <IntegrationLogo :integration=\"integration\" />\n </div>\n </div>\n\n <!-- Company Logo -->\n <img\n v-else-if=\"companyLogo\"\n alt=\"Logo\"\n class=\"mb-2 w-full object-contain\"\n :src=\"companyLogo\" />\n\n <!-- Title -->\n <div\n v-if=\"!companyLogo\"\n class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n {{ title || 'Untitled Collection' }}\n </div>\n\n <div class=\"text-c-1 text-center text-sm font-medium text-balance\">\n Import the OpenAPI document to instantly send API requests. No\n signup required.\n </div>\n\n <!-- Actions -->\n <template v-if=\"version\">\n <div class=\"z-10 inline-flex w-full flex-col items-center gap-2\">\n <ImportNowButton\n :source=\"\n prefetchResult?.url ?? prefetchResult?.content ?? source\n \"\n variant=\"button\"\n :watchMode=\"watchMode\"\n @importFinished=\"handleImportFinished\" />\n </div>\n <!-- Select the workspace -->\n <div class=\"flex justify-center\">\n <div\n class=\"text-c-3 inline-flex items-center px-4 py-1 text-xs font-medium\">\n Import to: <WorkspaceSelector />\n </div>\n </div>\n <!-- Watch Mode -->\n <template v-if=\"prefetchResult?.url\">\n <div class=\"mt-5 overflow-hidden border-t pt-4 text-sm\">\n <div class=\"flex items-center justify-center\">\n <WatchModeToggle\n v-model=\"watchMode\"\n :disableToolTip=\"true\" />\n </div>\n <div\n class=\"text-c-3 pt-0 text-center text-xs font-medium text-balance\">\n Automatically update your API client when the OpenAPI document\n content changes.\n </div>\n </div>\n </template>\n </template>\n </template>\n </div>\n <!-- Download Link -->\n <div class=\"flex flex-col items-center justify-center pb-8\">\n <div class=\"flex flex-col items-center text-center\">\n <div\n class=\"mb-2 flex h-10 w-10 items-center justify-center rounded-[10px] border\">\n <a\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n </div>\n <span class=\"text-c-2 text-sm leading-snug font-medium\">\n <a\n class=\"hover:text-c-1 mb-1 inline-block underline-offset-2\"\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n Download Desktop App\n </a>\n <br />\n free · open-source · offline first\n </span>\n </div>\n </div>\n </div>\n </ScalarModal>\n</template>\n<style>\n@reference \"@/style.css\";\n\n@variant md {\n .has-no-import-url,\n .has-import-url {\n max-width: 100dvw;\n overflow-x: hidden;\n contain: paint;\n }\n .has-no-import-url .scalar-client > main {\n opacity: 1;\n background: var(--scalar-background-1);\n animation: transform-restore-layout ease-in-out 0.3s forwards;\n }\n .has-import-url .scalar-client > main {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n animation: transform-fade-layout ease-in-out 0.3s forwards;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: 12px;\n overflow: hidden;\n z-index: 10000;\n }\n .has-import-url .scalar-client .sidenav {\n display: none;\n }\n .has-no-import-url .scalar-app,\n .has-import-url .scalar-app {\n background: var(--scalar-background-1) !important;\n }\n}\n@keyframes transform-fade-layout {\n 0% {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 10px, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n}\n@keyframes transform-restore-layout {\n 0% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(1) translate3d(0, 0, 0);\n }\n}\n.openapi-color {\n color: var(--scalar-color-green);\n}\n.section-flare {\n position: fixed;\n top: 0;\n right: -50dvw;\n}\n</style>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onBeforeUnmount, onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'paste'): void\n}>()\n\n// Register event listener\nonMounted(() => {\n document.addEventListener('paste', handlePaste)\n})\n\n// Unregister event listener\nonBeforeUnmount(() => {\n document.removeEventListener('paste', handlePaste)\n})\n\n// Handle the paste event\nfunction handlePaste(event: ClipboardEvent) {\n // Ignore paste events in input, textarea, or contenteditable elements\n const target = event.target as HTMLElement\n\n // Check if we're inside a CodeMirror instance\n const isCodeMirror = Boolean(\n document.activeElement?.classList.contains('cm-content'),\n )\n\n if (\n target &&\n (target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable ||\n isCodeMirror)\n ) {\n return\n }\n\n // Emit the clipboard text content\n if (event.clipboardData) {\n const pastedText = event.clipboardData.getData('text')\n\n if (pastedText) {\n emit('input', pastedText, null, 'paste')\n }\n }\n}\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onBeforeUnmount, onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'paste'): void\n}>()\n\n// Register event listener\nonMounted(() => {\n document.addEventListener('paste', handlePaste)\n})\n\n// Unregister event listener\nonBeforeUnmount(() => {\n document.removeEventListener('paste', handlePaste)\n})\n\n// Handle the paste event\nfunction handlePaste(event: ClipboardEvent) {\n // Ignore paste events in input, textarea, or contenteditable elements\n const target = event.target as HTMLElement\n\n // Check if we're inside a CodeMirror instance\n const isCodeMirror = Boolean(\n document.activeElement?.classList.contains('cm-content'),\n )\n\n if (\n target &&\n (target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable ||\n isCodeMirror)\n ) {\n return\n }\n\n // Emit the clipboard text content\n if (event.clipboardData) {\n const pastedText = event.clipboardData.getData('text')\n\n if (pastedText) {\n emit('input', pastedText, null, 'paste')\n }\n }\n}\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (\n e: 'input',\n url: string,\n integration: string | null,\n eventType: 'query',\n ): void\n}>()\n\n// Check URL query parameters for 'url' and 'integration' values\nonMounted(() => {\n const queryParameters = new URLSearchParams(window.location.search)\n\n const urlQueryParameter = queryParameters.get('url')\n\n if (urlQueryParameter) {\n emit(\n 'input',\n urlQueryParameter,\n queryParameters.get('integration'),\n 'query',\n )\n }\n})\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (\n e: 'input',\n url: string,\n integration: string | null,\n eventType: 'query',\n ): void\n}>()\n\n// Check URL query parameters for 'url' and 'integration' values\nonMounted(() => {\n const queryParameters = new URLSearchParams(window.location.search)\n\n const urlQueryParameter = queryParameters.get('url')\n\n if (urlQueryParameter) {\n emit(\n 'input',\n urlQueryParameter,\n queryParameters.get('integration'),\n 'query',\n )\n }\n})\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { nextTick, ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { workspaceStoreIsEmpty } from '@/components/ImportCollection/utils/workspace-store-is-empty'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport DropEventListener from './DropEventListener.vue'\nimport ImportCollectionModal from './ImportCollectionModal.vue'\nimport PasteEventListener from './PasteEventListener.vue'\nimport UrlQueryParameterChecker from './UrlQueryParameterChecker.vue'\nimport { importCollection } from './utils/import-collection'\n\nconst store = useWorkspace()\n\n/** Source to import from */\nconst source = ref<string | null>(null)\n\nconst integration = ref<string | null>(null)\n\nconst eventType = ref<'paste' | 'drop' | 'query' | null>(null)\n\n/** Reset the data when the modal was closed */\nasync function resetData() {\n source.value = null\n integration.value = null\n eventType.value = null\n\n await nextTick()\n}\n\n/** Receive data from the paste event listener */\nasync function handleInput(\n newSource: string,\n newIntegration: string | null = null,\n newEventType: 'paste' | 'drop' | 'query',\n) {\n // Reset, to trigger the modal to reopen\n await resetData()\n\n // We skip the modal and directly import if the store is empty.\n if (workspaceStoreIsEmpty(store)) {\n console.info('Workspace store is empty, directly importing:', newSource)\n\n if (await handleImportCollection(newSource)) {\n return\n }\n\n console.warn('Failed to import the collection from:', newSource)\n }\n\n // Open the modal\n source.value = newSource\n integration.value = newIntegration\n eventType.value = newEventType\n}\n\nconst router = useRouter()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection(\n source: string | null | undefined,\n): Promise<boolean> {\n if (!source) {\n return Promise.resolve(false)\n }\n\n return new Promise<boolean>((resolve) => {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source,\n // Use watch mode by default.\n watchMode: true,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n resolve(true)\n\n return\n }\n\n // If collection is undefined, consider it a failure\n toast('Import failed: No collection was created', 'error')\n\n resolve(false)\n },\n onError(error) {\n console.error('[importCollection]', error)\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n\n resolve(false)\n },\n })\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <!-- Modal -->\n <ImportCollectionModal\n :eventType=\"eventType\"\n :integration=\"integration\"\n :source=\"source\"\n @importFinished=\"resetData\" />\n\n <!-- Event listeners-->\n <PasteEventListener @input=\"handleInput\" />\n <DropEventListener @input=\"handleInput\" />\n <UrlQueryParameterChecker @input=\"handleInput\" />\n\n <!-- Wrapped content -->\n <slot />\n</template>\n","<script lang=\"ts\" setup>\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { nextTick, ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { workspaceStoreIsEmpty } from '@/components/ImportCollection/utils/workspace-store-is-empty'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport DropEventListener from './DropEventListener.vue'\nimport ImportCollectionModal from './ImportCollectionModal.vue'\nimport PasteEventListener from './PasteEventListener.vue'\nimport UrlQueryParameterChecker from './UrlQueryParameterChecker.vue'\nimport { importCollection } from './utils/import-collection'\n\nconst store = useWorkspace()\n\n/** Source to import from */\nconst source = ref<string | null>(null)\n\nconst integration = ref<string | null>(null)\n\nconst eventType = ref<'paste' | 'drop' | 'query' | null>(null)\n\n/** Reset the data when the modal was closed */\nasync function resetData() {\n source.value = null\n integration.value = null\n eventType.value = null\n\n await nextTick()\n}\n\n/** Receive data from the paste event listener */\nasync function handleInput(\n newSource: string,\n newIntegration: string | null = null,\n newEventType: 'paste' | 'drop' | 'query',\n) {\n // Reset, to trigger the modal to reopen\n await resetData()\n\n // We skip the modal and directly import if the store is empty.\n if (workspaceStoreIsEmpty(store)) {\n console.info('Workspace store is empty, directly importing:', newSource)\n\n if (await handleImportCollection(newSource)) {\n return\n }\n\n console.warn('Failed to import the collection from:', newSource)\n }\n\n // Open the modal\n source.value = newSource\n integration.value = newIntegration\n eventType.value = newEventType\n}\n\nconst router = useRouter()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection(\n source: string | null | undefined,\n): Promise<boolean> {\n if (!source) {\n return Promise.resolve(false)\n }\n\n return new Promise<boolean>((resolve) => {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source,\n // Use watch mode by default.\n watchMode: true,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n resolve(true)\n\n return\n }\n\n // If collection is undefined, consider it a failure\n toast('Import failed: No collection was created', 'error')\n\n resolve(false)\n },\n onError(error) {\n console.error('[importCollection]', error)\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n\n resolve(false)\n },\n })\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <!-- Modal -->\n <ImportCollectionModal\n :eventType=\"eventType\"\n :integration=\"integration\"\n :source=\"source\"\n @importFinished=\"resetData\" />\n\n <!-- Event listeners-->\n <PasteEventListener @input=\"handleInput\" />\n <DropEventListener @input=\"handleInput\" />\n <UrlQueryParameterChecker @input=\"handleInput\" />\n\n <!-- Wrapped content -->\n <slot />\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ImportCollection-BIYMxB9Q.js","names":[],"sources":["../src/components/ImportCollection/utils/workspace-store-is-empty.ts","../src/components/ImportCollection/DropEventListener.vue","../src/components/ImportCollection/DropEventListener.vue","../src/components/ImportCollection/hooks/useUrlPrefetcher.ts","../src/components/ImportCollection/utils/is-url.ts","../src/components/ImportCollection/utils/import-collection.ts","../src/components/ImportCollection/ImportNowButton.vue","../src/components/ImportCollection/ImportNowButton.vue","../src/components/ImportCollection/PrefetchError.vue","../src/components/ImportCollection/PrefetchError.vue","../src/components/ImportCollection/utils/is-document.ts","../src/components/ImportCollection/utils/get-openapi-version.ts","../src/components/ImportCollection/WorkspaceSelector.vue","../src/components/ImportCollection/WorkspaceSelector.vue","../src/components/ImportCollection/ImportCollectionModal.vue","../src/components/ImportCollection/ImportCollectionModal.vue","../src/components/ImportCollection/PasteEventListener.vue","../src/components/ImportCollection/PasteEventListener.vue","../src/components/ImportCollection/UrlQueryParameterChecker.vue","../src/components/ImportCollection/UrlQueryParameterChecker.vue","../src/components/ImportCollection/ImportCollectionListener.vue","../src/components/ImportCollection/ImportCollectionListener.vue"],"sourcesContent":["import type { WorkspaceStore } from '@/store'\n\n/**\n * Checks whether the store is empty.\n */\nexport function workspaceStoreIsEmpty(store: WorkspaceStore) {\n const hasSingleWorkspace = Object.keys(store.workspaces).length === 1\n const hasSingleCollection = Object.keys(store.collections).length === 1\n\n return hasSingleWorkspace && hasSingleCollection\n}\n","<script lang=\"ts\" setup>\nimport { ScalarIcon } from '@scalar/components'\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'drop'): void\n}>()\n\nconst isDragging = ref<boolean>(false)\n\nlet dragCounter = 0\n\n// Register event listeners\nonMounted(() => {\n document.addEventListener('dragenter', handleDragEnter)\n document.addEventListener('dragleave', handleDragLeave)\n document.addEventListener('dragover', handleDragOver)\n document.addEventListener('drop', handleDrop)\n})\n\n// Unregister event listeners\nonBeforeUnmount(() => {\n document.removeEventListener('dragenter', handleDragEnter)\n document.removeEventListener('dragover', handleDragOver)\n document.removeEventListener('dragleave', handleDragLeave)\n document.removeEventListener('drop', handleDrop)\n})\n\nfunction isFromApp(event: DragEvent): boolean {\n return event.dataTransfer?.types.includes('text/html') ?? false\n}\n\n// Drop\nfunction handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragging.value = false\n dragCounter = 0\n\n // Prevent emitting for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n // Text\n const droppedText = event.dataTransfer.getData('text').replace(/^blob:/, '')\n\n if (droppedText) {\n emit('input', droppedText, null, 'drop')\n }\n // Files\n else if (event.dataTransfer.files.length > 0) {\n const file = event.dataTransfer.files[0]\n if (!file) {\n return\n }\n\n const reader = new FileReader()\n\n reader.onload = (e) => {\n if (e.target && typeof e.target.result === 'string') {\n emit('input', e.target.result, null, 'drop')\n }\n }\n\n reader.readAsText(file)\n }\n }\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n}\n\nfunction handleDragLeave(event: DragEvent) {\n event.preventDefault()\n dragCounter--\n\n if (dragCounter === 0) {\n isDragging.value = false\n }\n}\n\nfunction handleDragEnter(event: DragEvent) {\n event.preventDefault()\n dragCounter++\n\n // Prevent displaying the draggable UI for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n const items = event.dataTransfer.items\n for (const item of items) {\n if (\n item?.kind === 'string' ||\n item?.type?.includes('json') ||\n item?.type?.includes('yml') ||\n item?.type?.includes('yaml')\n ) {\n isDragging.value = true\n return\n }\n }\n }\n isDragging.value = false\n}\n</script>\n\n<template>\n <transition\n enterActiveClass=\"transition-opacity duration-200\"\n enterFromClass=\"opacity-0\"\n leaveActiveClass=\"transition-opacity duration-200\"\n leaveToClass=\"opacity-0\">\n <div\n v-if=\"isDragging\"\n class=\"bg-b-2 fixed right-1/2 bottom-1/2 z-50 h-64 w-64 translate-x-1/2 translate-y-1/2 rounded-xl border transition-opacity duration-200 md:right-10 md:bottom-10 md:translate-x-0 md:translate-y-0\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <div>\n <ScalarIcon\n icon=\"Download\"\n size=\"xl\"\n thickness=\"2\" />\n </div>\n <div class=\"text-c-1 m-4 text-center\">\n Drop your OpenAPI document here\n </div>\n </div>\n </div>\n </transition>\n</template>\n","<script lang=\"ts\" setup>\nimport { ScalarIcon } from '@scalar/components'\nimport { onBeforeUnmount, onMounted, ref } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'drop'): void\n}>()\n\nconst isDragging = ref<boolean>(false)\n\nlet dragCounter = 0\n\n// Register event listeners\nonMounted(() => {\n document.addEventListener('dragenter', handleDragEnter)\n document.addEventListener('dragleave', handleDragLeave)\n document.addEventListener('dragover', handleDragOver)\n document.addEventListener('drop', handleDrop)\n})\n\n// Unregister event listeners\nonBeforeUnmount(() => {\n document.removeEventListener('dragenter', handleDragEnter)\n document.removeEventListener('dragover', handleDragOver)\n document.removeEventListener('dragleave', handleDragLeave)\n document.removeEventListener('drop', handleDrop)\n})\n\nfunction isFromApp(event: DragEvent): boolean {\n return event.dataTransfer?.types.includes('text/html') ?? false\n}\n\n// Drop\nfunction handleDrop(event: DragEvent) {\n event.preventDefault()\n isDragging.value = false\n dragCounter = 0\n\n // Prevent emitting for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n // Text\n const droppedText = event.dataTransfer.getData('text').replace(/^blob:/, '')\n\n if (droppedText) {\n emit('input', droppedText, null, 'drop')\n }\n // Files\n else if (event.dataTransfer.files.length > 0) {\n const file = event.dataTransfer.files[0]\n if (!file) {\n return\n }\n\n const reader = new FileReader()\n\n reader.onload = (e) => {\n if (e.target && typeof e.target.result === 'string') {\n emit('input', e.target.result, null, 'drop')\n }\n }\n\n reader.readAsText(file)\n }\n }\n}\n\nfunction handleDragOver(event: DragEvent) {\n event.preventDefault()\n}\n\nfunction handleDragLeave(event: DragEvent) {\n event.preventDefault()\n dragCounter--\n\n if (dragCounter === 0) {\n isDragging.value = false\n }\n}\n\nfunction handleDragEnter(event: DragEvent) {\n event.preventDefault()\n dragCounter++\n\n // Prevent displaying the draggable UI for text/html dragged items\n if (isFromApp(event)) {\n return\n }\n\n if (event.dataTransfer) {\n const items = event.dataTransfer.items\n for (const item of items) {\n if (\n item?.kind === 'string' ||\n item?.type?.includes('json') ||\n item?.type?.includes('yml') ||\n item?.type?.includes('yaml')\n ) {\n isDragging.value = true\n return\n }\n }\n }\n isDragging.value = false\n}\n</script>\n\n<template>\n <transition\n enterActiveClass=\"transition-opacity duration-200\"\n enterFromClass=\"opacity-0\"\n leaveActiveClass=\"transition-opacity duration-200\"\n leaveToClass=\"opacity-0\">\n <div\n v-if=\"isDragging\"\n class=\"bg-b-2 fixed right-1/2 bottom-1/2 z-50 h-64 w-64 translate-x-1/2 translate-y-1/2 rounded-xl border transition-opacity duration-200 md:right-10 md:bottom-10 md:translate-x-0 md:translate-y-0\">\n <div class=\"flex h-full flex-col items-center justify-center\">\n <div>\n <ScalarIcon\n icon=\"Download\"\n size=\"xl\"\n thickness=\"2\" />\n </div>\n <div class=\"text-c-1 m-4 text-center\">\n Drop your OpenAPI document here\n </div>\n </div>\n </div>\n </transition>\n</template>\n","import { redirectToProxy } from '@scalar/helpers/url/redirect-to-proxy'\nimport { resolve } from '@scalar/import'\nimport { fetchWithProxyFallback } from '@scalar/oas-utils/helpers'\nimport { reactive } from 'vue'\n\nimport { isUrl } from '@/libs'\n\ntype PrefetchResult = {\n state: 'idle' | 'loading'\n content: string | null\n input: string | null\n url: string | null\n error: string | null\n}\n\n/**\n * Vue composable for URL prefetching\n */\nexport function useUrlPrefetcher() {\n const prefetchResult = reactive<PrefetchResult>({\n state: 'idle',\n content: null,\n url: null,\n input: null,\n error: null,\n })\n\n function resetPrefetchResult() {\n Object.assign(prefetchResult, {\n state: 'idle',\n content: null,\n url: null,\n input: null,\n error: null,\n })\n }\n\n async function prefetchUrl(input: string | null, proxyUrl?: string) {\n if (!input) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: null,\n }\n }\n\n try {\n // If we try hard enough, we might find the actual OpenAPI document URL even if the input isn't one directly.\n const urlOrDocument = await resolve(input, {\n fetch: (url) => {\n return fetch(proxyUrl ? redirectToProxy(proxyUrl, url) : url, {\n cache: 'no-cache',\n })\n },\n })\n\n // If the input is an object, we're done\n if (typeof urlOrDocument === 'object' && urlOrDocument !== null) {\n const json = JSON.stringify(urlOrDocument, null, 2)\n\n return {\n state: 'idle',\n content: json,\n url: null,\n error: null,\n }\n }\n\n // Nothing was found.\n if (urlOrDocument === undefined) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: `Could not find an OpenAPI document in ${input}`,\n }\n }\n\n if (!isUrl(urlOrDocument)) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: 'Oops, we got invalid content for the given URL.',\n }\n }\n\n const url = urlOrDocument\n\n // Okay, we've got an URL. Let's fetch it:\n const result = await fetchWithProxyFallback(url, {\n proxyUrl,\n cache: 'no-cache',\n })\n\n if (!result.ok) {\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: `Couldn't fetch ${url}, got error ${[result.status, result.statusText].join(' ').trim()}.`,\n }\n }\n\n const content = await result.text()\n\n return {\n state: 'idle',\n content,\n url,\n error: null,\n }\n } catch (error: any) {\n console.error('[prefetchDocument]', error)\n\n return {\n state: 'idle',\n content: null,\n url: null,\n input,\n error: error.message,\n }\n }\n }\n\n async function prefetchUrlAndUpdateState(input: string | null, proxyUrl?: string) {\n Object.assign(prefetchResult, {\n state: 'loading',\n content: null,\n url: null,\n input,\n error: null,\n })\n\n const result = await prefetchUrl(input, proxyUrl)\n Object.assign(prefetchResult, result)\n return result\n }\n\n return {\n prefetchResult,\n prefetchUrl: prefetchUrlAndUpdateState,\n resetPrefetchResult,\n }\n}\n","/**\n * Checks whether the given string is an URL\n **/\nexport function isUrl(input: string | null): boolean {\n // Quick check for null or undefined\n if (!input) {\n return false\n }\n\n // Trim whitespace\n const trimmed = input.trim()\n\n // If it's an URL, it must start with http:// or https://\n if (!trimmed.startsWith('http://') && !trimmed.startsWith('https://')) {\n return false\n }\n\n // But it must have more than just the protocol\n return trimmed.replace(/^https?:\\/\\//, '').length > 0\n}\n","import type { Collection } from '@scalar/oas-utils/entities/spec'\nimport type { Workspace } from '@scalar/oas-utils/entities/workspace'\n\nimport { isUrl } from '@/components/ImportCollection/utils/is-url'\nimport type { WorkspaceStore } from '@/store'\n\nexport async function importCollection({\n store,\n workspace,\n source,\n watchMode,\n onSuccess,\n onError,\n}: {\n store: WorkspaceStore\n workspace: Workspace | undefined\n source: string | null | undefined\n watchMode: boolean\n onSuccess: (collection: Collection | undefined) => void\n onError: (error: Error) => void\n}) {\n try {\n if (source && workspace) {\n if (isUrl(source)) {\n const [error, entities] = await store.importSpecFromUrl(source, workspace.uid, {\n proxyUrl: workspace.proxyUrl,\n watchMode: watchMode,\n })\n\n if (!error) {\n onSuccess(entities?.collection)\n }\n\n return\n }\n\n const entities = await store.importSpecFile(source, workspace.uid)\n\n onSuccess(entities?.collection)\n }\n } catch (error) {\n onError(error as Error)\n }\n}\n","<script lang=\"ts\" setup>\nimport { ScalarButton } from '@scalar/components'\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport { importCollection } from './utils/import-collection'\n\nconst { source, watchMode = true } = defineProps<{\n source?: string | null\n variant?: 'button' | 'link'\n watchMode?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst router = useRouter()\nconst store = useWorkspace()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection() {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source: source,\n watchMode: watchMode,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n emit('importFinished')\n }\n },\n onError(error) {\n console.error('[importCollection]', error)\n\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n },\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <template v-if=\"source\">\n <!-- Button -->\n <ScalarButton\n v-if=\"variant === 'button'\"\n class=\"mt-3 h-fit w-full rounded-lg px-6 py-2.5 font-bold\"\n size=\"md\"\n type=\"button\"\n @click=\"handleImportCollection\">\n Import Collection\n </ScalarButton>\n <!-- Link -->\n <ScalarButton\n v-else\n class=\"h-fit rounded-lg px-6 py-2.5 text-[21px] font-bold\"\n size=\"md\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"handleImportCollection\">\n Try it in the browser\n </ScalarButton>\n <!-- <a\n v-else\n class=\"no-underline text-sm\"\n href=\"#\"\n @click=\"importCollection\">\n Try it in the browser\n </a> -->\n </template>\n</template>\n","<script lang=\"ts\" setup>\nimport { ScalarButton } from '@scalar/components'\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport { importCollection } from './utils/import-collection'\n\nconst { source, watchMode = true } = defineProps<{\n source?: string | null\n variant?: 'button' | 'link'\n watchMode?: boolean\n}>()\n\nconst emit = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst router = useRouter()\nconst store = useWorkspace()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection() {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source: source,\n watchMode: watchMode,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n emit('importFinished')\n }\n },\n onError(error) {\n console.error('[importCollection]', error)\n\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n },\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <template v-if=\"source\">\n <!-- Button -->\n <ScalarButton\n v-if=\"variant === 'button'\"\n class=\"mt-3 h-fit w-full rounded-lg px-6 py-2.5 font-bold\"\n size=\"md\"\n type=\"button\"\n @click=\"handleImportCollection\">\n Import Collection\n </ScalarButton>\n <!-- Link -->\n <ScalarButton\n v-else\n class=\"h-fit rounded-lg px-6 py-2.5 text-[21px] font-bold\"\n size=\"md\"\n type=\"button\"\n variant=\"ghost\"\n @click=\"handleImportCollection\">\n Try it in the browser\n </ScalarButton>\n <!-- <a\n v-else\n class=\"no-underline text-sm\"\n href=\"#\"\n @click=\"importCollection\">\n Try it in the browser\n </a> -->\n </template>\n</template>\n","<script setup lang=\"ts\">\nimport { isUrl } from '@/libs'\n\ndefineProps<{\n url?: string | null\n}>()\n</script>\n\n<template>\n <div class=\"w-full text-center text-sm font-medium break-words\">\n We couldn't find an OpenAPI document at the provided URL. Please download\n and import the\n <a\n v-if=\"url && isUrl(url)\"\n :href=\"url\"\n rel=\"noopener nofollow\"\n target=\"_blank\"\n v-text=\"'OpenAPI document manually'\" />\n <span\n v-else\n v-text=\"'OpenAPI document manually'\" />.\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { isUrl } from '@/libs'\n\ndefineProps<{\n url?: string | null\n}>()\n</script>\n\n<template>\n <div class=\"w-full text-center text-sm font-medium break-words\">\n We couldn't find an OpenAPI document at the provided URL. Please download\n and import the\n <a\n v-if=\"url && isUrl(url)\"\n :href=\"url\"\n rel=\"noopener nofollow\"\n target=\"_blank\"\n v-text=\"'OpenAPI document manually'\" />\n <span\n v-else\n v-text=\"'OpenAPI document manually'\" />.\n </div>\n</template>\n","/** Checks whether the given string could be an OpenAPI document */\nexport function isDocument(input: string | null): boolean {\n // Return false for null, undefined, empty strings, or whitespace-only strings\n if (!input || input.trim().length === 0) {\n return false\n }\n\n const trimmed = input.trim()\n\n // Return false if it looks like a URL (starts with http:// or https://)\n if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {\n return false\n }\n\n return true\n}\n","import { parse } from 'yaml'\n\nimport { isDocument } from './is-document'\n\n/**\n * Get the Swagger/OpenAPI version and format from the given string\n */\nexport function getOpenApiVersion(input: string | null) {\n if (!isDocument(input)) {\n return false\n }\n\n try {\n const result = JSON.parse(input ?? '')\n\n if (typeof result?.openapi === 'string') {\n return `OpenAPI ${result.openapi} JSON`\n }\n\n if (typeof result?.swagger === 'string') {\n return `Swagger ${result.swagger} JSON`\n }\n\n return false\n } catch {\n //\n }\n\n try {\n const result = parse(input ?? '')\n\n if (typeof result?.openapi === 'string') {\n return `OpenAPI ${result.openapi} YAML`\n }\n\n if (typeof result?.swagger === 'string') {\n return `Swagger ${result.swagger} YAML`\n }\n\n return false\n } catch {\n //\n }\n\n return false\n}\n","<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n ScalarModal,\n useModal,\n} from '@scalar/components'\nimport { useToasts } from '@scalar/use-toasts'\nimport { ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaces, workspaceMutators } = useWorkspace()\nconst { push } = useRouter()\n\nconst modal = useModal()\nconst { toast } = useToasts()\nconst workspaceName = ref('')\n\nconst updateSelected = (uid: string) => {\n if (uid === activeWorkspace.value?.uid) {\n return\n }\n\n push({\n name: 'workspace',\n params: {\n workspace: uid,\n },\n })\n}\n\nconst handleCreateWorkspace = () => {\n if (!workspaceName.value.trim()) {\n toast('Please enter a name before creating a workspace.', 'error')\n return\n }\n\n const newWorkspace = workspaceMutators.add({\n name: workspaceName.value,\n })\n\n toast(`Created new workspace '${newWorkspace.name}'`)\n\n push({\n name: 'workspace',\n params: {\n workspace: newWorkspace.uid,\n },\n })\n\n workspaceName.value = ''\n modal.hide()\n}\n</script>\n<template>\n <div class=\"flex w-[inherit] items-center text-base\">\n <ScalarDropdown>\n <ScalarButton\n class=\"hover:bg-b-2 text-c-3 line-clamp-1 h-full w-fit justify-start px-1.5 py-1 font-normal\"\n variant=\"ghost\">\n <div class=\"m-0 flex items-center gap-1 text-sm font-medium\">\n <h2 class=\"line-clamp-1 w-[calc(100%-10px)] text-left text-xs\">\n {{ activeWorkspace?.name }}\n </h2>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </div>\n </ScalarButton>\n\n <!-- Workspace list -->\n <template #items>\n <ScalarDropdownItem\n v-for=\"(workspace, uid) in workspaces\"\n :key=\"uid\"\n class=\"group/item flex w-full items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"updateSelected(uid)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeWorkspace?.uid === uid\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"overflow-hidden text-ellipsis\">{{\n workspace.name\n }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider />\n\n <!-- Add new workspace -->\n <ScalarDropdownItem\n class=\"flex items-center gap-1.5\"\n @click=\"modal.show()\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>New Workspace</span>\n </ScalarDropdownItem>\n </template>\n </ScalarDropdown>\n </div>\n <ScalarModal\n bodyClass=\"m-0 p-1 rounded-lg border-t-0\"\n class=\"z-overlay absolute\"\n :size=\"'xxs'\"\n :state=\"modal\"\n variant=\"form\">\n <form\n class=\"flex gap-1\"\n @submit.prevent=\"handleCreateWorkspace\">\n <input\n v-model=\"workspaceName\"\n class=\"min-h-8 w-full flex-1 border-none p-1.5 text-sm outline-none\"\n placeholder=\"New Workspace\"\n type=\"text\" />\n <ScalarButton\n class=\"max-h-8 p-0 px-3 text-xs\"\n :disabled=\"!workspaceName.trim()\"\n type=\"submit\">\n Continue\n </ScalarButton>\n </form>\n </ScalarModal>\n</template>\n","<script setup lang=\"ts\">\nimport {\n ScalarButton,\n ScalarDropdown,\n ScalarDropdownDivider,\n ScalarDropdownItem,\n ScalarIcon,\n ScalarModal,\n useModal,\n} from '@scalar/components'\nimport { useToasts } from '@scalar/use-toasts'\nimport { ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaces, workspaceMutators } = useWorkspace()\nconst { push } = useRouter()\n\nconst modal = useModal()\nconst { toast } = useToasts()\nconst workspaceName = ref('')\n\nconst updateSelected = (uid: string) => {\n if (uid === activeWorkspace.value?.uid) {\n return\n }\n\n push({\n name: 'workspace',\n params: {\n workspace: uid,\n },\n })\n}\n\nconst handleCreateWorkspace = () => {\n if (!workspaceName.value.trim()) {\n toast('Please enter a name before creating a workspace.', 'error')\n return\n }\n\n const newWorkspace = workspaceMutators.add({\n name: workspaceName.value,\n })\n\n toast(`Created new workspace '${newWorkspace.name}'`)\n\n push({\n name: 'workspace',\n params: {\n workspace: newWorkspace.uid,\n },\n })\n\n workspaceName.value = ''\n modal.hide()\n}\n</script>\n<template>\n <div class=\"flex w-[inherit] items-center text-base\">\n <ScalarDropdown>\n <ScalarButton\n class=\"hover:bg-b-2 text-c-3 line-clamp-1 h-full w-fit justify-start px-1.5 py-1 font-normal\"\n variant=\"ghost\">\n <div class=\"m-0 flex items-center gap-1 text-sm font-medium\">\n <h2 class=\"line-clamp-1 w-[calc(100%-10px)] text-left text-xs\">\n {{ activeWorkspace?.name }}\n </h2>\n <ScalarIcon\n icon=\"ChevronDown\"\n size=\"md\" />\n </div>\n </ScalarButton>\n\n <!-- Workspace list -->\n <template #items>\n <ScalarDropdownItem\n v-for=\"(workspace, uid) in workspaces\"\n :key=\"uid\"\n class=\"group/item flex w-full items-center gap-1.5 overflow-hidden text-ellipsis whitespace-nowrap\"\n @click.stop=\"updateSelected(uid)\">\n <div\n class=\"flex h-4 w-4 items-center justify-center rounded-full p-[3px]\"\n :class=\"\n activeWorkspace?.uid === uid\n ? 'bg-c-accent text-b-1'\n : 'shadow-border text-transparent'\n \">\n <ScalarIcon\n class=\"size-2.5\"\n icon=\"Checkmark\"\n thickness=\"3\" />\n </div>\n <span class=\"overflow-hidden text-ellipsis\">{{\n workspace.name\n }}</span>\n </ScalarDropdownItem>\n <ScalarDropdownDivider />\n\n <!-- Add new workspace -->\n <ScalarDropdownItem\n class=\"flex items-center gap-1.5\"\n @click=\"modal.show()\">\n <div class=\"flex h-4 w-4 items-center justify-center\">\n <ScalarIcon\n icon=\"Add\"\n size=\"sm\" />\n </div>\n <span>New Workspace</span>\n </ScalarDropdownItem>\n </template>\n </ScalarDropdown>\n </div>\n <ScalarModal\n bodyClass=\"m-0 p-1 rounded-lg border-t-0\"\n class=\"z-overlay absolute\"\n :size=\"'xxs'\"\n :state=\"modal\"\n variant=\"form\">\n <form\n class=\"flex gap-1\"\n @submit.prevent=\"handleCreateWorkspace\">\n <input\n v-model=\"workspaceName\"\n class=\"min-h-8 w-full flex-1 border-none p-1.5 text-sm outline-none\"\n placeholder=\"New Workspace\"\n type=\"text\" />\n <ScalarButton\n class=\"max-h-8 p-0 px-3 text-xs\"\n :disabled=\"!workspaceName.trim()\"\n type=\"submit\">\n Continue\n </ScalarButton>\n </form>\n </ScalarModal>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon, ScalarModal, useModal } from '@scalar/components'\nimport { isLocalUrl } from '@scalar/oas-utils/helpers'\nimport { normalize } from '@scalar/openapi-parser'\nimport type { OpenAPI } from '@scalar/openapi-types'\nimport {\n getThemeStyles,\n themeIds,\n type IntegrationThemeId,\n} from '@scalar/themes'\nimport { useColorMode } from '@scalar/use-hooks/useColorMode'\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport WatchModeToggle from '@/components/CommandPalette/WatchModeToggle.vue'\nimport { useUrlPrefetcher } from '@/components/ImportCollection/hooks/useUrlPrefetcher'\nimport ImportNowButton from '@/components/ImportCollection/ImportNowButton.vue'\nimport IntegrationLogo from '@/components/ImportCollection/IntegrationLogo.vue'\nimport PrefetchError from '@/components/ImportCollection/PrefetchError.vue'\nimport { getOpenApiVersion } from '@/components/ImportCollection/utils/get-openapi-version'\nimport { isDocument } from '@/components/ImportCollection/utils/is-document'\nimport { isUrl } from '@/components/ImportCollection/utils/is-url'\nimport WorkspaceSelector from '@/components/ImportCollection/WorkspaceSelector.vue'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst props = defineProps<{\n source: string | null\n integration: string | null\n eventType: 'drop' | 'paste' | 'query' | null\n}>()\n\nconst emits = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaceMutators, events } = useWorkspace()\n\nconst { prefetchResult, prefetchUrl, resetPrefetchResult } = useUrlPrefetcher()\n\nconst modalState = useModal()\n\nconst watchMode = ref<boolean>(true)\n\n/** Close modal when a keyboard shortcut is pressed */\nevents.hotKeys.on(() => modalState.hide())\n\n/** Try to make the retrieved content an OpenAPI document */\nconst openApiDocument = computed(() => {\n try {\n return normalize(\n prefetchResult.content || props.source || '',\n ) as OpenAPI.Document\n } catch {\n return undefined\n }\n})\n\n/** Title from the OpenAPI document */\nconst title = computed(() => openApiDocument.value?.info?.title)\n\n/** The OpenAPI/Swagger version */\nconst version = computed(() =>\n getOpenApiVersion(prefetchResult.content || props.source || ''),\n)\n\nconst { darkLightMode } = useColorMode()\nconst { currentRoute } = useRouter()\n\n/** Grab light and dark logos from the url query params */\nconst companyLogo = computed(() => {\n try {\n const query = currentRoute.value.query\n const logo =\n darkLightMode.value === 'dark' ? query.dark_logo : query.light_logo\n\n if (logo) {\n return decodeURIComponent(logo as string)\n }\n } catch {\n // No harm no foul\n }\n\n return null\n})\n\n/** Open/close modal on events */\nwatch(\n () => props.source,\n async (value) => {\n resetPrefetchResult()\n\n if (isUrl(value)) {\n // For drop & paste events only:\n const isDropOrPasteEvent =\n props.eventType && ['paste', 'drop'].includes(props.eventType)\n\n if (isDropOrPasteEvent) {\n // Check whether the URL is pointing to an OpenAPI document\n const { error } = await prefetchUrl(\n value,\n activeWorkspace.value?.proxyUrl,\n )\n\n if (error) {\n modalState.hide()\n } else {\n modalState.show()\n }\n\n return\n }\n\n // Query parameters:\n void prefetchUrl(value, activeWorkspace.value?.proxyUrl)\n\n modalState.show()\n\n return\n }\n\n if (!value) {\n modalState.hide()\n } else if (isDocument(value) && getOpenApiVersion(value)) {\n modalState.show()\n } else {\n modalState.hide()\n }\n },\n)\n\nconst hasUrl = computed(() => !!props.source && isUrl(props.source))\nconst hasContent = computed(() => !!props.source && isDocument(props.source))\n\n/** Show the integration icon only for local URLs */\nconst shouldShowIntegrationIcon = computed(() => {\n return prefetchResult.url && isLocalUrl(prefetchResult.url)\n})\n\n// Function to add/remove class from body\nconst toggleBodyClass = (add: boolean) => {\n document.body.classList.remove('has-no-import-url')\n\n if (add && (hasUrl.value || hasContent.value) && modalState.open) {\n document.body.classList.add('has-import-url')\n } else {\n document.body.classList.remove('has-import-url')\n }\n}\n\n/** Toggles the 'has-import-url' class on the body element */\nconst closeModal = () => {\n document.body.classList.remove('has-import-url')\n document.body.classList.add('has-no-import-url')\n}\n\n// Watch for changes in the modal state\nwatch(\n () => modalState.open,\n (isOpen) => {\n if (isOpen) {\n toggleBodyClass(true)\n } else {\n closeModal()\n }\n },\n)\n\n// Watch for changes in the source prop\nwatch(\n () => props.source,\n () => {\n toggleBodyClass(true)\n },\n)\n\n// Add class on mount if URL exists and modal is visible\nonMounted(() => {\n toggleBodyClass(true)\n})\n\n// Remove classes on unmount\nonUnmounted(() => {\n document.body.classList.remove('has-import-url')\n document.body.classList.remove('has-no-import-url')\n})\nconst themeStyleTag = computed(\n () =>\n activeWorkspace.value &&\n shouldShowIntegrationIcon.value &&\n props.integration &&\n `<style>${getThemeStyles(props.integration as IntegrationThemeId)}</style>`,\n)\n\nfunction handleImportFinished() {\n // If the integration is not a valid theme id, set the theme to default\n const isIntegrationThemeId = (value: string): value is IntegrationThemeId =>\n themeIds.includes(value as IntegrationThemeId)\n\n const integrationThemeId =\n props.integration && isIntegrationThemeId(props.integration)\n ? props.integration\n : 'default'\n\n if (shouldShowIntegrationIcon.value) {\n workspaceMutators.edit(\n activeWorkspace.value?.uid,\n 'themeId',\n integrationThemeId,\n )\n }\n emits('importFinished')\n}\n</script>\n\n<template>\n <ScalarModal\n size=\"full\"\n :state=\"modalState\">\n <div\n v-if=\"themeStyleTag\"\n v-html=\"themeStyleTag\" />\n <div\n class=\"relative flex h-screen flex-col justify-center overflow-hidden px-6 md:px-0\">\n <div class=\"section-flare\">\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n </div>\n <!-- Wait until the URL is fetched -->\n <div\n class=\"m-auto flex w-full max-w-[380px] flex-col items-center rounded-xl border px-8 py-8 transition-opacity\"\n :class=\"{ 'opacity-0': prefetchResult.state === 'loading' }\">\n <!-- Prefetch error -->\n <!-- Or: Document doesn't even have an OpenAPI/Swagger version, something is probably wrong -->\n <template\n v-if=\"\n prefetchResult.error && prefetchResult.state === 'idle' && !version\n \">\n <!-- Heading -->\n <div class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n No OpenAPI document found\n </div>\n <PrefetchError :url=\"prefetchResult?.input || props.source\" />\n </template>\n <!-- Success -->\n <template v-else>\n <!-- Integration Logo -->\n <div\n v-if=\"shouldShowIntegrationIcon\"\n class=\"mb-2 flex items-center justify-center p-1\">\n <div class=\"size-10 rounded-xl\">\n <IntegrationLogo :integration=\"integration\" />\n </div>\n </div>\n\n <!-- Company Logo -->\n <img\n v-else-if=\"companyLogo\"\n alt=\"Logo\"\n class=\"mb-2 w-full object-contain\"\n :src=\"companyLogo\" />\n\n <!-- Title -->\n <div\n v-if=\"!companyLogo\"\n class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n {{ title || 'Untitled Collection' }}\n </div>\n\n <div class=\"text-c-1 text-center text-sm font-medium text-balance\">\n Import the OpenAPI document to instantly send API requests. No\n signup required.\n </div>\n\n <!-- Actions -->\n <template v-if=\"version\">\n <div class=\"z-10 inline-flex w-full flex-col items-center gap-2\">\n <ImportNowButton\n :source=\"\n prefetchResult?.url ?? prefetchResult?.content ?? source\n \"\n variant=\"button\"\n :watchMode=\"watchMode\"\n @importFinished=\"handleImportFinished\" />\n </div>\n <!-- Select the workspace -->\n <div class=\"flex justify-center\">\n <div\n class=\"text-c-3 inline-flex items-center px-4 py-1 text-xs font-medium\">\n Import to: <WorkspaceSelector />\n </div>\n </div>\n <!-- Watch Mode -->\n <template v-if=\"prefetchResult?.url\">\n <div class=\"mt-5 overflow-hidden border-t pt-4 text-sm\">\n <div class=\"flex items-center justify-center\">\n <WatchModeToggle\n v-model=\"watchMode\"\n :disableToolTip=\"true\" />\n </div>\n <div\n class=\"text-c-3 pt-0 text-center text-xs font-medium text-balance\">\n Automatically update your API client when the OpenAPI document\n content changes.\n </div>\n </div>\n </template>\n </template>\n </template>\n </div>\n <!-- Download Link -->\n <div class=\"flex flex-col items-center justify-center pb-8\">\n <div class=\"flex flex-col items-center text-center\">\n <div\n class=\"mb-2 flex h-10 w-10 items-center justify-center rounded-[10px] border\">\n <a\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n </div>\n <span class=\"text-c-2 text-sm leading-snug font-medium\">\n <a\n class=\"hover:text-c-1 mb-1 inline-block underline-offset-2\"\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n Download Desktop App\n </a>\n <br />\n free · open-source · offline first\n </span>\n </div>\n </div>\n </div>\n </ScalarModal>\n</template>\n<style>\n@reference \"@/style.css\";\n\n@variant md {\n .has-no-import-url,\n .has-import-url {\n max-width: 100dvw;\n overflow-x: hidden;\n contain: paint;\n }\n .has-no-import-url .scalar-client > main {\n opacity: 1;\n background: var(--scalar-background-1);\n animation: transform-restore-layout ease-in-out 0.3s forwards;\n }\n .has-import-url .scalar-client > main {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n animation: transform-fade-layout ease-in-out 0.3s forwards;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: 12px;\n overflow: hidden;\n z-index: 10000;\n }\n .has-import-url .scalar-client .sidenav {\n display: none;\n }\n .has-no-import-url .scalar-app,\n .has-import-url .scalar-app {\n background: var(--scalar-background-1) !important;\n }\n}\n@keyframes transform-fade-layout {\n 0% {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 10px, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n}\n@keyframes transform-restore-layout {\n 0% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(1) translate3d(0, 0, 0);\n }\n}\n.openapi-color {\n color: var(--scalar-color-green);\n}\n.section-flare {\n position: fixed;\n top: 0;\n right: -50dvw;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ScalarIcon, ScalarModal, useModal } from '@scalar/components'\nimport { isLocalUrl } from '@scalar/oas-utils/helpers'\nimport { normalize } from '@scalar/openapi-parser'\nimport type { OpenAPI } from '@scalar/openapi-types'\nimport {\n getThemeStyles,\n themeIds,\n type IntegrationThemeId,\n} from '@scalar/themes'\nimport { useColorMode } from '@scalar/use-hooks/useColorMode'\nimport { computed, onMounted, onUnmounted, ref, watch } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport WatchModeToggle from '@/components/CommandPalette/WatchModeToggle.vue'\nimport { useUrlPrefetcher } from '@/components/ImportCollection/hooks/useUrlPrefetcher'\nimport ImportNowButton from '@/components/ImportCollection/ImportNowButton.vue'\nimport IntegrationLogo from '@/components/ImportCollection/IntegrationLogo.vue'\nimport PrefetchError from '@/components/ImportCollection/PrefetchError.vue'\nimport { getOpenApiVersion } from '@/components/ImportCollection/utils/get-openapi-version'\nimport { isDocument } from '@/components/ImportCollection/utils/is-document'\nimport { isUrl } from '@/components/ImportCollection/utils/is-url'\nimport WorkspaceSelector from '@/components/ImportCollection/WorkspaceSelector.vue'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nconst props = defineProps<{\n source: string | null\n integration: string | null\n eventType: 'drop' | 'paste' | 'query' | null\n}>()\n\nconst emits = defineEmits<{\n (e: 'importFinished'): void\n}>()\n\nconst { activeWorkspace } = useActiveEntities()\nconst { workspaceMutators, events } = useWorkspace()\n\nconst { prefetchResult, prefetchUrl, resetPrefetchResult } = useUrlPrefetcher()\n\nconst modalState = useModal()\n\nconst watchMode = ref<boolean>(true)\n\n/** Close modal when a keyboard shortcut is pressed */\nevents.hotKeys.on(() => modalState.hide())\n\n/** Try to make the retrieved content an OpenAPI document */\nconst openApiDocument = computed(() => {\n try {\n return normalize(\n prefetchResult.content || props.source || '',\n ) as OpenAPI.Document\n } catch {\n return undefined\n }\n})\n\n/** Title from the OpenAPI document */\nconst title = computed(() => openApiDocument.value?.info?.title)\n\n/** The OpenAPI/Swagger version */\nconst version = computed(() =>\n getOpenApiVersion(prefetchResult.content || props.source || ''),\n)\n\nconst { darkLightMode } = useColorMode()\nconst { currentRoute } = useRouter()\n\n/** Grab light and dark logos from the url query params */\nconst companyLogo = computed(() => {\n try {\n const query = currentRoute.value.query\n const logo =\n darkLightMode.value === 'dark' ? query.dark_logo : query.light_logo\n\n if (logo) {\n return decodeURIComponent(logo as string)\n }\n } catch {\n // No harm no foul\n }\n\n return null\n})\n\n/** Open/close modal on events */\nwatch(\n () => props.source,\n async (value) => {\n resetPrefetchResult()\n\n if (isUrl(value)) {\n // For drop & paste events only:\n const isDropOrPasteEvent =\n props.eventType && ['paste', 'drop'].includes(props.eventType)\n\n if (isDropOrPasteEvent) {\n // Check whether the URL is pointing to an OpenAPI document\n const { error } = await prefetchUrl(\n value,\n activeWorkspace.value?.proxyUrl,\n )\n\n if (error) {\n modalState.hide()\n } else {\n modalState.show()\n }\n\n return\n }\n\n // Query parameters:\n void prefetchUrl(value, activeWorkspace.value?.proxyUrl)\n\n modalState.show()\n\n return\n }\n\n if (!value) {\n modalState.hide()\n } else if (isDocument(value) && getOpenApiVersion(value)) {\n modalState.show()\n } else {\n modalState.hide()\n }\n },\n)\n\nconst hasUrl = computed(() => !!props.source && isUrl(props.source))\nconst hasContent = computed(() => !!props.source && isDocument(props.source))\n\n/** Show the integration icon only for local URLs */\nconst shouldShowIntegrationIcon = computed(() => {\n return prefetchResult.url && isLocalUrl(prefetchResult.url)\n})\n\n// Function to add/remove class from body\nconst toggleBodyClass = (add: boolean) => {\n document.body.classList.remove('has-no-import-url')\n\n if (add && (hasUrl.value || hasContent.value) && modalState.open) {\n document.body.classList.add('has-import-url')\n } else {\n document.body.classList.remove('has-import-url')\n }\n}\n\n/** Toggles the 'has-import-url' class on the body element */\nconst closeModal = () => {\n document.body.classList.remove('has-import-url')\n document.body.classList.add('has-no-import-url')\n}\n\n// Watch for changes in the modal state\nwatch(\n () => modalState.open,\n (isOpen) => {\n if (isOpen) {\n toggleBodyClass(true)\n } else {\n closeModal()\n }\n },\n)\n\n// Watch for changes in the source prop\nwatch(\n () => props.source,\n () => {\n toggleBodyClass(true)\n },\n)\n\n// Add class on mount if URL exists and modal is visible\nonMounted(() => {\n toggleBodyClass(true)\n})\n\n// Remove classes on unmount\nonUnmounted(() => {\n document.body.classList.remove('has-import-url')\n document.body.classList.remove('has-no-import-url')\n})\nconst themeStyleTag = computed(\n () =>\n activeWorkspace.value &&\n shouldShowIntegrationIcon.value &&\n props.integration &&\n `<style>${getThemeStyles(props.integration as IntegrationThemeId)}</style>`,\n)\n\nfunction handleImportFinished() {\n // If the integration is not a valid theme id, set the theme to default\n const isIntegrationThemeId = (value: string): value is IntegrationThemeId =>\n themeIds.includes(value as IntegrationThemeId)\n\n const integrationThemeId =\n props.integration && isIntegrationThemeId(props.integration)\n ? props.integration\n : 'default'\n\n if (shouldShowIntegrationIcon.value) {\n workspaceMutators.edit(\n activeWorkspace.value?.uid,\n 'themeId',\n integrationThemeId,\n )\n }\n emits('importFinished')\n}\n</script>\n\n<template>\n <ScalarModal\n size=\"full\"\n :state=\"modalState\">\n <div\n v-if=\"themeStyleTag\"\n v-html=\"themeStyleTag\" />\n <div\n class=\"relative flex h-screen flex-col justify-center overflow-hidden px-6 md:px-0\">\n <div class=\"section-flare\">\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n <div class=\"section-flare-item\" />\n </div>\n <!-- Wait until the URL is fetched -->\n <div\n class=\"m-auto flex w-full max-w-[380px] flex-col items-center rounded-xl border px-8 py-8 transition-opacity\"\n :class=\"{ 'opacity-0': prefetchResult.state === 'loading' }\">\n <!-- Prefetch error -->\n <!-- Or: Document doesn't even have an OpenAPI/Swagger version, something is probably wrong -->\n <template\n v-if=\"\n prefetchResult.error && prefetchResult.state === 'idle' && !version\n \">\n <!-- Heading -->\n <div class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n No OpenAPI document found\n </div>\n <PrefetchError :url=\"prefetchResult?.input || props.source\" />\n </template>\n <!-- Success -->\n <template v-else>\n <!-- Integration Logo -->\n <div\n v-if=\"shouldShowIntegrationIcon\"\n class=\"mb-2 flex items-center justify-center p-1\">\n <div class=\"size-10 rounded-xl\">\n <IntegrationLogo :integration=\"integration\" />\n </div>\n </div>\n\n <!-- Company Logo -->\n <img\n v-else-if=\"companyLogo\"\n alt=\"Logo\"\n class=\"mb-2 w-full object-contain\"\n :src=\"companyLogo\" />\n\n <!-- Title -->\n <div\n v-if=\"!companyLogo\"\n class=\"text-md mb-2 line-clamp-1 text-center font-bold\">\n {{ title || 'Untitled Collection' }}\n </div>\n\n <div class=\"text-c-1 text-center text-sm font-medium text-balance\">\n Import the OpenAPI document to instantly send API requests. No\n signup required.\n </div>\n\n <!-- Actions -->\n <template v-if=\"version\">\n <div class=\"z-10 inline-flex w-full flex-col items-center gap-2\">\n <ImportNowButton\n :source=\"\n prefetchResult?.url ?? prefetchResult?.content ?? source\n \"\n variant=\"button\"\n :watchMode=\"watchMode\"\n @importFinished=\"handleImportFinished\" />\n </div>\n <!-- Select the workspace -->\n <div class=\"flex justify-center\">\n <div\n class=\"text-c-3 inline-flex items-center px-4 py-1 text-xs font-medium\">\n Import to: <WorkspaceSelector />\n </div>\n </div>\n <!-- Watch Mode -->\n <template v-if=\"prefetchResult?.url\">\n <div class=\"mt-5 overflow-hidden border-t pt-4 text-sm\">\n <div class=\"flex items-center justify-center\">\n <WatchModeToggle\n v-model=\"watchMode\"\n :disableToolTip=\"true\" />\n </div>\n <div\n class=\"text-c-3 pt-0 text-center text-xs font-medium text-balance\">\n Automatically update your API client when the OpenAPI document\n content changes.\n </div>\n </div>\n </template>\n </template>\n </template>\n </div>\n <!-- Download Link -->\n <div class=\"flex flex-col items-center justify-center pb-8\">\n <div class=\"flex flex-col items-center text-center\">\n <div\n class=\"mb-2 flex h-10 w-10 items-center justify-center rounded-[10px] border\">\n <a\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n </div>\n <span class=\"text-c-2 text-sm leading-snug font-medium\">\n <a\n class=\"hover:text-c-1 mb-1 inline-block underline-offset-2\"\n href=\"https://scalar.com/download\"\n target=\"_blank\">\n Download Desktop App\n </a>\n <br />\n free · open-source · offline first\n </span>\n </div>\n </div>\n </div>\n </ScalarModal>\n</template>\n<style>\n@reference \"@/style.css\";\n\n@variant md {\n .has-no-import-url,\n .has-import-url {\n max-width: 100dvw;\n overflow-x: hidden;\n contain: paint;\n }\n .has-no-import-url .scalar-client > main {\n opacity: 1;\n background: var(--scalar-background-1);\n animation: transform-restore-layout ease-in-out 0.3s forwards;\n }\n .has-import-url .scalar-client > main {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n animation: transform-fade-layout ease-in-out 0.3s forwards;\n border: var(--scalar-border-width) solid var(--scalar-border-color);\n border-radius: 12px;\n overflow: hidden;\n z-index: 10000;\n }\n .has-import-url .scalar-client .sidenav {\n display: none;\n }\n .has-no-import-url .scalar-app,\n .has-import-url .scalar-app {\n background: var(--scalar-background-1) !important;\n }\n}\n@keyframes transform-fade-layout {\n 0% {\n opacity: 0;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 10px, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n}\n@keyframes transform-restore-layout {\n 0% {\n opacity: 1;\n transform: scale(0.85) translate3d(calc(50dvw + 80px), 0, 0);\n }\n 100% {\n opacity: 1;\n transform: scale(1) translate3d(0, 0, 0);\n }\n}\n.openapi-color {\n color: var(--scalar-color-green);\n}\n.section-flare {\n position: fixed;\n top: 0;\n right: -50dvw;\n}\n</style>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onBeforeUnmount, onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'paste'): void\n}>()\n\n// Register event listener\nonMounted(() => {\n document.addEventListener('paste', handlePaste)\n})\n\n// Unregister event listener\nonBeforeUnmount(() => {\n document.removeEventListener('paste', handlePaste)\n})\n\n// Handle the paste event\nfunction handlePaste(event: ClipboardEvent) {\n // Ignore paste events in input, textarea, or contenteditable elements\n const target = event.target as HTMLElement\n\n // Check if we're inside a CodeMirror instance\n const isCodeMirror = Boolean(\n document.activeElement?.classList.contains('cm-content'),\n )\n\n if (\n target &&\n (target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable ||\n isCodeMirror)\n ) {\n return\n }\n\n // Emit the clipboard text content\n if (event.clipboardData) {\n const pastedText = event.clipboardData.getData('text')\n\n if (pastedText) {\n emit('input', pastedText, null, 'paste')\n }\n }\n}\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onBeforeUnmount, onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (e: 'input', value: string, integration: null, eventType: 'paste'): void\n}>()\n\n// Register event listener\nonMounted(() => {\n document.addEventListener('paste', handlePaste)\n})\n\n// Unregister event listener\nonBeforeUnmount(() => {\n document.removeEventListener('paste', handlePaste)\n})\n\n// Handle the paste event\nfunction handlePaste(event: ClipboardEvent) {\n // Ignore paste events in input, textarea, or contenteditable elements\n const target = event.target as HTMLElement\n\n // Check if we're inside a CodeMirror instance\n const isCodeMirror = Boolean(\n document.activeElement?.classList.contains('cm-content'),\n )\n\n if (\n target &&\n (target.tagName === 'INPUT' ||\n target.tagName === 'TEXTAREA' ||\n target.isContentEditable ||\n isCodeMirror)\n ) {\n return\n }\n\n // Emit the clipboard text content\n if (event.clipboardData) {\n const pastedText = event.clipboardData.getData('text')\n\n if (pastedText) {\n emit('input', pastedText, null, 'paste')\n }\n }\n}\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (\n e: 'input',\n url: string,\n integration: string | null,\n eventType: 'query',\n ): void\n}>()\n\n// Check URL query parameters for 'url' and 'integration' values\nonMounted(() => {\n const queryParameters = new URLSearchParams(window.location.search)\n\n const urlQueryParameter = queryParameters.get('url')\n\n if (urlQueryParameter) {\n emit(\n 'input',\n urlQueryParameter,\n queryParameters.get('integration'),\n 'query',\n )\n }\n})\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\n/* eslint-disable vue/valid-template-root */\nimport { onMounted } from 'vue'\n\nconst emit = defineEmits<{\n (\n e: 'input',\n url: string,\n integration: string | null,\n eventType: 'query',\n ): void\n}>()\n\n// Check URL query parameters for 'url' and 'integration' values\nonMounted(() => {\n const queryParameters = new URLSearchParams(window.location.search)\n\n const urlQueryParameter = queryParameters.get('url')\n\n if (urlQueryParameter) {\n emit(\n 'input',\n urlQueryParameter,\n queryParameters.get('integration'),\n 'query',\n )\n }\n})\n</script>\n\n<template></template>\n","<script lang=\"ts\" setup>\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { nextTick, ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { workspaceStoreIsEmpty } from '@/components/ImportCollection/utils/workspace-store-is-empty'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport DropEventListener from './DropEventListener.vue'\nimport ImportCollectionModal from './ImportCollectionModal.vue'\nimport PasteEventListener from './PasteEventListener.vue'\nimport UrlQueryParameterChecker from './UrlQueryParameterChecker.vue'\nimport { importCollection } from './utils/import-collection'\n\nconst store = useWorkspace()\n\n/** Source to import from */\nconst source = ref<string | null>(null)\n\nconst integration = ref<string | null>(null)\n\nconst eventType = ref<'paste' | 'drop' | 'query' | null>(null)\n\n/** Reset the data when the modal was closed */\nasync function resetData() {\n source.value = null\n integration.value = null\n eventType.value = null\n\n await nextTick()\n}\n\n/** Receive data from the paste event listener */\nasync function handleInput(\n newSource: string,\n newIntegration: string | null = null,\n newEventType: 'paste' | 'drop' | 'query',\n) {\n // Reset, to trigger the modal to reopen\n await resetData()\n\n // We skip the modal and directly import if the store is empty.\n if (workspaceStoreIsEmpty(store)) {\n console.info('Workspace store is empty, directly importing:', newSource)\n\n if (await handleImportCollection(newSource)) {\n return\n }\n\n console.warn('Failed to import the collection from:', newSource)\n }\n\n // Open the modal\n source.value = newSource\n integration.value = newIntegration\n eventType.value = newEventType\n}\n\nconst router = useRouter()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection(\n source: string | null | undefined,\n): Promise<boolean> {\n if (!source) {\n return Promise.resolve(false)\n }\n\n return new Promise<boolean>((resolve) => {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source,\n // Use watch mode by default.\n watchMode: true,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n resolve(true)\n\n return\n }\n\n // If collection is undefined, consider it a failure\n toast('Import failed: No collection was created', 'error')\n\n resolve(false)\n },\n onError(error) {\n console.error('[importCollection]', error)\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n\n resolve(false)\n },\n })\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <!-- Modal -->\n <ImportCollectionModal\n :eventType=\"eventType\"\n :integration=\"integration\"\n :source=\"source\"\n @importFinished=\"resetData\" />\n\n <!-- Event listeners-->\n <PasteEventListener @input=\"handleInput\" />\n <DropEventListener @input=\"handleInput\" />\n <UrlQueryParameterChecker @input=\"handleInput\" />\n\n <!-- Wrapped content -->\n <slot />\n</template>\n","<script lang=\"ts\" setup>\nimport type { Collection } from '@scalar/oas-utils/entities/spec'\nimport { useToasts } from '@scalar/use-toasts'\nimport { nextTick, ref } from 'vue'\nimport { useRouter } from 'vue-router'\n\nimport { workspaceStoreIsEmpty } from '@/components/ImportCollection/utils/workspace-store-is-empty'\nimport { useWorkspace } from '@/store'\nimport { useActiveEntities } from '@/store/active-entities'\n\nimport DropEventListener from './DropEventListener.vue'\nimport ImportCollectionModal from './ImportCollectionModal.vue'\nimport PasteEventListener from './PasteEventListener.vue'\nimport UrlQueryParameterChecker from './UrlQueryParameterChecker.vue'\nimport { importCollection } from './utils/import-collection'\n\nconst store = useWorkspace()\n\n/** Source to import from */\nconst source = ref<string | null>(null)\n\nconst integration = ref<string | null>(null)\n\nconst eventType = ref<'paste' | 'drop' | 'query' | null>(null)\n\n/** Reset the data when the modal was closed */\nasync function resetData() {\n source.value = null\n integration.value = null\n eventType.value = null\n\n await nextTick()\n}\n\n/** Receive data from the paste event listener */\nasync function handleInput(\n newSource: string,\n newIntegration: string | null = null,\n newEventType: 'paste' | 'drop' | 'query',\n) {\n // Reset, to trigger the modal to reopen\n await resetData()\n\n // We skip the modal and directly import if the store is empty.\n if (workspaceStoreIsEmpty(store)) {\n console.info('Workspace store is empty, directly importing:', newSource)\n\n if (await handleImportCollection(newSource)) {\n return\n }\n\n console.warn('Failed to import the collection from:', newSource)\n }\n\n // Open the modal\n source.value = newSource\n integration.value = newIntegration\n eventType.value = newEventType\n}\n\nconst router = useRouter()\nconst { activeWorkspace } = useActiveEntities()\nconst { toast } = useToasts()\n\nfunction handleImportCollection(\n source: string | null | undefined,\n): Promise<boolean> {\n if (!source) {\n return Promise.resolve(false)\n }\n\n return new Promise<boolean>((resolve) => {\n void importCollection({\n store,\n workspace: activeWorkspace.value,\n source,\n // Use watch mode by default.\n watchMode: true,\n onSuccess(collection: Collection | undefined) {\n if (collection) {\n redirectToFirstRequestInCollection(collection)\n toast('Import successful', 'info')\n resolve(true)\n\n return\n }\n\n // If collection is undefined, consider it a failure\n toast('Import failed: No collection was created', 'error')\n\n resolve(false)\n },\n onError(error) {\n console.error('[importCollection]', error)\n const errorMessage = (error as Error)?.message || 'Unknown error'\n toast(`Import failed: ${errorMessage}`, 'error')\n\n resolve(false)\n },\n })\n })\n}\n\nfunction redirectToFirstRequestInCollection(collection?: Collection) {\n if (!collection) {\n return\n }\n\n router.push({\n name: 'request',\n params: {\n workspace: activeWorkspace.value?.uid,\n request: collection?.requests[0],\n },\n })\n}\n</script>\n\n<template>\n <!-- Modal -->\n <ImportCollectionModal\n :eventType=\"eventType\"\n :integration=\"integration\"\n :source=\"source\"\n @importFinished=\"resetData\" />\n\n <!-- Event listeners-->\n <PasteEventListener @input=\"handleInput\" />\n <DropEventListener @input=\"handleInput\" />\n <UrlQueryParameterChecker @input=\"handleInput\" />\n\n <!-- Wrapped content -->\n <slot />\n</template>\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { n as ROUTES, t as TheCommandPalette_default } from "./CommandPalette-
|
|
2
|
-
import { T as PathId, w as useActiveEntities } from "./store-
|
|
1
|
+
import { n as ROUTES, t as TheCommandPalette_default } from "./CommandPalette-BiA0IgO8.js";
|
|
2
|
+
import { T as PathId, w as useActiveEntities } from "./store-DaPoVtIS.js";
|
|
3
3
|
import { a as useLayout } from "./useSidebar-DLTwHDI-.js";
|
|
4
4
|
import { t as _plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BmmBcIzD.js";
|
|
5
5
|
import { Fragment, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, withCtx } from "vue";
|
|
@@ -278,4 +278,4 @@ var MainLayout_default = /* @__PURE__ */ defineComponent({
|
|
|
278
278
|
//#endregion
|
|
279
279
|
export { MainLayout_default as t };
|
|
280
280
|
|
|
281
|
-
//# sourceMappingURL=MainLayout-
|
|
281
|
+
//# sourceMappingURL=MainLayout-oMIJ5QXF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MainLayout-BEFMl1ud.js","names":[],"sources":["../src/components/SideNav/SideNavLink.vue","../src/components/SideNav/SideNavLink.vue","../src/components/SideNav/DownloadAppButton.vue","../src/components/SideNav/DownloadAppButton.vue","../src/components/SideNav/SideHelp.vue","../src/components/SideNav/SideHelp.vue","../src/components/SideNav/SideNavGroup.vue","../src/components/SideNav/SideNavGroup.vue","../src/components/SideNav/SideNavRouterLink.vue","../src/components/SideNav/SideNavRouterLink.vue","../src/components/SideNav/SideNav.vue","../src/components/SideNav/SideNav.vue","../src/layouts/App/MainLayout.vue","../src/layouts/App/MainLayout.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIcon, type Icon } from '@scalar/components'\nimport type { Component } from 'vue'\n\nimport { useLayout } from '@/hooks'\n\ndefineProps<{\n is?: Component | string\n active?: boolean\n icon: Icon\n}>()\n\nconst { layout } = useLayout()\n</script>\n<template>\n <component\n :is=\"is ?? 'a'\"\n class=\"hover:bg-b-3 hover:dark:bg-b-2 flex max-w-[37px] min-w-[37px] items-center justify-center rounded-lg p-2 no-underline\"\n :class=\"{\n 'bg-b-3 dark:bg-b-2 text-c-1 transition-none hover:cursor-default':\n active,\n 'sm:max-w-max sm:min-w-max sm:rounded sm:py-1.5': layout === 'web',\n }\">\n <slot name=\"icon\">\n <ScalarIcon\n :class=\"layout === 'web' ? 'sm:hidden' : ''\"\n :icon=\"icon\"\n thickness=\"1.5\" />\n </slot>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n <slot />\n </span>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon, type Icon } from '@scalar/components'\nimport type { Component } from 'vue'\n\nimport { useLayout } from '@/hooks'\n\ndefineProps<{\n is?: Component | string\n active?: boolean\n icon: Icon\n}>()\n\nconst { layout } = useLayout()\n</script>\n<template>\n <component\n :is=\"is ?? 'a'\"\n class=\"hover:bg-b-3 hover:dark:bg-b-2 flex max-w-[37px] min-w-[37px] items-center justify-center rounded-lg p-2 no-underline\"\n :class=\"{\n 'bg-b-3 dark:bg-b-2 text-c-1 transition-none hover:cursor-default':\n active,\n 'sm:max-w-max sm:min-w-max sm:rounded sm:py-1.5': layout === 'web',\n }\">\n <slot name=\"icon\">\n <ScalarIcon\n :class=\"layout === 'web' ? 'sm:hidden' : ''\"\n :icon=\"icon\"\n thickness=\"1.5\" />\n </slot>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n <slot />\n </span>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <SideNavLink\n class=\"download-app-button gap-2 !px-3 !py-1.5 sm:px-3\"\n href=\"https://scalar.com/download?utm_source=web_client&utm_medium=download_button&utm_campaign=topnav\"\n icon=\"Download\"\n target=\"_blank\">\n <template #icon>\n <ScalarIcon\n icon=\"Download\"\n size=\"sm\"\n thickness=\"2\" />\n </template>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n Download App\n </span>\n </SideNavLink>\n</template>\n<style scoped>\n.download-app-button {\n box-shadow: 0 0 0 0.5px var(--scalar-border-color);\n background: linear-gradient(rgba(255, 255, 255, 0.75), rgba(0, 0, 0, 0.035));\n}\n\n.dark-mode .download-app-button {\n background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.15));\n}\n\n.download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.035), rgba(255, 255, 255, 0.75));\n}\n\n.dark-mode .download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.1));\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <SideNavLink\n class=\"download-app-button gap-2 !px-3 !py-1.5 sm:px-3\"\n href=\"https://scalar.com/download?utm_source=web_client&utm_medium=download_button&utm_campaign=topnav\"\n icon=\"Download\"\n target=\"_blank\">\n <template #icon>\n <ScalarIcon\n icon=\"Download\"\n size=\"sm\"\n thickness=\"2\" />\n </template>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n Download App\n </span>\n </SideNavLink>\n</template>\n<style scoped>\n.download-app-button {\n box-shadow: 0 0 0 0.5px var(--scalar-border-color);\n background: linear-gradient(rgba(255, 255, 255, 0.75), rgba(0, 0, 0, 0.035));\n}\n\n.dark-mode .download-app-button {\n background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.15));\n}\n\n.download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.035), rgba(255, 255, 255, 0.75));\n}\n\n.dark-mode .download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.1));\n}\n</style>\n","<script setup lang=\"ts\">\nimport {\n ScalarDropdown,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\n\nimport SideNavLink from './SideNavLink.vue'\n</script>\n<template>\n <ScalarDropdown\n class=\"max-w-[150px]\"\n :placement=\"'top-end'\">\n <SideNavLink\n is=\"button\"\n icon=\"Help\"\n type=\"button\">\n About\n </SideNavLink>\n\n <!-- Help Menu -->\n <template #items>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Support</span>\n <a\n class=\"block no-underline\"\n href=\"https://discord.gg/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Discord\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Discord</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"GitHubLine\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>GitHub</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"mailto:support@scalar.com\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Email\"\n size=\"xs\" />\n </div>\n <span>Email</span>\n </ScalarDropdownItem>\n </a>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Product</span>\n <a\n class=\"block no-underline\"\n href=\"https://scalar.com/changelog\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Changelog\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Changelog</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar/issues/2669\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Roadmap\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Roadmap</span>\n </ScalarDropdownItem>\n </a>\n </template>\n </ScalarDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport {\n ScalarDropdown,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\n\nimport SideNavLink from './SideNavLink.vue'\n</script>\n<template>\n <ScalarDropdown\n class=\"max-w-[150px]\"\n :placement=\"'top-end'\">\n <SideNavLink\n is=\"button\"\n icon=\"Help\"\n type=\"button\">\n About\n </SideNavLink>\n\n <!-- Help Menu -->\n <template #items>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Support</span>\n <a\n class=\"block no-underline\"\n href=\"https://discord.gg/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Discord\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Discord</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"GitHubLine\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>GitHub</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"mailto:support@scalar.com\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Email\"\n size=\"xs\" />\n </div>\n <span>Email</span>\n </ScalarDropdownItem>\n </a>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Product</span>\n <a\n class=\"block no-underline\"\n href=\"https://scalar.com/changelog\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Changelog\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Changelog</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar/issues/2669\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Roadmap\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Roadmap</span>\n </ScalarDropdownItem>\n </a>\n </template>\n </ScalarDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <ul\n class=\"flex gap-1.5\"\n :class=\"layout === 'web' ? 'sm:gap-px sm:px-2' : 'sm:flex-col'\">\n <slot />\n </ul>\n</template>\n","<script setup lang=\"ts\">\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <ul\n class=\"flex gap-1.5\"\n :class=\"layout === 'web' ? 'sm:gap-px sm:px-2' : 'sm:flex-col'\">\n <slot />\n </ul>\n</template>\n","<script setup lang=\"ts\">\nimport type { Icon } from '@scalar/components'\nimport { RouterLink, type RouteLocationRaw } from 'vue-router'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\n\ndefineProps<{\n icon: Icon\n to: RouteLocationRaw\n active?: boolean\n}>()\n</script>\n<template>\n <SideNavLink\n :is=\"RouterLink\"\n :active=\"Boolean(active)\"\n :icon=\"icon\"\n :to=\"to\">\n <slot />\n </SideNavLink>\n</template>\n","<script setup lang=\"ts\">\nimport type { Icon } from '@scalar/components'\nimport { RouterLink, type RouteLocationRaw } from 'vue-router'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\n\ndefineProps<{\n icon: Icon\n to: RouteLocationRaw\n active?: boolean\n}>()\n</script>\n<template>\n <SideNavLink\n :is=\"RouterLink\"\n :active=\"Boolean(active)\"\n :icon=\"icon\"\n :to=\"to\">\n <slot />\n </SideNavLink>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport { useRouter } from 'vue-router'\n\nimport { ROUTES } from '@/constants'\nimport { useLayout } from '@/hooks'\nimport { PathId } from '@/routes'\nimport { useActiveEntities } from '@/store'\n\nimport DownloadAppButton from './DownloadAppButton.vue'\nimport SideHelp from './SideHelp.vue'\nimport SideNavGroup from './SideNavGroup.vue'\nimport SideNavRouterLink from './SideNavRouterLink.vue'\n\nconst { currentRoute } = useRouter()\nconst { layout } = useLayout()\n\nconst { activeWorkspace } = useActiveEntities()\n</script>\n<template>\n <nav\n aria-label=\"App Navigation\"\n class=\"app-drag-region flex items-center justify-center gap-1.5 pt-2 sm:justify-between\"\n :class=\"\n layout === 'web' ? 'h-header border !pt-0' : 'px-2 pb-2 sm:flex-col'\n \"\n role=\"navigation\">\n <SideNavGroup class=\"app-no-drag-region\">\n <a\n class=\"mr-3 ml-1 hidden items-center\"\n :class=\"{\n 'sm:flex': layout === 'web',\n }\"\n href=\"https://www.scalar.com\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n <!-- Everything, but settings -->\n <li\n v-for=\"({ icon, to, displayName }, i) in ROUTES.filter(\n (route) => route.to.name !== 'settings.default',\n )\"\n :key=\"i\">\n <SideNavRouterLink\n :active=\"\n Boolean(\n currentRoute.name === displayName.toLowerCase() ||\n (displayName.toLowerCase() === 'environment' &&\n currentRoute.name === 'environment.collection'),\n )\n \"\n :icon=\"icon\"\n :to=\"{\n ...to,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid ?? 'default',\n },\n }\">\n {{ displayName }}\n </SideNavRouterLink>\n </li>\n </SideNavGroup>\n <!-- Pinned to the bottom -->\n <SideNavGroup class=\"app-no-drag-region\">\n <li class=\"flex items-center\">\n <SideNavRouterLink\n :active=\"currentRoute.name === 'settings'\"\n icon=\"Settings\"\n :to=\"{\n name: `settings.default`,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid,\n },\n }\">\n Settings\n </SideNavRouterLink>\n </li>\n <li class=\"flex items-center\">\n <SideHelp />\n </li>\n <li\n v-if=\"layout !== 'desktop'\"\n class=\"hidden items-center justify-center sm:ml-1.5 sm:flex\">\n <DownloadAppButton />\n </li>\n </SideNavGroup>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport { useRouter } from 'vue-router'\n\nimport { ROUTES } from '@/constants'\nimport { useLayout } from '@/hooks'\nimport { PathId } from '@/routes'\nimport { useActiveEntities } from '@/store'\n\nimport DownloadAppButton from './DownloadAppButton.vue'\nimport SideHelp from './SideHelp.vue'\nimport SideNavGroup from './SideNavGroup.vue'\nimport SideNavRouterLink from './SideNavRouterLink.vue'\n\nconst { currentRoute } = useRouter()\nconst { layout } = useLayout()\n\nconst { activeWorkspace } = useActiveEntities()\n</script>\n<template>\n <nav\n aria-label=\"App Navigation\"\n class=\"app-drag-region flex items-center justify-center gap-1.5 pt-2 sm:justify-between\"\n :class=\"\n layout === 'web' ? 'h-header border !pt-0' : 'px-2 pb-2 sm:flex-col'\n \"\n role=\"navigation\">\n <SideNavGroup class=\"app-no-drag-region\">\n <a\n class=\"mr-3 ml-1 hidden items-center\"\n :class=\"{\n 'sm:flex': layout === 'web',\n }\"\n href=\"https://www.scalar.com\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n <!-- Everything, but settings -->\n <li\n v-for=\"({ icon, to, displayName }, i) in ROUTES.filter(\n (route) => route.to.name !== 'settings.default',\n )\"\n :key=\"i\">\n <SideNavRouterLink\n :active=\"\n Boolean(\n currentRoute.name === displayName.toLowerCase() ||\n (displayName.toLowerCase() === 'environment' &&\n currentRoute.name === 'environment.collection'),\n )\n \"\n :icon=\"icon\"\n :to=\"{\n ...to,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid ?? 'default',\n },\n }\">\n {{ displayName }}\n </SideNavRouterLink>\n </li>\n </SideNavGroup>\n <!-- Pinned to the bottom -->\n <SideNavGroup class=\"app-no-drag-region\">\n <li class=\"flex items-center\">\n <SideNavRouterLink\n :active=\"currentRoute.name === 'settings'\"\n icon=\"Settings\"\n :to=\"{\n name: `settings.default`,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid,\n },\n }\">\n Settings\n </SideNavRouterLink>\n </li>\n <li class=\"flex items-center\">\n <SideHelp />\n </li>\n <li\n v-if=\"layout !== 'desktop'\"\n class=\"hidden items-center justify-center sm:ml-1.5 sm:flex\">\n <DownloadAppButton />\n </li>\n </SideNavGroup>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { TheCommandPalette } from '@/components/CommandPalette'\nimport SideNav from '@/components/SideNav/SideNav.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <!-- min-h-0 is to allow scrolling of individual flex children -->\n <main\n class=\"flex min-h-0 flex-1 flex-col\"\n :class=\"layout === 'web' ? 'sm:flex-col' : 'sm:flex-row'\">\n <SideNav class=\"sidenav order-last sm:order-none\" />\n\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette />\n\n <div\n class=\"flex min-h-0 min-w-0 flex-1 flex-col\"\n :class=\"{\n 'border sm:mr-1.5 sm:mb-1.5 sm:rounded-lg sm:*:rounded-lg':\n layout === 'desktop',\n }\">\n <slot />\n </div>\n </main>\n</template>\n","<script setup lang=\"ts\">\nimport { TheCommandPalette } from '@/components/CommandPalette'\nimport SideNav from '@/components/SideNav/SideNav.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <!-- min-h-0 is to allow scrolling of individual flex children -->\n <main\n class=\"flex min-h-0 flex-1 flex-col\"\n :class=\"layout === 'web' ? 'sm:flex-col' : 'sm:flex-row'\">\n <SideNav class=\"sidenav order-last sm:order-none\" />\n\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette />\n\n <div\n class=\"flex min-h-0 min-w-0 flex-1 flex-col\"\n :class=\"{\n 'border sm:mr-1.5 sm:mb-1.5 sm:rounded-lg sm:*:rounded-lg':\n layout === 'desktop',\n }\">\n <slot />\n </div>\n </main>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MainLayout-oMIJ5QXF.js","names":[],"sources":["../src/components/SideNav/SideNavLink.vue","../src/components/SideNav/SideNavLink.vue","../src/components/SideNav/DownloadAppButton.vue","../src/components/SideNav/DownloadAppButton.vue","../src/components/SideNav/SideHelp.vue","../src/components/SideNav/SideHelp.vue","../src/components/SideNav/SideNavGroup.vue","../src/components/SideNav/SideNavGroup.vue","../src/components/SideNav/SideNavRouterLink.vue","../src/components/SideNav/SideNavRouterLink.vue","../src/components/SideNav/SideNav.vue","../src/components/SideNav/SideNav.vue","../src/layouts/App/MainLayout.vue","../src/layouts/App/MainLayout.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ScalarIcon, type Icon } from '@scalar/components'\nimport type { Component } from 'vue'\n\nimport { useLayout } from '@/hooks'\n\ndefineProps<{\n is?: Component | string\n active?: boolean\n icon: Icon\n}>()\n\nconst { layout } = useLayout()\n</script>\n<template>\n <component\n :is=\"is ?? 'a'\"\n class=\"hover:bg-b-3 hover:dark:bg-b-2 flex max-w-[37px] min-w-[37px] items-center justify-center rounded-lg p-2 no-underline\"\n :class=\"{\n 'bg-b-3 dark:bg-b-2 text-c-1 transition-none hover:cursor-default':\n active,\n 'sm:max-w-max sm:min-w-max sm:rounded sm:py-1.5': layout === 'web',\n }\">\n <slot name=\"icon\">\n <ScalarIcon\n :class=\"layout === 'web' ? 'sm:hidden' : ''\"\n :icon=\"icon\"\n thickness=\"1.5\" />\n </slot>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n <slot />\n </span>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon, type Icon } from '@scalar/components'\nimport type { Component } from 'vue'\n\nimport { useLayout } from '@/hooks'\n\ndefineProps<{\n is?: Component | string\n active?: boolean\n icon: Icon\n}>()\n\nconst { layout } = useLayout()\n</script>\n<template>\n <component\n :is=\"is ?? 'a'\"\n class=\"hover:bg-b-3 hover:dark:bg-b-2 flex max-w-[37px] min-w-[37px] items-center justify-center rounded-lg p-2 no-underline\"\n :class=\"{\n 'bg-b-3 dark:bg-b-2 text-c-1 transition-none hover:cursor-default':\n active,\n 'sm:max-w-max sm:min-w-max sm:rounded sm:py-1.5': layout === 'web',\n }\">\n <slot name=\"icon\">\n <ScalarIcon\n :class=\"layout === 'web' ? 'sm:hidden' : ''\"\n :icon=\"icon\"\n thickness=\"1.5\" />\n </slot>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n <slot />\n </span>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <SideNavLink\n class=\"download-app-button gap-2 !px-3 !py-1.5 sm:px-3\"\n href=\"https://scalar.com/download?utm_source=web_client&utm_medium=download_button&utm_campaign=topnav\"\n icon=\"Download\"\n target=\"_blank\">\n <template #icon>\n <ScalarIcon\n icon=\"Download\"\n size=\"sm\"\n thickness=\"2\" />\n </template>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n Download App\n </span>\n </SideNavLink>\n</template>\n<style scoped>\n.download-app-button {\n box-shadow: 0 0 0 0.5px var(--scalar-border-color);\n background: linear-gradient(rgba(255, 255, 255, 0.75), rgba(0, 0, 0, 0.035));\n}\n\n.dark-mode .download-app-button {\n background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.15));\n}\n\n.download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.035), rgba(255, 255, 255, 0.75));\n}\n\n.dark-mode .download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.1));\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <SideNavLink\n class=\"download-app-button gap-2 !px-3 !py-1.5 sm:px-3\"\n href=\"https://scalar.com/download?utm_source=web_client&utm_medium=download_button&utm_campaign=topnav\"\n icon=\"Download\"\n target=\"_blank\">\n <template #icon>\n <ScalarIcon\n icon=\"Download\"\n size=\"sm\"\n thickness=\"2\" />\n </template>\n <span\n class=\"sr-only text-sm font-medium\"\n :class=\"{ 'sm:not-sr-only': layout === 'web' }\">\n Download App\n </span>\n </SideNavLink>\n</template>\n<style scoped>\n.download-app-button {\n box-shadow: 0 0 0 0.5px var(--scalar-border-color);\n background: linear-gradient(rgba(255, 255, 255, 0.75), rgba(0, 0, 0, 0.035));\n}\n\n.dark-mode .download-app-button {\n background: linear-gradient(rgba(255, 255, 255, 0.1), rgba(0, 0, 0, 0.15));\n}\n\n.download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.035), rgba(255, 255, 255, 0.75));\n}\n\n.dark-mode .download-app-button:hover {\n background: linear-gradient(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.1));\n}\n</style>\n","<script setup lang=\"ts\">\nimport {\n ScalarDropdown,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\n\nimport SideNavLink from './SideNavLink.vue'\n</script>\n<template>\n <ScalarDropdown\n class=\"max-w-[150px]\"\n :placement=\"'top-end'\">\n <SideNavLink\n is=\"button\"\n icon=\"Help\"\n type=\"button\">\n About\n </SideNavLink>\n\n <!-- Help Menu -->\n <template #items>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Support</span>\n <a\n class=\"block no-underline\"\n href=\"https://discord.gg/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Discord\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Discord</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"GitHubLine\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>GitHub</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"mailto:support@scalar.com\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Email\"\n size=\"xs\" />\n </div>\n <span>Email</span>\n </ScalarDropdownItem>\n </a>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Product</span>\n <a\n class=\"block no-underline\"\n href=\"https://scalar.com/changelog\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Changelog\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Changelog</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar/issues/2669\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Roadmap\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Roadmap</span>\n </ScalarDropdownItem>\n </a>\n </template>\n </ScalarDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport {\n ScalarDropdown,\n ScalarDropdownItem,\n ScalarIcon,\n} from '@scalar/components'\n\nimport SideNavLink from './SideNavLink.vue'\n</script>\n<template>\n <ScalarDropdown\n class=\"max-w-[150px]\"\n :placement=\"'top-end'\">\n <SideNavLink\n is=\"button\"\n icon=\"Help\"\n type=\"button\">\n About\n </SideNavLink>\n\n <!-- Help Menu -->\n <template #items>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Support</span>\n <a\n class=\"block no-underline\"\n href=\"https://discord.gg/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Discord\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Discord</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"GitHubLine\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>GitHub</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"mailto:support@scalar.com\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Email\"\n size=\"xs\" />\n </div>\n <span>Email</span>\n </ScalarDropdownItem>\n </a>\n <span class=\"text-c-2 px-2.5 py-1.5 text-xs font-medium\">Product</span>\n <a\n class=\"block no-underline\"\n href=\"https://scalar.com/changelog\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Changelog\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Changelog</span>\n </ScalarDropdownItem>\n </a>\n <a\n class=\"block no-underline\"\n href=\"https://github.com/scalar/scalar/issues/2669\"\n target=\"_blank\">\n <ScalarDropdownItem class=\"flex w-full items-center gap-1.5\">\n <div class=\"flex items-center justify-center\">\n <ScalarIcon\n icon=\"Roadmap\"\n size=\"xs\"\n thickness=\"1.75\" />\n </div>\n <span>Roadmap</span>\n </ScalarDropdownItem>\n </a>\n </template>\n </ScalarDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <ul\n class=\"flex gap-1.5\"\n :class=\"layout === 'web' ? 'sm:gap-px sm:px-2' : 'sm:flex-col'\">\n <slot />\n </ul>\n</template>\n","<script setup lang=\"ts\">\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <ul\n class=\"flex gap-1.5\"\n :class=\"layout === 'web' ? 'sm:gap-px sm:px-2' : 'sm:flex-col'\">\n <slot />\n </ul>\n</template>\n","<script setup lang=\"ts\">\nimport type { Icon } from '@scalar/components'\nimport { RouterLink, type RouteLocationRaw } from 'vue-router'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\n\ndefineProps<{\n icon: Icon\n to: RouteLocationRaw\n active?: boolean\n}>()\n</script>\n<template>\n <SideNavLink\n :is=\"RouterLink\"\n :active=\"Boolean(active)\"\n :icon=\"icon\"\n :to=\"to\">\n <slot />\n </SideNavLink>\n</template>\n","<script setup lang=\"ts\">\nimport type { Icon } from '@scalar/components'\nimport { RouterLink, type RouteLocationRaw } from 'vue-router'\n\nimport SideNavLink from '@/components/SideNav/SideNavLink.vue'\n\ndefineProps<{\n icon: Icon\n to: RouteLocationRaw\n active?: boolean\n}>()\n</script>\n<template>\n <SideNavLink\n :is=\"RouterLink\"\n :active=\"Boolean(active)\"\n :icon=\"icon\"\n :to=\"to\">\n <slot />\n </SideNavLink>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport { useRouter } from 'vue-router'\n\nimport { ROUTES } from '@/constants'\nimport { useLayout } from '@/hooks'\nimport { PathId } from '@/routes'\nimport { useActiveEntities } from '@/store'\n\nimport DownloadAppButton from './DownloadAppButton.vue'\nimport SideHelp from './SideHelp.vue'\nimport SideNavGroup from './SideNavGroup.vue'\nimport SideNavRouterLink from './SideNavRouterLink.vue'\n\nconst { currentRoute } = useRouter()\nconst { layout } = useLayout()\n\nconst { activeWorkspace } = useActiveEntities()\n</script>\n<template>\n <nav\n aria-label=\"App Navigation\"\n class=\"app-drag-region flex items-center justify-center gap-1.5 pt-2 sm:justify-between\"\n :class=\"\n layout === 'web' ? 'h-header border !pt-0' : 'px-2 pb-2 sm:flex-col'\n \"\n role=\"navigation\">\n <SideNavGroup class=\"app-no-drag-region\">\n <a\n class=\"mr-3 ml-1 hidden items-center\"\n :class=\"{\n 'sm:flex': layout === 'web',\n }\"\n href=\"https://www.scalar.com\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n <!-- Everything, but settings -->\n <li\n v-for=\"({ icon, to, displayName }, i) in ROUTES.filter(\n (route) => route.to.name !== 'settings.default',\n )\"\n :key=\"i\">\n <SideNavRouterLink\n :active=\"\n Boolean(\n currentRoute.name === displayName.toLowerCase() ||\n (displayName.toLowerCase() === 'environment' &&\n currentRoute.name === 'environment.collection'),\n )\n \"\n :icon=\"icon\"\n :to=\"{\n ...to,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid ?? 'default',\n },\n }\">\n {{ displayName }}\n </SideNavRouterLink>\n </li>\n </SideNavGroup>\n <!-- Pinned to the bottom -->\n <SideNavGroup class=\"app-no-drag-region\">\n <li class=\"flex items-center\">\n <SideNavRouterLink\n :active=\"currentRoute.name === 'settings'\"\n icon=\"Settings\"\n :to=\"{\n name: `settings.default`,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid,\n },\n }\">\n Settings\n </SideNavRouterLink>\n </li>\n <li class=\"flex items-center\">\n <SideHelp />\n </li>\n <li\n v-if=\"layout !== 'desktop'\"\n class=\"hidden items-center justify-center sm:ml-1.5 sm:flex\">\n <DownloadAppButton />\n </li>\n </SideNavGroup>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { ScalarIcon } from '@scalar/components'\nimport { useRouter } from 'vue-router'\n\nimport { ROUTES } from '@/constants'\nimport { useLayout } from '@/hooks'\nimport { PathId } from '@/routes'\nimport { useActiveEntities } from '@/store'\n\nimport DownloadAppButton from './DownloadAppButton.vue'\nimport SideHelp from './SideHelp.vue'\nimport SideNavGroup from './SideNavGroup.vue'\nimport SideNavRouterLink from './SideNavRouterLink.vue'\n\nconst { currentRoute } = useRouter()\nconst { layout } = useLayout()\n\nconst { activeWorkspace } = useActiveEntities()\n</script>\n<template>\n <nav\n aria-label=\"App Navigation\"\n class=\"app-drag-region flex items-center justify-center gap-1.5 pt-2 sm:justify-between\"\n :class=\"\n layout === 'web' ? 'h-header border !pt-0' : 'px-2 pb-2 sm:flex-col'\n \"\n role=\"navigation\">\n <SideNavGroup class=\"app-no-drag-region\">\n <a\n class=\"mr-3 ml-1 hidden items-center\"\n :class=\"{\n 'sm:flex': layout === 'web',\n }\"\n href=\"https://www.scalar.com\"\n target=\"_blank\">\n <ScalarIcon\n icon=\"Logo\"\n size=\"xl\" />\n </a>\n <!-- Everything, but settings -->\n <li\n v-for=\"({ icon, to, displayName }, i) in ROUTES.filter(\n (route) => route.to.name !== 'settings.default',\n )\"\n :key=\"i\">\n <SideNavRouterLink\n :active=\"\n Boolean(\n currentRoute.name === displayName.toLowerCase() ||\n (displayName.toLowerCase() === 'environment' &&\n currentRoute.name === 'environment.collection'),\n )\n \"\n :icon=\"icon\"\n :to=\"{\n ...to,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid ?? 'default',\n },\n }\">\n {{ displayName }}\n </SideNavRouterLink>\n </li>\n </SideNavGroup>\n <!-- Pinned to the bottom -->\n <SideNavGroup class=\"app-no-drag-region\">\n <li class=\"flex items-center\">\n <SideNavRouterLink\n :active=\"currentRoute.name === 'settings'\"\n icon=\"Settings\"\n :to=\"{\n name: `settings.default`,\n params: {\n [PathId.Workspace]: activeWorkspace?.uid,\n },\n }\">\n Settings\n </SideNavRouterLink>\n </li>\n <li class=\"flex items-center\">\n <SideHelp />\n </li>\n <li\n v-if=\"layout !== 'desktop'\"\n class=\"hidden items-center justify-center sm:ml-1.5 sm:flex\">\n <DownloadAppButton />\n </li>\n </SideNavGroup>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { TheCommandPalette } from '@/components/CommandPalette'\nimport SideNav from '@/components/SideNav/SideNav.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <!-- min-h-0 is to allow scrolling of individual flex children -->\n <main\n class=\"flex min-h-0 flex-1 flex-col\"\n :class=\"layout === 'web' ? 'sm:flex-col' : 'sm:flex-row'\">\n <SideNav class=\"sidenav order-last sm:order-none\" />\n\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette />\n\n <div\n class=\"flex min-h-0 min-w-0 flex-1 flex-col\"\n :class=\"{\n 'border sm:mr-1.5 sm:mb-1.5 sm:rounded-lg sm:*:rounded-lg':\n layout === 'desktop',\n }\">\n <slot />\n </div>\n </main>\n</template>\n","<script setup lang=\"ts\">\nimport { TheCommandPalette } from '@/components/CommandPalette'\nimport SideNav from '@/components/SideNav/SideNav.vue'\nimport { useLayout } from '@/hooks'\n\nconst { layout } = useLayout()\n</script>\n<template>\n <!-- min-h-0 is to allow scrolling of individual flex children -->\n <main\n class=\"flex min-h-0 flex-1 flex-col\"\n :class=\"layout === 'web' ? 'sm:flex-col' : 'sm:flex-row'\">\n <SideNav class=\"sidenav order-last sm:order-none\" />\n\n <!-- Popup command palette to add resources from anywhere -->\n <TheCommandPalette />\n\n <div\n class=\"flex min-h-0 min-w-0 flex-1 flex-col\"\n :class=\"{\n 'border sm:mr-1.5 sm:mb-1.5 sm:rounded-lg sm:*:rounded-lg':\n layout === 'desktop',\n }\">\n <slot />\n </div>\n </main>\n</template>\n"],"mappings":"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"}
|