diff --git a/electron.vite.config.ts b/electron.vite.config.ts index ed5a7dad7..c53d4c87a 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -6,6 +6,7 @@ import { defineConfig } from "electron-vite"; import flow from "rollup-plugin-flow"; import { ViteImageOptimizer } from "vite-plugin-image-optimizer"; import { viteStaticCopy } from "vite-plugin-static-copy"; +import svgr from "vite-plugin-svgr"; import tsconfigPaths from "vite-tsconfig-paths"; export default defineConfig({ @@ -65,6 +66,10 @@ export default defineConfig({ viteStaticCopy({ targets: [{ src: "node_modules/monaco-editor/min/vs/*", dest: "monaco" }], }), + svgr({ + svgrOptions: { exportType: "default", ref: true, svgo: false, titleProp: true }, + include: "**/*.svg", + }), ], }, }); diff --git a/frontend/app/app.less b/frontend/app/app.less index c2c476b93..e5d5d496a 100644 --- a/frontend/app/app.less +++ b/frontend/app/app.less @@ -87,3 +87,7 @@ body { display: block; } } + +a { + color: var(--accent-color); +} diff --git a/frontend/app/asset/logo.svg b/frontend/app/asset/logo.svg new file mode 100644 index 000000000..51c1d820d --- /dev/null +++ b/frontend/app/asset/logo.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app/element/modal.less b/frontend/app/element/modal.less index b93b47e43..5339d03fb 100644 --- a/frontend/app/element/modal.less +++ b/frontend/app/element/modal.less @@ -7,7 +7,7 @@ left: 0; width: 100vw; height: 100%; - z-index: 100; + z-index: var(--zindex-elem-modal); background-color: rgba(21, 23, 21, 0.7); .modal { diff --git a/frontend/app/element/toggle.less b/frontend/app/element/toggle.less new file mode 100644 index 000000000..33c9766fc --- /dev/null +++ b/frontend/app/element/toggle.less @@ -0,0 +1,61 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +.check-toggle-wrapper { + user-select: none; + display: flex; + height: 100%; + align-items: center; + justify-content: center; + + .checkbox-toggle { + position: relative; + display: inline-block; + width: 32px; + height: 20px; + + input { + opacity: 0; + width: 0; + height: 0; + } + + .slider { + position: absolute; + cursor: pointer; + content: ""; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: var(--toggle-bg-color); + transition: 0.5s; + border-radius: 33px; + } + + .slider:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 3px; + bottom: 2px; + background-color: var(--toggle-thumb-color); + transition: 0.5s; + border-radius: 50%; + } + + input:checked + .slider { + background-color: var(--toggle-checked-bg-color); + } + + input:checked + .slider:before { + transform: translateX(11px); + } + } + + label { + cursor: pointer; + padding: 0 5px; + } +} diff --git a/frontend/app/element/toggle.tsx b/frontend/app/element/toggle.tsx new file mode 100644 index 000000000..25d6b31ae --- /dev/null +++ b/frontend/app/element/toggle.tsx @@ -0,0 +1,37 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import "./toggle.less"; + +interface ToggleProps { + checked: boolean; + onChange: (value: boolean) => void; + label?: string; + id?: string; +} + +const Toggle = ({ checked, onChange, label, id }: ToggleProps) => { + const handleChange = (e: any) => { + if (onChange != null) { + onChange(e.target.checked); + } + }; + + const inputId = id || `toggle-${Math.random().toString(36).substr(2, 9)}`; + + return ( +
+
+ + +
+ {label && ( + + )} +
+ ); +}; + +export { Toggle }; diff --git a/frontend/app/element/windowdrag.less b/frontend/app/element/windowdrag.less index 4bdebe0e1..795e7d645 100644 --- a/frontend/app/element/windowdrag.less +++ b/frontend/app/element/windowdrag.less @@ -3,5 +3,5 @@ .window-drag { -webkit-app-region: drag; - z-index: 100; + z-index: var(--zindex-window-drag); } diff --git a/frontend/app/modals/modal.less b/frontend/app/modals/modal.less new file mode 100644 index 000000000..dc9eff73d --- /dev/null +++ b/frontend/app/modals/modal.less @@ -0,0 +1,75 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +.modal-wrapper { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + display: flex; + justify-content: center; + align-items: center; + z-index: var(--zindex-modal-wrapper); + + .modal-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(21, 23, 21, 0.7); + z-index: var(--zindex-modal-backdrop); + } +} + +.modal { + z-index: var(--zindex-modal); + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 16px; + border-radius: 10px; + background: var(--modal-bg-color); + border: 1px solid var(--border-color); + box-shadow: 0px 5px 5px 5px rgba(0, 0, 0, 0.1); + + .modal-header { + width: 100%; + display: flex; + align-items: center; + padding: 12px 14px 12px 20px; + justify-content: space-between; + line-height: 20px; + border-bottom: 1px solid var(--modal-header-bottom-border-color); + user-select: none; + + .modal-title { + color: var(--main-text-color); + font-size: var(--title-font-size); + } + + button { + padding-right: 4px !important; + i { + font-size: 18px; + } + } + } + + .modal-body { + width: 100%; + padding: 0px 20px; + } + + .modal-footer { + display: flex; + justify-content: flex-end; + width: 100%; + padding: 0 20px 20px; + + button:last-child { + margin-left: 8px; + } + } +} diff --git a/frontend/app/modals/modal.tsx b/frontend/app/modals/modal.tsx new file mode 100644 index 000000000..6a891ad20 --- /dev/null +++ b/frontend/app/modals/modal.tsx @@ -0,0 +1,121 @@ +// Copyright 2023, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { Button } from "@/app/element/button"; +import ReactDOM from "react-dom"; + +import "./modal.less"; + +interface ModalHeaderProps { + title: React.ReactNode; + description?: string; + onClose?: () => void; +} + +const ModalHeader = ({ onClose, title, description }: ModalHeaderProps) => ( +
+ {typeof title === "string" ?

{title}

: title} + {description &&

{description}

} + {onClose && ( + + )} +
+); + +interface ModalContentProps { + children: React.ReactNode; +} + +function ModalContent({ children }: ModalContentProps) { + return
{children}
; +} + +interface ModalFooterProps { + okLabel?: string; + cancelLabel?: string; + onOk?: () => void; + onCancel?: () => void; +} + +const ModalFooter = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }: ModalFooterProps) => ( + +); + +interface ModalProps { + title: string; + children?: React.ReactNode; + description?: string; + okLabel?: string; + cancelLabel?: string; + className?: string; + onClickBackdrop?: () => void; + onOk?: () => void; + onCancel?: () => void; + onClose?: () => void; +} + +const Modal = ({ + children, + className, + title, + description, + cancelLabel, + okLabel, + onCancel, + onOk, + onClose, + onClickBackdrop, +}: ModalProps) => { + const renderBackdrop = (onClick) =>
; + + const renderModal = () => ( +
+ {renderBackdrop(onClickBackdrop)} +
+ + {children} + +
+
+ ); + + return ReactDOM.createPortal(renderModal(), document.getElementById("main")); +}; + +interface FlexiModalProps { + children?: React.ReactNode; + className?: string; + onClickBackdrop?: () => void; +} + +const FlexiModal = ({ children, className, onClickBackdrop }: FlexiModalProps) => { + const renderBackdrop = (onClick) =>
; + + const renderModal = () => ( +
+ {renderBackdrop(onClickBackdrop)} +
{children}
+
+ ); + + return ReactDOM.createPortal(renderModal(), document.getElementById("main")); +}; + +FlexiModal.Header = ModalHeader; +FlexiModal.Content = ModalContent; +FlexiModal.Footer = ModalFooter; + +export { FlexiModal, Modal }; diff --git a/frontend/app/modals/modalregistry.tsx b/frontend/app/modals/modalregistry.tsx new file mode 100644 index 000000000..3f5f48fdb --- /dev/null +++ b/frontend/app/modals/modalregistry.tsx @@ -0,0 +1,14 @@ +// Copyright 2023, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { TosModal } from "./tos"; +import { UserInputModal } from "./userinputmodal"; + +const modalRegistry: { [key: string]: React.ComponentType } = { + [TosModal.displayName || "TosModal"]: TosModal, + [UserInputModal.displayName || "UserInputModal"]: UserInputModal, +}; + +export const getModalComponent = (key: string): React.ComponentType | undefined => { + return modalRegistry[key]; +}; diff --git a/frontend/app/modals/modalsrenderer.tsx b/frontend/app/modals/modalsrenderer.tsx new file mode 100644 index 000000000..720b40803 --- /dev/null +++ b/frontend/app/modals/modalsrenderer.tsx @@ -0,0 +1,26 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import { atoms } from "@/store/global"; +import { modalsModel } from "@/store/modalmodel"; +import * as jotai from "jotai"; +import { getModalComponent } from "./modalregistry"; +import { TosModal } from "./tos"; + +const ModalsRenderer = () => { + const clientData = jotai.useAtomValue(atoms.client); + const [modals] = jotai.useAtom(modalsModel.modalsAtom); + const rtn: JSX.Element[] = []; + for (const modal of modals) { + const ModalComponent = getModalComponent(modal.displayName); + if (ModalComponent) { + rtn.push(); + } + } + if (!clientData.tosagreed) { + rtn.push(); + } + return <>{rtn}; +}; + +export { ModalsRenderer }; diff --git a/frontend/app/modals/tos.less b/frontend/app/modals/tos.less new file mode 100644 index 000000000..756326143 --- /dev/null +++ b/frontend/app/modals/tos.less @@ -0,0 +1,127 @@ +.tos-modal { + width: 640px; + + .modal-inner { + padding: 40px 76px; + gap: 32px; + display: flex; + flex-direction: column; + + header.tos-header { + flex-direction: column; + gap: var(--sizing-sm, 12px); + border-bottom: none; + padding: 0; + margin-bottom: 20px; + + .logo { + margin-bottom: 10px; + } + + .modal-title { + text-align: center; + font-size: 25px; + font-weight: 400; + color: var(--main-text-color); + } + + .modal-subtitle { + color: var(--main-text-color); + text-align: center; + + font-style: normal; + font-weight: 300; + line-height: 20px; + } + } + + .tos-content { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 32px; + width: 100%; + margin-bottom: 0; + + .content-section { + display: flex; + width: 100%; + align-items: center; + gap: 32px; + + .icon-wrapper { + .icon { + font-size: 32px; + color: rgba(255, 255, 255, 0.5); + } + + .fa-people-group { + font-size: 25px; + } + } + + .content-section-inner { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 4px; + flex: 1 0 0; + + .content-section-title { + color: var(--main-text-color); + font-style: normal; + line-height: 18px; + font-size: 16px; + margin-bottom: 5px; + } + + .content-section-text { + color: rgba(255, 255, 255, 0.7); + font-style: normal; + line-height: 20px; + } + + .content-section-field { + display: flex; + align-items: center; + gap: 8px; + } + + .check-toggle-wrapper { + margin-top: 5px; + + label { + font-size: 13px; + } + } + } + } + } + + footer { + .content-section-text { + text-align: center; + color: rgba(255, 255, 255, 0.7); + font-size: 11px; + } + + .button-wrapper { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + + button { + font-size: 14px; + margin-bottom: 28px; + color: #000; + font-weight: 600; + } + + button.disabled-button { + cursor: default; + } + } + } + } +} diff --git a/frontend/app/modals/tos.tsx b/frontend/app/modals/tos.tsx new file mode 100644 index 000000000..6bbea4e90 --- /dev/null +++ b/frontend/app/modals/tos.tsx @@ -0,0 +1,97 @@ +// Copyright 2024, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import Logo from "@/app/asset/logo.svg"; +import { Button } from "@/app/element/button"; +import * as services from "@/store/services"; +import { FlexiModal } from "./modal"; + +import "./tos.less"; + +const TosModal = () => { + const acceptTos = () => { + services.ClientService.AgreeTos(); + }; + + return ( + +
+
+
+ +
+
Welcome to Wave Terminal!
+
+
+
+
+ + + +
+
+
Support us on GitHub
+
+ We're open source and committed to providing a free terminal for individual + users. Please show your support by giving us a star on{" "} + + Github (wavetermdev/waveterm) + +
+
+
+
+
+ + + +
+
+
Join our Community
+
+ Get help, submit feature requests, report bugs, or just chat with fellow terminal + enthusiasts. +
+ + Join the Wave Discord Channel + +
+
+
+
+
+ +
+
+
Telemetry
+
+ We collect minimal anonymous + +  telemetry data  + + to help us understand how people are using Wave. +
+
+
+
+ +
+
+ ); +}; + +TosModal.displayName = "TosModal"; + +export { TosModal }; diff --git a/frontend/app/element/userinputmodal.less b/frontend/app/modals/userinputmodal.less similarity index 89% rename from frontend/app/element/userinputmodal.less rename to frontend/app/modals/userinputmodal.less index ccb93974d..18b17ac8a 100644 --- a/frontend/app/element/userinputmodal.less +++ b/frontend/app/modals/userinputmodal.less @@ -6,12 +6,13 @@ flex-direction: column; justify-content: space-between; gap: 1rem; + margin: 0 1rem 1rem 1rem; font: var(--fixed-font); color: var(--main-text-color); .userinput-markdown { - color: var(--main-text-color); + color: inherit; } .userinput-text { @@ -25,6 +26,7 @@ border: var(--border-color); padding: 5px 0 5px 16px; min-height: 30px; + color: inherit; &:hover { cursor: text; diff --git a/frontend/app/element/userinputmodal.tsx b/frontend/app/modals/userinputmodal.tsx similarity index 86% rename from frontend/app/element/userinputmodal.tsx rename to frontend/app/modals/userinputmodal.tsx index 84b647d80..e30e46cce 100644 --- a/frontend/app/element/userinputmodal.tsx +++ b/frontend/app/modals/userinputmodal.tsx @@ -1,18 +1,16 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { Modal } from "@/app/modals/modal"; import { Markdown } from "@/element/markdown"; -import { WaveModal } from "@/element/modal"; -import { atoms } from "@/store/global"; +import { modalsModel } from "@/store/modalmodel"; import * as keyutil from "@/util/keyutil"; -import * as jotai from "jotai"; import * as React from "react"; import { UserInputService } from "../store/services"; import "./userinputmodal.less"; -export const UserInputModal = (userInputRequest: UserInputRequest) => { - const setModals = jotai.useSetAtom(atoms.userInput); +const UserInputModal = (userInputRequest: UserInputRequest) => { const [responseText, setResponseText] = React.useState(""); const [countdown, setCountdown] = React.useState(Math.floor(userInputRequest.timeoutms / 1000)); const checkboxStatus = React.useRef(false); @@ -23,10 +21,7 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { requestid: userInputRequest.requestid, errormsg: "Canceled by the user", }); - setModals((prev) => { - prev.pop(); - return [...prev]; - }); + modalsModel.popModal(); }, [responseText, userInputRequest]); const handleSendText = React.useCallback(() => { @@ -36,10 +31,7 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { text: responseText, checkboxstat: checkboxStatus.current, }); - setModals((prev) => { - prev.pop(); - return [...prev]; - }); + modalsModel.popModal(); }, [responseText, userInputRequest]); const handleSendConfirm = React.useCallback(() => { @@ -49,10 +41,7 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { confirm: true, checkboxstat: checkboxStatus.current, }); - setModals((prev) => { - prev.pop(); - return [...prev]; - }); + modalsModel.popModal(); }, [userInputRequest]); const handleSubmit = React.useCallback(() => { @@ -119,15 +108,19 @@ export const UserInputModal = (userInputRequest: UserInputRequest) => { }, [countdown]); return ( - handleSubmit()} + onOk={() => handleSubmit()} onCancel={() => handleSendCancel()} >
{queryText} {inputBox}
-
+ ); }; + +UserInputModal.displayName = "UserInputModal"; + +export { UserInputModal }; diff --git a/frontend/app/store/global.ts b/frontend/app/store/global.ts index 379316aa5..74e6d3789 100644 --- a/frontend/app/store/global.ts +++ b/frontend/app/store/global.ts @@ -16,6 +16,7 @@ import * as layoututil from "@/util/layoututil"; import { produce } from "immer"; import * as jotai from "jotai"; import * as rxjs from "rxjs"; +import { modalsModel } from "./modalmodel"; import * as services from "./services"; import * as WOS from "./wos"; import { WSControl } from "./ws"; @@ -101,7 +102,6 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) { } return windowData.activetabid; }); - const userInputAtom = jotai.atom([]) as jotai.PrimitiveAtom>; atoms = { // initialized in wave.ts (will not be null inside of application) windowId: windowIdAtom, @@ -113,7 +113,6 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) { settingsConfigAtom: settingsConfigAtom, tabAtom: tabAtom, activeTabId: activeTabIdAtom, - userInput: userInputAtom, isFullScreen: isFullScreenAtom, }; } @@ -229,10 +228,8 @@ function handleWSEventMessage(msg: WSEventType) { return; } if (msg.eventtype == "userinput") { - // handle user input const data: UserInputRequest = msg.data; - console.log(data); - globalStore.set(atoms.userInput, (prev) => [...prev, data]); + modalsModel.pushModal("UserInputModal", { ...data }); return; } if (msg.eventtype == "blockfile") { diff --git a/frontend/app/store/modalmodel.ts b/frontend/app/store/modalmodel.ts new file mode 100644 index 000000000..9003c2516 --- /dev/null +++ b/frontend/app/store/modalmodel.ts @@ -0,0 +1,41 @@ +// Copyright 2023, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +import * as jotai from "jotai"; +import { globalStore } from "./global"; + +class ModalsModel { + modalsAtom: jotai.PrimitiveAtom>; + + constructor() { + this.modalsAtom = jotai.atom([]); + } + + pushModal = (displayName: string, props?: any) => { + const modals = globalStore.get(this.modalsAtom); + globalStore.set(this.modalsAtom, [...modals, { displayName, props }]); + }; + + popModal = (callback?: () => void) => { + const modals = globalStore.get(this.modalsAtom); + if (modals.length > 0) { + const updatedModals = modals.slice(0, -1); + globalStore.set(this.modalsAtom, updatedModals); + if (callback) callback(); + } + }; + + hasOpenModals(): boolean { + const modals = globalStore.get(this.modalsAtom); + return modals.length > 0; + } + + isModalOpen(displayName: string): boolean { + const modals = globalStore.get(this.modalsAtom); + return modals.some((modal) => modal.displayName === displayName); + } +} + +const modalsModel = new ModalsModel(); + +export { modalsModel }; diff --git a/frontend/app/store/services.ts b/frontend/app/store/services.ts index 8e2fcf778..b5f064a8a 100644 --- a/frontend/app/store/services.ts +++ b/frontend/app/store/services.ts @@ -22,6 +22,10 @@ export const BlockService = new BlockServiceType(); // clientservice.ClientService (client) class ClientServiceType { + // @returns object updates + AgreeTos(): Promise { + return WOS.callBackendService("client", "AgreeTos", Array.from(arguments)) + } FocusWindow(arg2: string): Promise { return WOS.callBackendService("client", "FocusWindow", Array.from(arguments)) } diff --git a/frontend/app/tab/tab.less b/frontend/app/tab/tab.less index b2eae8d91..d10ab58cc 100644 --- a/frontend/app/tab/tab.less +++ b/frontend/app/tab/tab.less @@ -46,7 +46,7 @@ left: 50%; transform: translate3d(-50%, -50%, 0); user-select: none; - z-index: 3; + z-index: var(--zindex-tab-name); font-size: 11px; font-weight: 500; @@ -71,7 +71,7 @@ justify-content: center; cursor: pointer; opacity: 0.5; - z-index: 3; + z-index: var(--zindex-tab-name); &:hover { opacity: 1; diff --git a/frontend/app/theme.less b/frontend/app/theme.less index 5ea6f6cb0..84143e73c 100644 --- a/frontend/app/theme.less +++ b/frontend/app/theme.less @@ -38,4 +38,34 @@ /* z-index values */ --zindex-header-hover: 100; --zindex-termstickers: 20; + --zindex-modal: 2; + --zindex-modal-wrapper: 500; + --zindex-modal-backdrop: 1; + --zindex-elem-modal: 100; + --zindex-window-drag: 100; + --zindex-tab-name: 3; + --zindex-layout-placeholder-container: 1; + --zindex-layout-overlay-container: 2; + + // z-indexes in xterm.css + // xterm-helpers: 5 + // xterm-helper-textarea: -5 + // composition-view: 1 + // xterm-message: 10 + // xterm-decoration: 6 + // xterm-decoration-top-layer: 7 + // xterm-decoration-overview-ruler: 8 + // xterm-decoration-top: 2 + + /* modal colors */ + --modal-bg-color: rgb(26, 28, 26); + --modal-header-bottom-border-color: rgba(241, 246, 243, 0.15); + + /* toggle colors */ + --toggle-bg-color: var(--border-color); + --toggle-thumb-color: var(--main-text-color); + --toggle-checked-bg-color: var(--accent-color); + + /* link color */ + --link-color: #58c142; } diff --git a/frontend/app/workspace/workspace.tsx b/frontend/app/workspace/workspace.tsx index 2b79325e2..38f177f7d 100644 --- a/frontend/app/workspace/workspace.tsx +++ b/frontend/app/workspace/workspace.tsx @@ -1,9 +1,9 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 +import { ModalsRenderer } from "@/app/modals/modalsrenderer"; import { TabBar } from "@/app/tab/tabbar"; import { TabContent } from "@/app/tab/tabcontent"; -import { UserInputModal } from "@/element/userinputmodal"; import { atoms, createBlock } from "@/store/global"; import * as services from "@/store/services"; import * as util from "@/util/util"; @@ -107,11 +107,10 @@ const Widgets = React.memo(() => { const WorkspaceElem = React.memo(() => { const windowData = jotai.useAtomValue(atoms.waveWindow); const activeTabId = windowData?.activetabid; - const modals = jotai.useAtomValue(atoms.userInput); const ws = jotai.useAtomValue(atoms.workspace); + return (
- {modals.length > 0 && }
{activeTabId == "" ? ( @@ -120,6 +119,7 @@ const WorkspaceElem = React.memo(() => { <> + )}
diff --git a/frontend/layout/lib/tilelayout.less b/frontend/layout/lib/tilelayout.less index a6dc4e5e3..4106e3fc4 100644 --- a/frontend/layout/lib/tilelayout.less +++ b/frontend/layout/lib/tilelayout.less @@ -21,11 +21,11 @@ } .placeholder-container { - z-index: 1; + z-index: var(--zindex-layout-placeholder-container); } .overlay-container { - z-index: 2; + z-index: var(--zindex-layout-overlay-container); } .overlay-node { diff --git a/frontend/types/custom.d.ts b/frontend/types/custom.d.ts index 7be0890af..d3bec07df 100644 --- a/frontend/types/custom.d.ts +++ b/frontend/types/custom.d.ts @@ -15,7 +15,6 @@ declare global { settingsConfigAtom: jotai.PrimitiveAtom; // driven from WOS, settings -- updated via WebSocket tabAtom: jotai.Atom; // driven from WOS activeTabId: jotai.Atom; // derrived from windowDataAtom - userInput: jotai.PrimitiveAtom>; isFullScreen: jotai.PrimitiveAtom; }; diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index 588af2e7c..31efef432 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -63,6 +63,7 @@ declare global { mainwindowid: string; windowids: string[]; meta: MetaType; + tosagreed?: number; }; // wshrpc.CommandAppendIJsonData diff --git a/frontend/util/util.ts b/frontend/util/util.ts index 9688a03ab..0671bbd94 100644 --- a/frontend/util/util.ts +++ b/frontend/util/util.ts @@ -197,6 +197,16 @@ function getCrypto() { } } +/** + * Generates an external link by appending the given URL to the "https://extern?" endpoint. + * + * @param {string} url - The URL to be encoded and appended to the external link. + * @return {string} The generated external link. + */ +function makeExternLink(url: string): string { + return "https://extern?" + encodeURIComponent(url); +} + export { base64ToArray, base64ToString, @@ -209,6 +219,7 @@ export { jotaiLoadableValue, jsonDeepEqual, lazy, + makeExternLink, makeIconClass, stringToBase64, useAtomValueSafe, diff --git a/package.json b/package.json index 117584fae..83a42ff6d 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "vite": "^5.3.5", "vite-plugin-image-optimizer": "^1.1.8", "vite-plugin-static-copy": "^1.0.6", + "vite-plugin-svgr": "^4.2.0", "vite-tsconfig-paths": "^4.3.2", "vitest": "^2.0.4" }, diff --git a/pkg/service/clientservice/clientservice.go b/pkg/service/clientservice/clientservice.go index 252fc1db5..486caa912 100644 --- a/pkg/service/clientservice/clientservice.go +++ b/pkg/service/clientservice/clientservice.go @@ -73,3 +73,18 @@ func (cs *ClientService) FocusWindow(ctx context.Context, windowId string) error client.WindowIds = utilfn.MoveSliceIdxToFront(client.WindowIds, winIdx) return wstore.DBUpdate(ctx, client) } + +func (cs *ClientService) AgreeTos(ctx context.Context) (wstore.UpdatesRtnType, error) { + ctx = wstore.ContextWithUpdates(ctx) + clientData, err := wstore.DBGetSingleton[*wstore.Client](ctx) + if err != nil { + return nil, fmt.Errorf("error getting client data: %w", err) + } + timestamp := time.Now().UnixMilli() + clientData.TosAgreed = timestamp + err = wstore.DBUpdate(ctx, clientData) + if err != nil { + return nil, fmt.Errorf("error updating client data: %w", err) + } + return wstore.ContextGetUpdatesRtn(ctx), nil +} diff --git a/pkg/wstore/wstore.go b/pkg/wstore/wstore.go index 507cb5b56..0efc14417 100644 --- a/pkg/wstore/wstore.go +++ b/pkg/wstore/wstore.go @@ -349,8 +349,8 @@ func CreateWindow(ctx context.Context) (*Window, error) { Y: 100, }, WinSize: WinSize{ - Width: 800, - Height: 600, + Width: 1200, + Height: 800, }, } err := DBInsert(ctx, window) diff --git a/pkg/wstore/wstore_types.go b/pkg/wstore/wstore_types.go index 593d970d2..b9d59befb 100644 --- a/pkg/wstore/wstore_types.go +++ b/pkg/wstore/wstore_types.go @@ -166,6 +166,7 @@ type Client struct { MainWindowId string `json:"mainwindowid"` // deprecated WindowIds []string `json:"windowids"` Meta map[string]any `json:"meta"` + TosAgreed int64 `json:"tosagreed,omitempty"` } func (*Client) GetOType() string { diff --git a/tsconfig.json b/tsconfig.json index 729a36205..ccabc961b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,6 +23,10 @@ "@/element/*": ["frontend/app/element/*"], "@/bindings/*": ["frontend/bindings/github.com/wavetermdev/thenextwave/pkg/service/*"], "@/gopkg/*": ["frontend/bindings/github.com/wavetermdev/thenextwave/pkg/*"], - } - } + }, + "types": [ + "vite/client", + "vite-plugin-svgr/client" + ] + }, } diff --git a/yarn.lock b/yarn.lock index ba9873dfd..6156172e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,6 +29,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/code-frame@npm:7.24.7" + dependencies: + "@babel/highlight": "npm:^7.24.7" + picocolors: "npm:^1.0.0" + checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.24.6": version: 7.24.6 resolution: "@babel/code-frame@npm:7.24.6" @@ -39,16 +49,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/code-frame@npm:7.24.7" - dependencies: - "@babel/highlight": "npm:^7.24.7" - picocolors: "npm:^1.0.0" - checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6 - languageName: node - linkType: hard - "@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.6": version: 7.24.6 resolution: "@babel/compat-data@npm:7.24.6" @@ -86,7 +86,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.24.7": +"@babel/core@npm:^7.21.3, @babel/core@npm:^7.24.7": version: 7.24.9 resolution: "@babel/core@npm:7.24.9" dependencies: @@ -1763,6 +1763,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.21.3, @babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9": + version: 7.24.9 + resolution: "@babel/types@npm:7.24.9" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.8" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10c0/4970b3481cab39c5c3fdb7c28c834df5c7049f3c7f43baeafe121bb05270ebf0da7c65b097abf314877f213baa591109c82204f30d66cdd46c22ece4a2f32415 + languageName: node + linkType: hard + "@babel/types@npm:^7.24.7": version: 7.24.7 resolution: "@babel/types@npm:7.24.7" @@ -1774,17 +1785,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.24.8, @babel/types@npm:^7.24.9": - version: 7.24.9 - resolution: "@babel/types@npm:7.24.9" - dependencies: - "@babel/helper-string-parser": "npm:^7.24.8" - "@babel/helper-validator-identifier": "npm:^7.24.7" - to-fast-properties: "npm:^2.0.0" - checksum: 10c0/4970b3481cab39c5c3fdb7c28c834df5c7049f3c7f43baeafe121bb05270ebf0da7c65b097abf314877f213baa591109c82204f30d66cdd46c22ece4a2f32415 - languageName: node - linkType: hard - "@base2/pretty-print-object@npm:1.0.1": version: 1.0.1 resolution: "@base2/pretty-print-object@npm:1.0.1" @@ -2603,7 +2603,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.2": +"@rollup/pluginutils@npm:^5.0.2, @rollup/pluginutils@npm:^5.0.5": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: @@ -3198,6 +3198,133 @@ __metadata: languageName: node linkType: hard +"@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/a50bd0baa34faf16bcba712091f94c7f0e230431fe99a9dfc3401fa92823ad3f68495b86ab9bf9044b53839e8c416cfbb37eb3f246ff33f261e0fa9ee1779c5b + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-attribute@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/8a98e59bd9971e066815b4129409932f7a4db4866834fe75677ea6d517972fb40b380a69a4413189f20e7947411f9ab1b0f029dd5e8068686a5a0188d3ccd4c7 + languageName: node + linkType: hard + +"@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-remove-jsx-empty-expression@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/517dcca75223bd05d3f056a8514dbba3031278bea4eadf0842c576d84f4651e7a4e0e7082d3ee4ef42456de0f9c4531d8a1917c04876ca64b014b859ca8f1bde + languageName: node + linkType: hard + +"@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-replace-jsx-attribute-value@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/004bd1892053b7e9c1b0bb14acc44e77634ec393722b87b1e4fae53e2c35122a2dd0d5c15e9070dbeec274e22e7693a2b8b48506733a8009ee92b12946fcb10a + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-dynamic-title@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/80e0a7fcf902f984c705051ca5c82ea6050ccbb70b651a8fea6d0eb5809e4dac274b49ea6be2d87f1eb9dfc0e2d6cdfffe1669ec2117f44b67a60a07d4c0b8b8 + languageName: node + linkType: hard + +"@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-svg-em-dimensions@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/73e92c8277a89279745c0c500f59f083279a8dc30cd552b22981fade2a77628fb2bd2819ee505725fcd2e93f923e3790b52efcff409a159e657b46604a0b9a21 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-plugin-transform-react-native-svg@npm:8.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/655ed6bc7a208ceaa4ecff0a54ccc36008c3cb31efa90d11e171cab325ebbb21aa78f09c7b65f9b3ddeda3a85f348c0c862902c48be13c14b4de165c847974e3 + languageName: node + linkType: hard + +"@svgr/babel-plugin-transform-svg-component@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/babel-plugin-transform-svg-component@npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/4ac00bb99a3db4ef05e4362f116a3c608ee365a2d26cf7318d8d41a4a5b30a02c80455cce0e62c65b60ed815b5d632bedabac2ccd4b56f998fadef5286e3ded4 + languageName: node + linkType: hard + +"@svgr/babel-preset@npm:8.1.0": + version: 8.1.0 + resolution: "@svgr/babel-preset@npm:8.1.0" + dependencies: + "@svgr/babel-plugin-add-jsx-attribute": "npm:8.0.0" + "@svgr/babel-plugin-remove-jsx-attribute": "npm:8.0.0" + "@svgr/babel-plugin-remove-jsx-empty-expression": "npm:8.0.0" + "@svgr/babel-plugin-replace-jsx-attribute-value": "npm:8.0.0" + "@svgr/babel-plugin-svg-dynamic-title": "npm:8.0.0" + "@svgr/babel-plugin-svg-em-dimensions": "npm:8.0.0" + "@svgr/babel-plugin-transform-react-native-svg": "npm:8.1.0" + "@svgr/babel-plugin-transform-svg-component": "npm:8.0.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/49367d3ad0831f79b1056871b91766246f449d4d1168623af5e283fbaefce4a01d77ab00de6b045b55e956f9aae27895823198493cd232d88d3435ea4517ffc5 + languageName: node + linkType: hard + +"@svgr/core@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/core@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@svgr/babel-preset": "npm:8.1.0" + camelcase: "npm:^6.2.0" + cosmiconfig: "npm:^8.1.3" + snake-case: "npm:^3.0.4" + checksum: 10c0/6a2f6b1bc79bce39f66f088d468985d518005fc5147ebf4f108570a933818b5951c2cb7da230ddff4b7c8028b5a672b2d33aa2acce012b8b9770073aa5a2d041 + languageName: node + linkType: hard + +"@svgr/hast-util-to-babel-ast@npm:8.0.0": + version: 8.0.0 + resolution: "@svgr/hast-util-to-babel-ast@npm:8.0.0" + dependencies: + "@babel/types": "npm:^7.21.3" + entities: "npm:^4.4.0" + checksum: 10c0/f4165b583ba9eaf6719e598977a7b3ed182f177983e55f9eb55a6a73982d81277510e9eb7ab41f255151fb9ed4edd11ac4bef95dd872f04ed64966d8c85e0f79 + languageName: node + linkType: hard + +"@svgr/plugin-jsx@npm:^8.1.0": + version: 8.1.0 + resolution: "@svgr/plugin-jsx@npm:8.1.0" + dependencies: + "@babel/core": "npm:^7.21.3" + "@svgr/babel-preset": "npm:8.1.0" + "@svgr/hast-util-to-babel-ast": "npm:8.0.0" + svg-parser: "npm:^2.0.4" + peerDependencies: + "@svgr/core": "*" + checksum: 10c0/07b4d9e00de795540bf70556fa2cc258774d01e97a12a26234c6fdf42b309beb7c10f31ee24d1a71137239347b1547b8bb5587d3a6de10669f95dcfe99cddc56 + languageName: node + linkType: hard + "@swc/core-darwin-arm64@npm:1.7.0": version: 1.7.0 resolution: "@swc/core-darwin-arm64@npm:1.7.0" @@ -4995,6 +5122,13 @@ __metadata: languageName: node linkType: hard +"camelcase@npm:^6.2.0": + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 10c0/0d701658219bd3116d12da3eab31acddb3f9440790c0792e0d398f0a520a6a4058018e546862b6fba89d7ae990efaeb97da71e1913e9ebf5a8b5621a3d55c710 + languageName: node + linkType: hard + "caniuse-lite@npm:^1.0.30001587": version: 1.0.30001617 resolution: "caniuse-lite@npm:1.0.30001617" @@ -5481,6 +5615,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.1.3": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a + languageName: node + linkType: hard + "crc@npm:^3.8.0": version: 3.8.0 resolution: "crc@npm:3.8.0" @@ -6148,6 +6299,16 @@ __metadata: languageName: node linkType: hard +"dot-case@npm:^3.0.4": + version: 3.0.4 + resolution: "dot-case@npm:3.0.4" + dependencies: + no-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/5b859ea65097a7ea870e2c91b5768b72ddf7fa947223fd29e167bcdff58fe731d941c48e47a38ec8aa8e43044c8fbd15cd8fa21689a526bc34b6548197cd5b05 + languageName: node + linkType: hard + "dotenv-expand@npm:^5.1.0": version: 5.1.0 resolution: "dotenv-expand@npm:5.1.0" @@ -6389,6 +6550,15 @@ __metadata: languageName: node linkType: hard +"error-ex@npm:^1.3.1": + version: 1.3.2 + resolution: "error-ex@npm:1.3.2" + dependencies: + is-arrayish: "npm:^0.2.1" + checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce + languageName: node + linkType: hard + "es-define-property@npm:^1.0.0": version: 1.0.0 resolution: "es-define-property@npm:1.0.0" @@ -7950,7 +8120,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -8065,6 +8235,13 @@ __metadata: languageName: node linkType: hard +"is-arrayish@npm:^0.2.1": + version: 0.2.1 + resolution: "is-arrayish@npm:0.2.1" + checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 + languageName: node + linkType: hard + "is-arrayish@npm:^0.3.1": version: 0.3.2 resolution: "is-arrayish@npm:0.3.2" @@ -8463,6 +8640,13 @@ __metadata: languageName: node linkType: hard +"json-parse-even-better-errors@npm:^2.3.0": + version: 2.3.1 + resolution: "json-parse-even-better-errors@npm:2.3.1" + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 + languageName: node + linkType: hard + "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -8607,6 +8791,13 @@ __metadata: languageName: node linkType: hard +"lines-and-columns@npm:^1.1.6": + version: 1.2.4 + resolution: "lines-and-columns@npm:1.2.4" + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d + languageName: node + linkType: hard + "locate-path@npm:^3.0.0": version: 3.0.0 resolution: "locate-path@npm:3.0.0" @@ -8730,6 +8921,15 @@ __metadata: languageName: node linkType: hard +"lower-case@npm:^2.0.2": + version: 2.0.2 + resolution: "lower-case@npm:2.0.2" + dependencies: + tslib: "npm:^2.0.3" + checksum: 10c0/3d925e090315cf7dc1caa358e0477e186ffa23947740e4314a7429b6e62d72742e0bbe7536a5ae56d19d7618ce998aba05caca53c2902bd5742fdca5fc57fd7b + languageName: node + linkType: hard + "lowercase-keys@npm:^2.0.0": version: 2.0.0 resolution: "lowercase-keys@npm:2.0.0" @@ -9753,6 +9953,16 @@ __metadata: languageName: node linkType: hard +"no-case@npm:^3.0.4": + version: 3.0.4 + resolution: "no-case@npm:3.0.4" + dependencies: + lower-case: "npm:^2.0.2" + tslib: "npm:^2.0.3" + checksum: 10c0/8ef545f0b3f8677c848f86ecbd42ca0ff3cd9dd71c158527b344c69ba14710d816d8489c746b6ca225e7b615108938a0bda0a54706f8c255933703ac1cf8e703 + languageName: node + linkType: hard + "node-addon-api@npm:^1.6.3": version: 1.7.2 resolution: "node-addon-api@npm:1.7.2" @@ -10091,6 +10301,18 @@ __metadata: languageName: node linkType: hard +"parse-json@npm:^5.2.0": + version: 5.2.0 + resolution: "parse-json@npm:5.2.0" + dependencies: + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 + languageName: node + linkType: hard + "parse-node-version@npm:^1.0.1": version: 1.0.1 resolution: "parse-node-version@npm:1.0.1" @@ -11437,6 +11659,16 @@ __metadata: languageName: node linkType: hard +"snake-case@npm:^3.0.4": + version: 3.0.4 + resolution: "snake-case@npm:3.0.4" + dependencies: + dot-case: "npm:^3.0.4" + tslib: "npm:^2.0.3" + checksum: 10c0/ab19a913969f58f4474fe9f6e8a026c8a2142a01f40b52b79368068343177f818cdfef0b0c6b9558f298782441d5ca8ed5932eb57822439fad791d866e62cecd + languageName: node + linkType: hard + "socks-proxy-agent@npm:^8.0.3": version: 8.0.3 resolution: "socks-proxy-agent@npm:8.0.3" @@ -11735,6 +11967,13 @@ __metadata: languageName: node linkType: hard +"svg-parser@npm:^2.0.4": + version: 2.0.4 + resolution: "svg-parser@npm:2.0.4" + checksum: 10c0/02f6cb155dd7b63ebc2f44f36365bc294543bebb81b614b7628f1af3c54ab64f7e1cec20f06e252bf95bdde78441ae295a412c68ad1678f16a6907d924512b7a + languageName: node + linkType: hard + "tar@npm:^6.1.11, tar@npm:^6.1.12, tar@npm:^6.1.2, tar@npm:^6.2.0": version: 6.2.1 resolution: "tar@npm:6.2.1" @@ -11905,6 +12144,7 @@ __metadata: vite: "npm:^5.3.5" vite-plugin-image-optimizer: "npm:^1.1.8" vite-plugin-static-copy: "npm:^1.0.6" + vite-plugin-svgr: "npm:^4.2.0" vite-tsconfig-paths: "npm:^4.3.2" vitest: "npm:^2.0.4" winston: "npm:^3.13.1" @@ -12136,7 +12376,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.6.3": +"tslib@npm:^2.0.3, tslib@npm:^2.6.3": version: 2.6.3 resolution: "tslib@npm:2.6.3" checksum: 10c0/2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a @@ -12656,6 +12896,19 @@ __metadata: languageName: node linkType: hard +"vite-plugin-svgr@npm:^4.2.0": + version: 4.2.0 + resolution: "vite-plugin-svgr@npm:4.2.0" + dependencies: + "@rollup/pluginutils": "npm:^5.0.5" + "@svgr/core": "npm:^8.1.0" + "@svgr/plugin-jsx": "npm:^8.1.0" + peerDependencies: + vite: ^2.6.0 || 3 || 4 || 5 + checksum: 10c0/0a6400f20905f53d08f1ce7d1f22d9a57db403e110e790f80c2e0411a0064a071a36b781f56f6823654f98052219171003f9ea023d4a31d930b4a4fc01776d1f + languageName: node + linkType: hard + "vite-tsconfig-paths@npm:^4.3.2": version: 4.3.2 resolution: "vite-tsconfig-paths@npm:4.3.2"