├── .gitignore ├── LICENSE ├── README.md ├── app.go ├── clipcapsule.gif ├── favicon.ico ├── frontend ├── index.html ├── package.json ├── package.json.md5 ├── pnpm-lock.yaml ├── postcss.config.cjs ├── src │ ├── App.css │ ├── App.tsx │ ├── assets │ │ ├── logo-2.png │ │ ├── logo.png │ │ └── wails.png │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts ├── tailwind.config.cjs ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts ├── go.mod ├── go.sum ├── main.go ├── scripts ├── build-macos-arm.sh ├── build-macos-intel.sh ├── build-macos.sh ├── build-windows.sh ├── build.sh └── install-wails-cli.sh ├── utils ├── db.go └── monitorClipboard.go ├── wails.json └── wails.toml /.gitignore: -------------------------------------------------------------------------------- 1 | # Go 2 | *.exe 3 | *.test 4 | *.out 5 | *.log 6 | *.db 7 | *.sqlite 8 | *.sqlite3 9 | 10 | # Go build artifacts 11 | /build 12 | /bin 13 | /dist 14 | *.so 15 | *.dll 16 | *.a 17 | 18 | # Wails build artifacts 19 | frontend/dist/ 20 | frontend/node_modules/ 21 | wailsjs/ 22 | 23 | # Runtime files 24 | .DS_Store 25 | *.tmp 26 | *.pid 27 | *.lock 28 | 29 | # Logs and debug 30 | *.log 31 | debug/ 32 | *.swp 33 | *.swo 34 | 35 | # VSCode/JetBrains/Editor stuff 36 | .vscode/ 37 | .idea/ 38 | *.code-workspace 39 | 40 | # OS files 41 | Thumbs.db 42 | ehthumbs.db 43 | Desktop.ini 44 | 45 | # npm / yarn 46 | node_modules/ 47 | package-lock.json 48 | yarn.lock 49 | 50 | # Environment / config 51 | .env 52 | .env.* 53 | .config 54 | *.local 55 | 56 | # Clipboard device or udev paths (if cached) 57 | keyboardid* 58 | deviceinfo* 59 | 60 | # Backup files 61 | *.bak 62 | *.old 63 | *~ 64 | 65 | # Repomix files (AI tools) 66 | repomix-output.xml 67 | 68 | # Wails build folders (depending on Wails version) 69 | frontend/wailsjs/go/ 70 | frontend/wailsjs/runtime/ 71 | 72 | # System generated 73 | *.crash 74 | 75 | 76 | frontend/vite.config.ts.timestamp-1745062894951.mjs 77 | 78 | .repomix* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Victor Evogor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📋 ClipCapsule 2 | 3 |

4 | Clipcapsule Preview 5 |

6 | 7 | 8 | 9 | **ClipCapsule** is a minimalist clipboard manager for Linux, built with **Go** and **WailsJS**. It supercharges your productivity by allowing you to manage and switch clipboard entries using only keyboard shortcuts—no mouse or GUI required. 10 | 11 | > ⚠️ This is a **work-in-progress** project. Currently, the GUI must be open for shortcuts to work, but we're actively working on a background daemon to make the app run seamlessly without launching the interface. 12 | 13 | --- 14 | 15 | ## ✨ Features 16 | 17 | - 🚀 **Keyboard-first Workflow**: Switch clipboard items instantly with `CTRL + SHIFT + 1~9`. 18 | - 📜 **Clipboard History**: Automatically saves your recent copies in an embedded database. 19 | - 🔄 **Dynamic Reordering**: Selecting an item with a shortcut moves it to the top of the stack. 20 | - 🔐 **Local-Only**: Your data stays on your machine, no cloud syncing or telemetry. 21 | 22 | --- 23 | 24 | ## 🖥️ Example Use 25 | 26 | When you copy items, the database stores them like this: 27 | 28 | | text | pos | 29 | |------------|-----| 30 | | item1text | 1 | 31 | | item2text | 2 | 32 | | item3text | 3 | 33 | | item4text | 4 | 34 | | item5text | 5 | 35 | | ... | ... | 36 | 37 | - The item at `pos = 1` is the active clipboard item (what gets pasted on `CTRL + V`). 38 | - Pressing `CTRL + SHIFT + 3`: 39 | - Moves `item3text` to position 1. 40 | - Reorders the rest accordingly. 41 | 42 | --- 43 | 44 | ## ⚙️ Installation 45 | 46 | ### 1. Clone the repo 47 | ```bash 48 | git clone https://github.com/Victor-Evogor/clipcapsule.git 49 | cd clipcapsule 50 | ``` 51 | 52 | ### 2. Install Wails 53 | 54 | Follow instructions from the [Wails documentation](https://wails.io/docs/gettingstarted/installation). 55 | 56 | ### 3. Build the application 57 | 58 | You'll need to build with elevated privileges to allow the app to listen for global key events: 59 | 60 | ```bash 61 | sudo wails build 62 | ``` 63 | 64 | > 🛑 Alternatively, give your user access to the keyboard input device path (e.g. `/dev/input/eventX`) by adding appropriate udev rules or group permissions. 65 | 66 | Example (for testing): 67 | ```bash 68 | sudo chmod a+r /dev/input/eventX 69 | ``` 70 | 71 | (Replace `/dev/input/eventX` with your actual keyboard event device.) 72 | 73 | > ⚠️ A proper fix for permissions will be added soon. For now, elevated privileges or manual access setup is required. 74 | 75 | --- 76 | 77 | ## ⌨️ Keyboard Shortcuts 78 | 79 | | Shortcut | Action | 80 | |----------------------|---------------------------------------------| 81 | | `CTRL + V` | Paste current top clipboard entry | 82 | | `CTRL + SHIFT + 1-9` | Move selected item to the top of the stack | 83 | 84 | --- 85 | 86 | ## 🛠️ Development 87 | 88 | - Frontend: Wails + JS/TS (see `frontend/`) 89 | - Backend: Go 90 | - Clipboard access and keyboard interception handled natively 91 | 92 | --- 93 | 94 | ## 🧱 Tech Stack 95 | 96 | - [Go](https://golang.org/) 97 | - [Wails](https://wails.io/) 98 | - [X11 Input](https://wiki.archlinux.org/title/X_keyboard_extension) (via raw device read) 99 | 100 | --- 101 | 102 | ## 🚧 Roadmap 103 | 104 | - [x] Core clipboard logic 105 | - [x] Keyboard shortcut mapping 106 | - [X] Clipboard preview UI 107 | - [ ] Daemon mode (run in background without GUI) 108 | - [ ] Tray icon & preferences 109 | - [ ] Configurable shortcuts 110 | - [ ] Exclude sensitive entries (e.g., passwords) 111 | 112 | --- 113 | 114 | ## 🐞 Known Issues 115 | 116 | - You need to run the app as `sudo` or manually allow access to keyboard input devices. 117 | - No daemon yet — GUI must be open for shortcuts to work. 118 | 119 | --- 120 | 121 | ## 🙌 Contributing 122 | 123 | PRs and issues are welcome! If you have ideas or find bugs, open an issue or submit a patch. 124 | 125 | --- 126 | 127 | ## 📄 License 128 | 129 | MIT License — see `LICENSE` file for details. 130 | -------------------------------------------------------------------------------- /app.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "clipcapsule/utils" 5 | "context" 6 | "fmt" 7 | 8 | "golang.design/x/clipboard" 9 | ) 10 | 11 | // App struct 12 | type App struct { 13 | ctx context.Context 14 | } 15 | 16 | // NewApp creates a new App application struct 17 | func NewApp() *App { 18 | return &App{} 19 | } 20 | 21 | // startup is called at application startup 22 | func (a *App) startup(ctx context.Context) { 23 | // Perform your setup here 24 | a.ctx = ctx 25 | } 26 | 27 | // domReady is called after front-end resources have been loaded 28 | func (a App) domReady(ctx context.Context) { 29 | // Add your action here 30 | } 31 | 32 | // beforeClose is called when the application is about to quit, 33 | // either by clicking the window close button or calling runtime.Quit. 34 | // Returning true will cause the application to continue, false will continue shutdown as normal. 35 | func (a *App) beforeClose(ctx context.Context) (prevent bool) { 36 | return false 37 | } 38 | 39 | // shutdown is called at application termination 40 | func (a *App) shutdown(ctx context.Context) { 41 | // Perform your teardown here 42 | } 43 | 44 | // Greet returns a greeting for the given name 45 | func (a *App) Greet(name string) string { 46 | return fmt.Sprintf("Hello %s, It's show time!", name) 47 | } 48 | 49 | func (a *App) GetHistory() []string { 50 | db := &utils.Db{} 51 | if err := db.New(); err != nil { 52 | panic(err) 53 | } 54 | history, err := db.FetchAllItems() 55 | 56 | if err != nil { 57 | return nil 58 | } 59 | 60 | var historyContents = []string{} 61 | for _, item := range history { 62 | historyContents = append(historyContents, item.Content) 63 | } 64 | 65 | return historyContents 66 | } 67 | 68 | func (a *App) UpdateHistory(newOrder []string) ([]utils.ClipboardItem, error) { 69 | db := utils.Db{} 70 | if err := db.New(); err != nil { 71 | return nil, err 72 | } 73 | items := db.UpdateAllItems(newOrder) 74 | if clipboard.Init() != nil { 75 | panic("failed to initialize clipboard") 76 | } 77 | if len((items)) > 0 { 78 | clipboard.Write(clipboard.FmtText, []byte(items[0].Content)) 79 | } else { 80 | clipboard.Write(clipboard.FmtText, []byte("")) 81 | } 82 | return items, nil 83 | } 84 | -------------------------------------------------------------------------------- /clipcapsule.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Victor-Evogor/clipcapsule/5370e2b20f46ce75f7f3a6254fc5c570fc7ffeed/clipcapsule.gif -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Victor-Evogor/clipcapsule/5370e2b20f46ce75f7f3a6254fc5c570fc7ffeed/favicon.ico -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vite + React + TS + Tailwind 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clipcapsule", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "@dnd-kit/core": "^6.3.1", 13 | "@dnd-kit/modifiers": "^9.0.0", 14 | "@dnd-kit/sortable": "^10.0.0", 15 | "@dnd-kit/utilities": "^3.2.2", 16 | "react": "^18.2.0", 17 | "react-dom": "^18.2.0" 18 | }, 19 | "devDependencies": { 20 | "@types/react": "^18.0.17", 21 | "@types/react-dom": "^18.0.6", 22 | "@vitejs/plugin-react": "^2.1.0", 23 | "autoprefixer": "^10.4.12", 24 | "postcss": "^8.4.17", 25 | "tailwindcss": "^3.1.8", 26 | "typescript": "^4.6.4", 27 | "vite": "^3.1.0" 28 | }, 29 | "author": "Victor Evogor" 30 | } -------------------------------------------------------------------------------- /frontend/package.json.md5: -------------------------------------------------------------------------------- 1 | 671c2da1020f77e38834876a970b75a6 -------------------------------------------------------------------------------- /frontend/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@dnd-kit/core': 12 | specifier: ^6.3.1 13 | version: 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 14 | '@dnd-kit/modifiers': 15 | specifier: ^9.0.0 16 | version: 9.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) 17 | '@dnd-kit/sortable': 18 | specifier: ^10.0.0 19 | version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) 20 | '@dnd-kit/utilities': 21 | specifier: ^3.2.2 22 | version: 3.2.2(react@18.3.1) 23 | react: 24 | specifier: ^18.2.0 25 | version: 18.3.1 26 | react-dom: 27 | specifier: ^18.2.0 28 | version: 18.3.1(react@18.3.1) 29 | devDependencies: 30 | '@types/react': 31 | specifier: ^18.0.17 32 | version: 18.3.20 33 | '@types/react-dom': 34 | specifier: ^18.0.6 35 | version: 18.3.6(@types/react@18.3.20) 36 | '@vitejs/plugin-react': 37 | specifier: ^2.1.0 38 | version: 2.2.0(vite@3.2.11) 39 | autoprefixer: 40 | specifier: ^10.4.12 41 | version: 10.4.21(postcss@8.5.3) 42 | postcss: 43 | specifier: ^8.4.17 44 | version: 8.5.3 45 | tailwindcss: 46 | specifier: ^3.1.8 47 | version: 3.4.17 48 | typescript: 49 | specifier: ^4.6.4 50 | version: 4.9.5 51 | vite: 52 | specifier: ^3.1.0 53 | version: 3.2.11 54 | 55 | packages: 56 | 57 | '@alloc/quick-lru@5.2.0': 58 | resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} 59 | engines: {node: '>=10'} 60 | 61 | '@ampproject/remapping@2.3.0': 62 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 63 | engines: {node: '>=6.0.0'} 64 | 65 | '@babel/code-frame@7.26.2': 66 | resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} 67 | engines: {node: '>=6.9.0'} 68 | 69 | '@babel/compat-data@7.26.8': 70 | resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} 71 | engines: {node: '>=6.9.0'} 72 | 73 | '@babel/core@7.26.10': 74 | resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} 75 | engines: {node: '>=6.9.0'} 76 | 77 | '@babel/generator@7.27.0': 78 | resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==} 79 | engines: {node: '>=6.9.0'} 80 | 81 | '@babel/helper-annotate-as-pure@7.25.9': 82 | resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} 83 | engines: {node: '>=6.9.0'} 84 | 85 | '@babel/helper-compilation-targets@7.27.0': 86 | resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==} 87 | engines: {node: '>=6.9.0'} 88 | 89 | '@babel/helper-module-imports@7.25.9': 90 | resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} 91 | engines: {node: '>=6.9.0'} 92 | 93 | '@babel/helper-module-transforms@7.26.0': 94 | resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} 95 | engines: {node: '>=6.9.0'} 96 | peerDependencies: 97 | '@babel/core': ^7.0.0 98 | 99 | '@babel/helper-plugin-utils@7.26.5': 100 | resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} 101 | engines: {node: '>=6.9.0'} 102 | 103 | '@babel/helper-string-parser@7.25.9': 104 | resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} 105 | engines: {node: '>=6.9.0'} 106 | 107 | '@babel/helper-validator-identifier@7.25.9': 108 | resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} 109 | engines: {node: '>=6.9.0'} 110 | 111 | '@babel/helper-validator-option@7.25.9': 112 | resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} 113 | engines: {node: '>=6.9.0'} 114 | 115 | '@babel/helpers@7.27.0': 116 | resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==} 117 | engines: {node: '>=6.9.0'} 118 | 119 | '@babel/parser@7.27.0': 120 | resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==} 121 | engines: {node: '>=6.0.0'} 122 | hasBin: true 123 | 124 | '@babel/plugin-syntax-jsx@7.25.9': 125 | resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} 126 | engines: {node: '>=6.9.0'} 127 | peerDependencies: 128 | '@babel/core': ^7.0.0-0 129 | 130 | '@babel/plugin-transform-react-jsx-development@7.25.9': 131 | resolution: {integrity: sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==} 132 | engines: {node: '>=6.9.0'} 133 | peerDependencies: 134 | '@babel/core': ^7.0.0-0 135 | 136 | '@babel/plugin-transform-react-jsx-self@7.25.9': 137 | resolution: {integrity: sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==} 138 | engines: {node: '>=6.9.0'} 139 | peerDependencies: 140 | '@babel/core': ^7.0.0-0 141 | 142 | '@babel/plugin-transform-react-jsx-source@7.25.9': 143 | resolution: {integrity: sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==} 144 | engines: {node: '>=6.9.0'} 145 | peerDependencies: 146 | '@babel/core': ^7.0.0-0 147 | 148 | '@babel/plugin-transform-react-jsx@7.25.9': 149 | resolution: {integrity: sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==} 150 | engines: {node: '>=6.9.0'} 151 | peerDependencies: 152 | '@babel/core': ^7.0.0-0 153 | 154 | '@babel/template@7.27.0': 155 | resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} 156 | engines: {node: '>=6.9.0'} 157 | 158 | '@babel/traverse@7.27.0': 159 | resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==} 160 | engines: {node: '>=6.9.0'} 161 | 162 | '@babel/types@7.27.0': 163 | resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} 164 | engines: {node: '>=6.9.0'} 165 | 166 | '@dnd-kit/accessibility@3.1.1': 167 | resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} 168 | peerDependencies: 169 | react: '>=16.8.0' 170 | 171 | '@dnd-kit/core@6.3.1': 172 | resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} 173 | peerDependencies: 174 | react: '>=16.8.0' 175 | react-dom: '>=16.8.0' 176 | 177 | '@dnd-kit/modifiers@9.0.0': 178 | resolution: {integrity: sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw==} 179 | peerDependencies: 180 | '@dnd-kit/core': ^6.3.0 181 | react: '>=16.8.0' 182 | 183 | '@dnd-kit/sortable@10.0.0': 184 | resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} 185 | peerDependencies: 186 | '@dnd-kit/core': ^6.3.0 187 | react: '>=16.8.0' 188 | 189 | '@dnd-kit/utilities@3.2.2': 190 | resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} 191 | peerDependencies: 192 | react: '>=16.8.0' 193 | 194 | '@esbuild/android-arm@0.15.18': 195 | resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} 196 | engines: {node: '>=12'} 197 | cpu: [arm] 198 | os: [android] 199 | 200 | '@esbuild/linux-loong64@0.15.18': 201 | resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} 202 | engines: {node: '>=12'} 203 | cpu: [loong64] 204 | os: [linux] 205 | 206 | '@isaacs/cliui@8.0.2': 207 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 208 | engines: {node: '>=12'} 209 | 210 | '@jridgewell/gen-mapping@0.3.8': 211 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 212 | engines: {node: '>=6.0.0'} 213 | 214 | '@jridgewell/resolve-uri@3.1.2': 215 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 216 | engines: {node: '>=6.0.0'} 217 | 218 | '@jridgewell/set-array@1.2.1': 219 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 220 | engines: {node: '>=6.0.0'} 221 | 222 | '@jridgewell/sourcemap-codec@1.5.0': 223 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 224 | 225 | '@jridgewell/trace-mapping@0.3.25': 226 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 227 | 228 | '@nodelib/fs.scandir@2.1.5': 229 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 230 | engines: {node: '>= 8'} 231 | 232 | '@nodelib/fs.stat@2.0.5': 233 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 234 | engines: {node: '>= 8'} 235 | 236 | '@nodelib/fs.walk@1.2.8': 237 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 238 | engines: {node: '>= 8'} 239 | 240 | '@pkgjs/parseargs@0.11.0': 241 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 242 | engines: {node: '>=14'} 243 | 244 | '@types/prop-types@15.7.14': 245 | resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} 246 | 247 | '@types/react-dom@18.3.6': 248 | resolution: {integrity: sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==} 249 | peerDependencies: 250 | '@types/react': ^18.0.0 251 | 252 | '@types/react@18.3.20': 253 | resolution: {integrity: sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==} 254 | 255 | '@vitejs/plugin-react@2.2.0': 256 | resolution: {integrity: sha512-FFpefhvExd1toVRlokZgxgy2JtnBOdp4ZDsq7ldCWaqGSGn9UhWMAVm/1lxPL14JfNS5yGz+s9yFrQY6shoStA==} 257 | engines: {node: ^14.18.0 || >=16.0.0} 258 | peerDependencies: 259 | vite: ^3.0.0 260 | 261 | ansi-regex@5.0.1: 262 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 263 | engines: {node: '>=8'} 264 | 265 | ansi-regex@6.1.0: 266 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 267 | engines: {node: '>=12'} 268 | 269 | ansi-styles@4.3.0: 270 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 271 | engines: {node: '>=8'} 272 | 273 | ansi-styles@6.2.1: 274 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 275 | engines: {node: '>=12'} 276 | 277 | any-promise@1.3.0: 278 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 279 | 280 | anymatch@3.1.3: 281 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} 282 | engines: {node: '>= 8'} 283 | 284 | arg@5.0.2: 285 | resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 286 | 287 | autoprefixer@10.4.21: 288 | resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} 289 | engines: {node: ^10 || ^12 || >=14} 290 | hasBin: true 291 | peerDependencies: 292 | postcss: ^8.1.0 293 | 294 | balanced-match@1.0.2: 295 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 296 | 297 | binary-extensions@2.3.0: 298 | resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} 299 | engines: {node: '>=8'} 300 | 301 | brace-expansion@2.0.1: 302 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 303 | 304 | braces@3.0.3: 305 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 306 | engines: {node: '>=8'} 307 | 308 | browserslist@4.24.4: 309 | resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} 310 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 311 | hasBin: true 312 | 313 | camelcase-css@2.0.1: 314 | resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} 315 | engines: {node: '>= 6'} 316 | 317 | caniuse-lite@1.0.30001712: 318 | resolution: {integrity: sha512-MBqPpGYYdQ7/hfKiet9SCI+nmN5/hp4ZzveOJubl5DTAMa5oggjAuoi0Z4onBpKPFI2ePGnQuQIzF3VxDjDJig==} 319 | 320 | chokidar@3.6.0: 321 | resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} 322 | engines: {node: '>= 8.10.0'} 323 | 324 | color-convert@2.0.1: 325 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 326 | engines: {node: '>=7.0.0'} 327 | 328 | color-name@1.1.4: 329 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 330 | 331 | commander@4.1.1: 332 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 333 | engines: {node: '>= 6'} 334 | 335 | convert-source-map@2.0.0: 336 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} 337 | 338 | cross-spawn@7.0.6: 339 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 340 | engines: {node: '>= 8'} 341 | 342 | cssesc@3.0.0: 343 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 344 | engines: {node: '>=4'} 345 | hasBin: true 346 | 347 | csstype@3.1.3: 348 | resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} 349 | 350 | debug@4.4.0: 351 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 352 | engines: {node: '>=6.0'} 353 | peerDependencies: 354 | supports-color: '*' 355 | peerDependenciesMeta: 356 | supports-color: 357 | optional: true 358 | 359 | didyoumean@1.2.2: 360 | resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} 361 | 362 | dlv@1.1.3: 363 | resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} 364 | 365 | eastasianwidth@0.2.0: 366 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 367 | 368 | electron-to-chromium@1.5.132: 369 | resolution: {integrity: sha512-QgX9EBvWGmvSRa74zqfnG7+Eno0Ak0vftBll0Pt2/z5b3bEGYL6OUXLgKPtvx73dn3dvwrlyVkjPKRRlhLYTEg==} 370 | 371 | emoji-regex@8.0.0: 372 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 373 | 374 | emoji-regex@9.2.2: 375 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 376 | 377 | esbuild-android-64@0.15.18: 378 | resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==} 379 | engines: {node: '>=12'} 380 | cpu: [x64] 381 | os: [android] 382 | 383 | esbuild-android-arm64@0.15.18: 384 | resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==} 385 | engines: {node: '>=12'} 386 | cpu: [arm64] 387 | os: [android] 388 | 389 | esbuild-darwin-64@0.15.18: 390 | resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==} 391 | engines: {node: '>=12'} 392 | cpu: [x64] 393 | os: [darwin] 394 | 395 | esbuild-darwin-arm64@0.15.18: 396 | resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==} 397 | engines: {node: '>=12'} 398 | cpu: [arm64] 399 | os: [darwin] 400 | 401 | esbuild-freebsd-64@0.15.18: 402 | resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==} 403 | engines: {node: '>=12'} 404 | cpu: [x64] 405 | os: [freebsd] 406 | 407 | esbuild-freebsd-arm64@0.15.18: 408 | resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==} 409 | engines: {node: '>=12'} 410 | cpu: [arm64] 411 | os: [freebsd] 412 | 413 | esbuild-linux-32@0.15.18: 414 | resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==} 415 | engines: {node: '>=12'} 416 | cpu: [ia32] 417 | os: [linux] 418 | 419 | esbuild-linux-64@0.15.18: 420 | resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==} 421 | engines: {node: '>=12'} 422 | cpu: [x64] 423 | os: [linux] 424 | 425 | esbuild-linux-arm64@0.15.18: 426 | resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==} 427 | engines: {node: '>=12'} 428 | cpu: [arm64] 429 | os: [linux] 430 | 431 | esbuild-linux-arm@0.15.18: 432 | resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==} 433 | engines: {node: '>=12'} 434 | cpu: [arm] 435 | os: [linux] 436 | 437 | esbuild-linux-mips64le@0.15.18: 438 | resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==} 439 | engines: {node: '>=12'} 440 | cpu: [mips64el] 441 | os: [linux] 442 | 443 | esbuild-linux-ppc64le@0.15.18: 444 | resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==} 445 | engines: {node: '>=12'} 446 | cpu: [ppc64] 447 | os: [linux] 448 | 449 | esbuild-linux-riscv64@0.15.18: 450 | resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==} 451 | engines: {node: '>=12'} 452 | cpu: [riscv64] 453 | os: [linux] 454 | 455 | esbuild-linux-s390x@0.15.18: 456 | resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==} 457 | engines: {node: '>=12'} 458 | cpu: [s390x] 459 | os: [linux] 460 | 461 | esbuild-netbsd-64@0.15.18: 462 | resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==} 463 | engines: {node: '>=12'} 464 | cpu: [x64] 465 | os: [netbsd] 466 | 467 | esbuild-openbsd-64@0.15.18: 468 | resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==} 469 | engines: {node: '>=12'} 470 | cpu: [x64] 471 | os: [openbsd] 472 | 473 | esbuild-sunos-64@0.15.18: 474 | resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} 475 | engines: {node: '>=12'} 476 | cpu: [x64] 477 | os: [sunos] 478 | 479 | esbuild-windows-32@0.15.18: 480 | resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==} 481 | engines: {node: '>=12'} 482 | cpu: [ia32] 483 | os: [win32] 484 | 485 | esbuild-windows-64@0.15.18: 486 | resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==} 487 | engines: {node: '>=12'} 488 | cpu: [x64] 489 | os: [win32] 490 | 491 | esbuild-windows-arm64@0.15.18: 492 | resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==} 493 | engines: {node: '>=12'} 494 | cpu: [arm64] 495 | os: [win32] 496 | 497 | esbuild@0.15.18: 498 | resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==} 499 | engines: {node: '>=12'} 500 | hasBin: true 501 | 502 | escalade@3.2.0: 503 | resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} 504 | engines: {node: '>=6'} 505 | 506 | fast-glob@3.3.3: 507 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 508 | engines: {node: '>=8.6.0'} 509 | 510 | fastq@1.19.1: 511 | resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} 512 | 513 | fill-range@7.1.1: 514 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 515 | engines: {node: '>=8'} 516 | 517 | foreground-child@3.3.1: 518 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 519 | engines: {node: '>=14'} 520 | 521 | fraction.js@4.3.7: 522 | resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} 523 | 524 | fsevents@2.3.3: 525 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 526 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 527 | os: [darwin] 528 | 529 | function-bind@1.1.2: 530 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 531 | 532 | gensync@1.0.0-beta.2: 533 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 534 | engines: {node: '>=6.9.0'} 535 | 536 | glob-parent@5.1.2: 537 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 538 | engines: {node: '>= 6'} 539 | 540 | glob-parent@6.0.2: 541 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 542 | engines: {node: '>=10.13.0'} 543 | 544 | glob@10.4.5: 545 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 546 | hasBin: true 547 | 548 | globals@11.12.0: 549 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 550 | engines: {node: '>=4'} 551 | 552 | hasown@2.0.2: 553 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 554 | engines: {node: '>= 0.4'} 555 | 556 | is-binary-path@2.1.0: 557 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 558 | engines: {node: '>=8'} 559 | 560 | is-core-module@2.16.1: 561 | resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 562 | engines: {node: '>= 0.4'} 563 | 564 | is-extglob@2.1.1: 565 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 566 | engines: {node: '>=0.10.0'} 567 | 568 | is-fullwidth-code-point@3.0.0: 569 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 570 | engines: {node: '>=8'} 571 | 572 | is-glob@4.0.3: 573 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 574 | engines: {node: '>=0.10.0'} 575 | 576 | is-number@7.0.0: 577 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 578 | engines: {node: '>=0.12.0'} 579 | 580 | isexe@2.0.0: 581 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 582 | 583 | jackspeak@3.4.3: 584 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 585 | 586 | jiti@1.21.7: 587 | resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} 588 | hasBin: true 589 | 590 | js-tokens@4.0.0: 591 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 592 | 593 | jsesc@3.1.0: 594 | resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} 595 | engines: {node: '>=6'} 596 | hasBin: true 597 | 598 | json5@2.2.3: 599 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} 600 | engines: {node: '>=6'} 601 | hasBin: true 602 | 603 | lilconfig@3.1.3: 604 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 605 | engines: {node: '>=14'} 606 | 607 | lines-and-columns@1.2.4: 608 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 609 | 610 | loose-envify@1.4.0: 611 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 612 | hasBin: true 613 | 614 | lru-cache@10.4.3: 615 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 616 | 617 | lru-cache@5.1.1: 618 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} 619 | 620 | magic-string@0.26.7: 621 | resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==} 622 | engines: {node: '>=12'} 623 | 624 | merge2@1.4.1: 625 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 626 | engines: {node: '>= 8'} 627 | 628 | micromatch@4.0.8: 629 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 630 | engines: {node: '>=8.6'} 631 | 632 | minimatch@9.0.5: 633 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 634 | engines: {node: '>=16 || 14 >=14.17'} 635 | 636 | minipass@7.1.2: 637 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 638 | engines: {node: '>=16 || 14 >=14.17'} 639 | 640 | ms@2.1.3: 641 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 642 | 643 | mz@2.7.0: 644 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 645 | 646 | nanoid@3.3.11: 647 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 648 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 649 | hasBin: true 650 | 651 | node-releases@2.0.19: 652 | resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} 653 | 654 | normalize-path@3.0.0: 655 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 656 | engines: {node: '>=0.10.0'} 657 | 658 | normalize-range@0.1.2: 659 | resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} 660 | engines: {node: '>=0.10.0'} 661 | 662 | object-assign@4.1.1: 663 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 664 | engines: {node: '>=0.10.0'} 665 | 666 | object-hash@3.0.0: 667 | resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} 668 | engines: {node: '>= 6'} 669 | 670 | package-json-from-dist@1.0.1: 671 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 672 | 673 | path-key@3.1.1: 674 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 675 | engines: {node: '>=8'} 676 | 677 | path-parse@1.0.7: 678 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 679 | 680 | path-scurry@1.11.1: 681 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 682 | engines: {node: '>=16 || 14 >=14.18'} 683 | 684 | picocolors@1.1.1: 685 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 686 | 687 | picomatch@2.3.1: 688 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 689 | engines: {node: '>=8.6'} 690 | 691 | pify@2.3.0: 692 | resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} 693 | engines: {node: '>=0.10.0'} 694 | 695 | pirates@4.0.7: 696 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 697 | engines: {node: '>= 6'} 698 | 699 | postcss-import@15.1.0: 700 | resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} 701 | engines: {node: '>=14.0.0'} 702 | peerDependencies: 703 | postcss: ^8.0.0 704 | 705 | postcss-js@4.0.1: 706 | resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} 707 | engines: {node: ^12 || ^14 || >= 16} 708 | peerDependencies: 709 | postcss: ^8.4.21 710 | 711 | postcss-load-config@4.0.2: 712 | resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} 713 | engines: {node: '>= 14'} 714 | peerDependencies: 715 | postcss: '>=8.0.9' 716 | ts-node: '>=9.0.0' 717 | peerDependenciesMeta: 718 | postcss: 719 | optional: true 720 | ts-node: 721 | optional: true 722 | 723 | postcss-nested@6.2.0: 724 | resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} 725 | engines: {node: '>=12.0'} 726 | peerDependencies: 727 | postcss: ^8.2.14 728 | 729 | postcss-selector-parser@6.1.2: 730 | resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} 731 | engines: {node: '>=4'} 732 | 733 | postcss-value-parser@4.2.0: 734 | resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 735 | 736 | postcss@8.5.3: 737 | resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} 738 | engines: {node: ^10 || ^12 || >=14} 739 | 740 | queue-microtask@1.2.3: 741 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 742 | 743 | react-dom@18.3.1: 744 | resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} 745 | peerDependencies: 746 | react: ^18.3.1 747 | 748 | react-refresh@0.14.2: 749 | resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} 750 | engines: {node: '>=0.10.0'} 751 | 752 | react@18.3.1: 753 | resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} 754 | engines: {node: '>=0.10.0'} 755 | 756 | read-cache@1.0.0: 757 | resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} 758 | 759 | readdirp@3.6.0: 760 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 761 | engines: {node: '>=8.10.0'} 762 | 763 | resolve@1.22.10: 764 | resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} 765 | engines: {node: '>= 0.4'} 766 | hasBin: true 767 | 768 | reusify@1.1.0: 769 | resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} 770 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 771 | 772 | rollup@2.79.2: 773 | resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} 774 | engines: {node: '>=10.0.0'} 775 | hasBin: true 776 | 777 | run-parallel@1.2.0: 778 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 779 | 780 | scheduler@0.23.2: 781 | resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} 782 | 783 | semver@6.3.1: 784 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} 785 | hasBin: true 786 | 787 | shebang-command@2.0.0: 788 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 789 | engines: {node: '>=8'} 790 | 791 | shebang-regex@3.0.0: 792 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 793 | engines: {node: '>=8'} 794 | 795 | signal-exit@4.1.0: 796 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 797 | engines: {node: '>=14'} 798 | 799 | source-map-js@1.2.1: 800 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 801 | engines: {node: '>=0.10.0'} 802 | 803 | sourcemap-codec@1.4.8: 804 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 805 | deprecated: Please use @jridgewell/sourcemap-codec instead 806 | 807 | string-width@4.2.3: 808 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 809 | engines: {node: '>=8'} 810 | 811 | string-width@5.1.2: 812 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 813 | engines: {node: '>=12'} 814 | 815 | strip-ansi@6.0.1: 816 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 817 | engines: {node: '>=8'} 818 | 819 | strip-ansi@7.1.0: 820 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 821 | engines: {node: '>=12'} 822 | 823 | sucrase@3.35.0: 824 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 825 | engines: {node: '>=16 || 14 >=14.17'} 826 | hasBin: true 827 | 828 | supports-preserve-symlinks-flag@1.0.0: 829 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 830 | engines: {node: '>= 0.4'} 831 | 832 | tailwindcss@3.4.17: 833 | resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} 834 | engines: {node: '>=14.0.0'} 835 | hasBin: true 836 | 837 | thenify-all@1.6.0: 838 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 839 | engines: {node: '>=0.8'} 840 | 841 | thenify@3.3.1: 842 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 843 | 844 | to-regex-range@5.0.1: 845 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 846 | engines: {node: '>=8.0'} 847 | 848 | ts-interface-checker@0.1.13: 849 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 850 | 851 | tslib@2.8.1: 852 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 853 | 854 | typescript@4.9.5: 855 | resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} 856 | engines: {node: '>=4.2.0'} 857 | hasBin: true 858 | 859 | update-browserslist-db@1.1.3: 860 | resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} 861 | hasBin: true 862 | peerDependencies: 863 | browserslist: '>= 4.21.0' 864 | 865 | util-deprecate@1.0.2: 866 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 867 | 868 | vite@3.2.11: 869 | resolution: {integrity: sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==} 870 | engines: {node: ^14.18.0 || >=16.0.0} 871 | hasBin: true 872 | peerDependencies: 873 | '@types/node': '>= 14' 874 | less: '*' 875 | sass: '*' 876 | stylus: '*' 877 | sugarss: '*' 878 | terser: ^5.4.0 879 | peerDependenciesMeta: 880 | '@types/node': 881 | optional: true 882 | less: 883 | optional: true 884 | sass: 885 | optional: true 886 | stylus: 887 | optional: true 888 | sugarss: 889 | optional: true 890 | terser: 891 | optional: true 892 | 893 | which@2.0.2: 894 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 895 | engines: {node: '>= 8'} 896 | hasBin: true 897 | 898 | wrap-ansi@7.0.0: 899 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 900 | engines: {node: '>=10'} 901 | 902 | wrap-ansi@8.1.0: 903 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 904 | engines: {node: '>=12'} 905 | 906 | yallist@3.1.1: 907 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} 908 | 909 | yaml@2.7.1: 910 | resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} 911 | engines: {node: '>= 14'} 912 | hasBin: true 913 | 914 | snapshots: 915 | 916 | '@alloc/quick-lru@5.2.0': {} 917 | 918 | '@ampproject/remapping@2.3.0': 919 | dependencies: 920 | '@jridgewell/gen-mapping': 0.3.8 921 | '@jridgewell/trace-mapping': 0.3.25 922 | 923 | '@babel/code-frame@7.26.2': 924 | dependencies: 925 | '@babel/helper-validator-identifier': 7.25.9 926 | js-tokens: 4.0.0 927 | picocolors: 1.1.1 928 | 929 | '@babel/compat-data@7.26.8': {} 930 | 931 | '@babel/core@7.26.10': 932 | dependencies: 933 | '@ampproject/remapping': 2.3.0 934 | '@babel/code-frame': 7.26.2 935 | '@babel/generator': 7.27.0 936 | '@babel/helper-compilation-targets': 7.27.0 937 | '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10) 938 | '@babel/helpers': 7.27.0 939 | '@babel/parser': 7.27.0 940 | '@babel/template': 7.27.0 941 | '@babel/traverse': 7.27.0 942 | '@babel/types': 7.27.0 943 | convert-source-map: 2.0.0 944 | debug: 4.4.0 945 | gensync: 1.0.0-beta.2 946 | json5: 2.2.3 947 | semver: 6.3.1 948 | transitivePeerDependencies: 949 | - supports-color 950 | 951 | '@babel/generator@7.27.0': 952 | dependencies: 953 | '@babel/parser': 7.27.0 954 | '@babel/types': 7.27.0 955 | '@jridgewell/gen-mapping': 0.3.8 956 | '@jridgewell/trace-mapping': 0.3.25 957 | jsesc: 3.1.0 958 | 959 | '@babel/helper-annotate-as-pure@7.25.9': 960 | dependencies: 961 | '@babel/types': 7.27.0 962 | 963 | '@babel/helper-compilation-targets@7.27.0': 964 | dependencies: 965 | '@babel/compat-data': 7.26.8 966 | '@babel/helper-validator-option': 7.25.9 967 | browserslist: 4.24.4 968 | lru-cache: 5.1.1 969 | semver: 6.3.1 970 | 971 | '@babel/helper-module-imports@7.25.9': 972 | dependencies: 973 | '@babel/traverse': 7.27.0 974 | '@babel/types': 7.27.0 975 | transitivePeerDependencies: 976 | - supports-color 977 | 978 | '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)': 979 | dependencies: 980 | '@babel/core': 7.26.10 981 | '@babel/helper-module-imports': 7.25.9 982 | '@babel/helper-validator-identifier': 7.25.9 983 | '@babel/traverse': 7.27.0 984 | transitivePeerDependencies: 985 | - supports-color 986 | 987 | '@babel/helper-plugin-utils@7.26.5': {} 988 | 989 | '@babel/helper-string-parser@7.25.9': {} 990 | 991 | '@babel/helper-validator-identifier@7.25.9': {} 992 | 993 | '@babel/helper-validator-option@7.25.9': {} 994 | 995 | '@babel/helpers@7.27.0': 996 | dependencies: 997 | '@babel/template': 7.27.0 998 | '@babel/types': 7.27.0 999 | 1000 | '@babel/parser@7.27.0': 1001 | dependencies: 1002 | '@babel/types': 7.27.0 1003 | 1004 | '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.10)': 1005 | dependencies: 1006 | '@babel/core': 7.26.10 1007 | '@babel/helper-plugin-utils': 7.26.5 1008 | 1009 | '@babel/plugin-transform-react-jsx-development@7.25.9(@babel/core@7.26.10)': 1010 | dependencies: 1011 | '@babel/core': 7.26.10 1012 | '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) 1013 | transitivePeerDependencies: 1014 | - supports-color 1015 | 1016 | '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.10)': 1017 | dependencies: 1018 | '@babel/core': 7.26.10 1019 | '@babel/helper-plugin-utils': 7.26.5 1020 | 1021 | '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.10)': 1022 | dependencies: 1023 | '@babel/core': 7.26.10 1024 | '@babel/helper-plugin-utils': 7.26.5 1025 | 1026 | '@babel/plugin-transform-react-jsx@7.25.9(@babel/core@7.26.10)': 1027 | dependencies: 1028 | '@babel/core': 7.26.10 1029 | '@babel/helper-annotate-as-pure': 7.25.9 1030 | '@babel/helper-module-imports': 7.25.9 1031 | '@babel/helper-plugin-utils': 7.26.5 1032 | '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10) 1033 | '@babel/types': 7.27.0 1034 | transitivePeerDependencies: 1035 | - supports-color 1036 | 1037 | '@babel/template@7.27.0': 1038 | dependencies: 1039 | '@babel/code-frame': 7.26.2 1040 | '@babel/parser': 7.27.0 1041 | '@babel/types': 7.27.0 1042 | 1043 | '@babel/traverse@7.27.0': 1044 | dependencies: 1045 | '@babel/code-frame': 7.26.2 1046 | '@babel/generator': 7.27.0 1047 | '@babel/parser': 7.27.0 1048 | '@babel/template': 7.27.0 1049 | '@babel/types': 7.27.0 1050 | debug: 4.4.0 1051 | globals: 11.12.0 1052 | transitivePeerDependencies: 1053 | - supports-color 1054 | 1055 | '@babel/types@7.27.0': 1056 | dependencies: 1057 | '@babel/helper-string-parser': 7.25.9 1058 | '@babel/helper-validator-identifier': 7.25.9 1059 | 1060 | '@dnd-kit/accessibility@3.1.1(react@18.3.1)': 1061 | dependencies: 1062 | react: 18.3.1 1063 | tslib: 2.8.1 1064 | 1065 | '@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': 1066 | dependencies: 1067 | '@dnd-kit/accessibility': 3.1.1(react@18.3.1) 1068 | '@dnd-kit/utilities': 3.2.2(react@18.3.1) 1069 | react: 18.3.1 1070 | react-dom: 18.3.1(react@18.3.1) 1071 | tslib: 2.8.1 1072 | 1073 | '@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': 1074 | dependencies: 1075 | '@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1076 | '@dnd-kit/utilities': 3.2.2(react@18.3.1) 1077 | react: 18.3.1 1078 | tslib: 2.8.1 1079 | 1080 | '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)': 1081 | dependencies: 1082 | '@dnd-kit/core': 6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) 1083 | '@dnd-kit/utilities': 3.2.2(react@18.3.1) 1084 | react: 18.3.1 1085 | tslib: 2.8.1 1086 | 1087 | '@dnd-kit/utilities@3.2.2(react@18.3.1)': 1088 | dependencies: 1089 | react: 18.3.1 1090 | tslib: 2.8.1 1091 | 1092 | '@esbuild/android-arm@0.15.18': 1093 | optional: true 1094 | 1095 | '@esbuild/linux-loong64@0.15.18': 1096 | optional: true 1097 | 1098 | '@isaacs/cliui@8.0.2': 1099 | dependencies: 1100 | string-width: 5.1.2 1101 | string-width-cjs: string-width@4.2.3 1102 | strip-ansi: 7.1.0 1103 | strip-ansi-cjs: strip-ansi@6.0.1 1104 | wrap-ansi: 8.1.0 1105 | wrap-ansi-cjs: wrap-ansi@7.0.0 1106 | 1107 | '@jridgewell/gen-mapping@0.3.8': 1108 | dependencies: 1109 | '@jridgewell/set-array': 1.2.1 1110 | '@jridgewell/sourcemap-codec': 1.5.0 1111 | '@jridgewell/trace-mapping': 0.3.25 1112 | 1113 | '@jridgewell/resolve-uri@3.1.2': {} 1114 | 1115 | '@jridgewell/set-array@1.2.1': {} 1116 | 1117 | '@jridgewell/sourcemap-codec@1.5.0': {} 1118 | 1119 | '@jridgewell/trace-mapping@0.3.25': 1120 | dependencies: 1121 | '@jridgewell/resolve-uri': 3.1.2 1122 | '@jridgewell/sourcemap-codec': 1.5.0 1123 | 1124 | '@nodelib/fs.scandir@2.1.5': 1125 | dependencies: 1126 | '@nodelib/fs.stat': 2.0.5 1127 | run-parallel: 1.2.0 1128 | 1129 | '@nodelib/fs.stat@2.0.5': {} 1130 | 1131 | '@nodelib/fs.walk@1.2.8': 1132 | dependencies: 1133 | '@nodelib/fs.scandir': 2.1.5 1134 | fastq: 1.19.1 1135 | 1136 | '@pkgjs/parseargs@0.11.0': 1137 | optional: true 1138 | 1139 | '@types/prop-types@15.7.14': {} 1140 | 1141 | '@types/react-dom@18.3.6(@types/react@18.3.20)': 1142 | dependencies: 1143 | '@types/react': 18.3.20 1144 | 1145 | '@types/react@18.3.20': 1146 | dependencies: 1147 | '@types/prop-types': 15.7.14 1148 | csstype: 3.1.3 1149 | 1150 | '@vitejs/plugin-react@2.2.0(vite@3.2.11)': 1151 | dependencies: 1152 | '@babel/core': 7.26.10 1153 | '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) 1154 | '@babel/plugin-transform-react-jsx-development': 7.25.9(@babel/core@7.26.10) 1155 | '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10) 1156 | '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10) 1157 | magic-string: 0.26.7 1158 | react-refresh: 0.14.2 1159 | vite: 3.2.11 1160 | transitivePeerDependencies: 1161 | - supports-color 1162 | 1163 | ansi-regex@5.0.1: {} 1164 | 1165 | ansi-regex@6.1.0: {} 1166 | 1167 | ansi-styles@4.3.0: 1168 | dependencies: 1169 | color-convert: 2.0.1 1170 | 1171 | ansi-styles@6.2.1: {} 1172 | 1173 | any-promise@1.3.0: {} 1174 | 1175 | anymatch@3.1.3: 1176 | dependencies: 1177 | normalize-path: 3.0.0 1178 | picomatch: 2.3.1 1179 | 1180 | arg@5.0.2: {} 1181 | 1182 | autoprefixer@10.4.21(postcss@8.5.3): 1183 | dependencies: 1184 | browserslist: 4.24.4 1185 | caniuse-lite: 1.0.30001712 1186 | fraction.js: 4.3.7 1187 | normalize-range: 0.1.2 1188 | picocolors: 1.1.1 1189 | postcss: 8.5.3 1190 | postcss-value-parser: 4.2.0 1191 | 1192 | balanced-match@1.0.2: {} 1193 | 1194 | binary-extensions@2.3.0: {} 1195 | 1196 | brace-expansion@2.0.1: 1197 | dependencies: 1198 | balanced-match: 1.0.2 1199 | 1200 | braces@3.0.3: 1201 | dependencies: 1202 | fill-range: 7.1.1 1203 | 1204 | browserslist@4.24.4: 1205 | dependencies: 1206 | caniuse-lite: 1.0.30001712 1207 | electron-to-chromium: 1.5.132 1208 | node-releases: 2.0.19 1209 | update-browserslist-db: 1.1.3(browserslist@4.24.4) 1210 | 1211 | camelcase-css@2.0.1: {} 1212 | 1213 | caniuse-lite@1.0.30001712: {} 1214 | 1215 | chokidar@3.6.0: 1216 | dependencies: 1217 | anymatch: 3.1.3 1218 | braces: 3.0.3 1219 | glob-parent: 5.1.2 1220 | is-binary-path: 2.1.0 1221 | is-glob: 4.0.3 1222 | normalize-path: 3.0.0 1223 | readdirp: 3.6.0 1224 | optionalDependencies: 1225 | fsevents: 2.3.3 1226 | 1227 | color-convert@2.0.1: 1228 | dependencies: 1229 | color-name: 1.1.4 1230 | 1231 | color-name@1.1.4: {} 1232 | 1233 | commander@4.1.1: {} 1234 | 1235 | convert-source-map@2.0.0: {} 1236 | 1237 | cross-spawn@7.0.6: 1238 | dependencies: 1239 | path-key: 3.1.1 1240 | shebang-command: 2.0.0 1241 | which: 2.0.2 1242 | 1243 | cssesc@3.0.0: {} 1244 | 1245 | csstype@3.1.3: {} 1246 | 1247 | debug@4.4.0: 1248 | dependencies: 1249 | ms: 2.1.3 1250 | 1251 | didyoumean@1.2.2: {} 1252 | 1253 | dlv@1.1.3: {} 1254 | 1255 | eastasianwidth@0.2.0: {} 1256 | 1257 | electron-to-chromium@1.5.132: {} 1258 | 1259 | emoji-regex@8.0.0: {} 1260 | 1261 | emoji-regex@9.2.2: {} 1262 | 1263 | esbuild-android-64@0.15.18: 1264 | optional: true 1265 | 1266 | esbuild-android-arm64@0.15.18: 1267 | optional: true 1268 | 1269 | esbuild-darwin-64@0.15.18: 1270 | optional: true 1271 | 1272 | esbuild-darwin-arm64@0.15.18: 1273 | optional: true 1274 | 1275 | esbuild-freebsd-64@0.15.18: 1276 | optional: true 1277 | 1278 | esbuild-freebsd-arm64@0.15.18: 1279 | optional: true 1280 | 1281 | esbuild-linux-32@0.15.18: 1282 | optional: true 1283 | 1284 | esbuild-linux-64@0.15.18: 1285 | optional: true 1286 | 1287 | esbuild-linux-arm64@0.15.18: 1288 | optional: true 1289 | 1290 | esbuild-linux-arm@0.15.18: 1291 | optional: true 1292 | 1293 | esbuild-linux-mips64le@0.15.18: 1294 | optional: true 1295 | 1296 | esbuild-linux-ppc64le@0.15.18: 1297 | optional: true 1298 | 1299 | esbuild-linux-riscv64@0.15.18: 1300 | optional: true 1301 | 1302 | esbuild-linux-s390x@0.15.18: 1303 | optional: true 1304 | 1305 | esbuild-netbsd-64@0.15.18: 1306 | optional: true 1307 | 1308 | esbuild-openbsd-64@0.15.18: 1309 | optional: true 1310 | 1311 | esbuild-sunos-64@0.15.18: 1312 | optional: true 1313 | 1314 | esbuild-windows-32@0.15.18: 1315 | optional: true 1316 | 1317 | esbuild-windows-64@0.15.18: 1318 | optional: true 1319 | 1320 | esbuild-windows-arm64@0.15.18: 1321 | optional: true 1322 | 1323 | esbuild@0.15.18: 1324 | optionalDependencies: 1325 | '@esbuild/android-arm': 0.15.18 1326 | '@esbuild/linux-loong64': 0.15.18 1327 | esbuild-android-64: 0.15.18 1328 | esbuild-android-arm64: 0.15.18 1329 | esbuild-darwin-64: 0.15.18 1330 | esbuild-darwin-arm64: 0.15.18 1331 | esbuild-freebsd-64: 0.15.18 1332 | esbuild-freebsd-arm64: 0.15.18 1333 | esbuild-linux-32: 0.15.18 1334 | esbuild-linux-64: 0.15.18 1335 | esbuild-linux-arm: 0.15.18 1336 | esbuild-linux-arm64: 0.15.18 1337 | esbuild-linux-mips64le: 0.15.18 1338 | esbuild-linux-ppc64le: 0.15.18 1339 | esbuild-linux-riscv64: 0.15.18 1340 | esbuild-linux-s390x: 0.15.18 1341 | esbuild-netbsd-64: 0.15.18 1342 | esbuild-openbsd-64: 0.15.18 1343 | esbuild-sunos-64: 0.15.18 1344 | esbuild-windows-32: 0.15.18 1345 | esbuild-windows-64: 0.15.18 1346 | esbuild-windows-arm64: 0.15.18 1347 | 1348 | escalade@3.2.0: {} 1349 | 1350 | fast-glob@3.3.3: 1351 | dependencies: 1352 | '@nodelib/fs.stat': 2.0.5 1353 | '@nodelib/fs.walk': 1.2.8 1354 | glob-parent: 5.1.2 1355 | merge2: 1.4.1 1356 | micromatch: 4.0.8 1357 | 1358 | fastq@1.19.1: 1359 | dependencies: 1360 | reusify: 1.1.0 1361 | 1362 | fill-range@7.1.1: 1363 | dependencies: 1364 | to-regex-range: 5.0.1 1365 | 1366 | foreground-child@3.3.1: 1367 | dependencies: 1368 | cross-spawn: 7.0.6 1369 | signal-exit: 4.1.0 1370 | 1371 | fraction.js@4.3.7: {} 1372 | 1373 | fsevents@2.3.3: 1374 | optional: true 1375 | 1376 | function-bind@1.1.2: {} 1377 | 1378 | gensync@1.0.0-beta.2: {} 1379 | 1380 | glob-parent@5.1.2: 1381 | dependencies: 1382 | is-glob: 4.0.3 1383 | 1384 | glob-parent@6.0.2: 1385 | dependencies: 1386 | is-glob: 4.0.3 1387 | 1388 | glob@10.4.5: 1389 | dependencies: 1390 | foreground-child: 3.3.1 1391 | jackspeak: 3.4.3 1392 | minimatch: 9.0.5 1393 | minipass: 7.1.2 1394 | package-json-from-dist: 1.0.1 1395 | path-scurry: 1.11.1 1396 | 1397 | globals@11.12.0: {} 1398 | 1399 | hasown@2.0.2: 1400 | dependencies: 1401 | function-bind: 1.1.2 1402 | 1403 | is-binary-path@2.1.0: 1404 | dependencies: 1405 | binary-extensions: 2.3.0 1406 | 1407 | is-core-module@2.16.1: 1408 | dependencies: 1409 | hasown: 2.0.2 1410 | 1411 | is-extglob@2.1.1: {} 1412 | 1413 | is-fullwidth-code-point@3.0.0: {} 1414 | 1415 | is-glob@4.0.3: 1416 | dependencies: 1417 | is-extglob: 2.1.1 1418 | 1419 | is-number@7.0.0: {} 1420 | 1421 | isexe@2.0.0: {} 1422 | 1423 | jackspeak@3.4.3: 1424 | dependencies: 1425 | '@isaacs/cliui': 8.0.2 1426 | optionalDependencies: 1427 | '@pkgjs/parseargs': 0.11.0 1428 | 1429 | jiti@1.21.7: {} 1430 | 1431 | js-tokens@4.0.0: {} 1432 | 1433 | jsesc@3.1.0: {} 1434 | 1435 | json5@2.2.3: {} 1436 | 1437 | lilconfig@3.1.3: {} 1438 | 1439 | lines-and-columns@1.2.4: {} 1440 | 1441 | loose-envify@1.4.0: 1442 | dependencies: 1443 | js-tokens: 4.0.0 1444 | 1445 | lru-cache@10.4.3: {} 1446 | 1447 | lru-cache@5.1.1: 1448 | dependencies: 1449 | yallist: 3.1.1 1450 | 1451 | magic-string@0.26.7: 1452 | dependencies: 1453 | sourcemap-codec: 1.4.8 1454 | 1455 | merge2@1.4.1: {} 1456 | 1457 | micromatch@4.0.8: 1458 | dependencies: 1459 | braces: 3.0.3 1460 | picomatch: 2.3.1 1461 | 1462 | minimatch@9.0.5: 1463 | dependencies: 1464 | brace-expansion: 2.0.1 1465 | 1466 | minipass@7.1.2: {} 1467 | 1468 | ms@2.1.3: {} 1469 | 1470 | mz@2.7.0: 1471 | dependencies: 1472 | any-promise: 1.3.0 1473 | object-assign: 4.1.1 1474 | thenify-all: 1.6.0 1475 | 1476 | nanoid@3.3.11: {} 1477 | 1478 | node-releases@2.0.19: {} 1479 | 1480 | normalize-path@3.0.0: {} 1481 | 1482 | normalize-range@0.1.2: {} 1483 | 1484 | object-assign@4.1.1: {} 1485 | 1486 | object-hash@3.0.0: {} 1487 | 1488 | package-json-from-dist@1.0.1: {} 1489 | 1490 | path-key@3.1.1: {} 1491 | 1492 | path-parse@1.0.7: {} 1493 | 1494 | path-scurry@1.11.1: 1495 | dependencies: 1496 | lru-cache: 10.4.3 1497 | minipass: 7.1.2 1498 | 1499 | picocolors@1.1.1: {} 1500 | 1501 | picomatch@2.3.1: {} 1502 | 1503 | pify@2.3.0: {} 1504 | 1505 | pirates@4.0.7: {} 1506 | 1507 | postcss-import@15.1.0(postcss@8.5.3): 1508 | dependencies: 1509 | postcss: 8.5.3 1510 | postcss-value-parser: 4.2.0 1511 | read-cache: 1.0.0 1512 | resolve: 1.22.10 1513 | 1514 | postcss-js@4.0.1(postcss@8.5.3): 1515 | dependencies: 1516 | camelcase-css: 2.0.1 1517 | postcss: 8.5.3 1518 | 1519 | postcss-load-config@4.0.2(postcss@8.5.3): 1520 | dependencies: 1521 | lilconfig: 3.1.3 1522 | yaml: 2.7.1 1523 | optionalDependencies: 1524 | postcss: 8.5.3 1525 | 1526 | postcss-nested@6.2.0(postcss@8.5.3): 1527 | dependencies: 1528 | postcss: 8.5.3 1529 | postcss-selector-parser: 6.1.2 1530 | 1531 | postcss-selector-parser@6.1.2: 1532 | dependencies: 1533 | cssesc: 3.0.0 1534 | util-deprecate: 1.0.2 1535 | 1536 | postcss-value-parser@4.2.0: {} 1537 | 1538 | postcss@8.5.3: 1539 | dependencies: 1540 | nanoid: 3.3.11 1541 | picocolors: 1.1.1 1542 | source-map-js: 1.2.1 1543 | 1544 | queue-microtask@1.2.3: {} 1545 | 1546 | react-dom@18.3.1(react@18.3.1): 1547 | dependencies: 1548 | loose-envify: 1.4.0 1549 | react: 18.3.1 1550 | scheduler: 0.23.2 1551 | 1552 | react-refresh@0.14.2: {} 1553 | 1554 | react@18.3.1: 1555 | dependencies: 1556 | loose-envify: 1.4.0 1557 | 1558 | read-cache@1.0.0: 1559 | dependencies: 1560 | pify: 2.3.0 1561 | 1562 | readdirp@3.6.0: 1563 | dependencies: 1564 | picomatch: 2.3.1 1565 | 1566 | resolve@1.22.10: 1567 | dependencies: 1568 | is-core-module: 2.16.1 1569 | path-parse: 1.0.7 1570 | supports-preserve-symlinks-flag: 1.0.0 1571 | 1572 | reusify@1.1.0: {} 1573 | 1574 | rollup@2.79.2: 1575 | optionalDependencies: 1576 | fsevents: 2.3.3 1577 | 1578 | run-parallel@1.2.0: 1579 | dependencies: 1580 | queue-microtask: 1.2.3 1581 | 1582 | scheduler@0.23.2: 1583 | dependencies: 1584 | loose-envify: 1.4.0 1585 | 1586 | semver@6.3.1: {} 1587 | 1588 | shebang-command@2.0.0: 1589 | dependencies: 1590 | shebang-regex: 3.0.0 1591 | 1592 | shebang-regex@3.0.0: {} 1593 | 1594 | signal-exit@4.1.0: {} 1595 | 1596 | source-map-js@1.2.1: {} 1597 | 1598 | sourcemap-codec@1.4.8: {} 1599 | 1600 | string-width@4.2.3: 1601 | dependencies: 1602 | emoji-regex: 8.0.0 1603 | is-fullwidth-code-point: 3.0.0 1604 | strip-ansi: 6.0.1 1605 | 1606 | string-width@5.1.2: 1607 | dependencies: 1608 | eastasianwidth: 0.2.0 1609 | emoji-regex: 9.2.2 1610 | strip-ansi: 7.1.0 1611 | 1612 | strip-ansi@6.0.1: 1613 | dependencies: 1614 | ansi-regex: 5.0.1 1615 | 1616 | strip-ansi@7.1.0: 1617 | dependencies: 1618 | ansi-regex: 6.1.0 1619 | 1620 | sucrase@3.35.0: 1621 | dependencies: 1622 | '@jridgewell/gen-mapping': 0.3.8 1623 | commander: 4.1.1 1624 | glob: 10.4.5 1625 | lines-and-columns: 1.2.4 1626 | mz: 2.7.0 1627 | pirates: 4.0.7 1628 | ts-interface-checker: 0.1.13 1629 | 1630 | supports-preserve-symlinks-flag@1.0.0: {} 1631 | 1632 | tailwindcss@3.4.17: 1633 | dependencies: 1634 | '@alloc/quick-lru': 5.2.0 1635 | arg: 5.0.2 1636 | chokidar: 3.6.0 1637 | didyoumean: 1.2.2 1638 | dlv: 1.1.3 1639 | fast-glob: 3.3.3 1640 | glob-parent: 6.0.2 1641 | is-glob: 4.0.3 1642 | jiti: 1.21.7 1643 | lilconfig: 3.1.3 1644 | micromatch: 4.0.8 1645 | normalize-path: 3.0.0 1646 | object-hash: 3.0.0 1647 | picocolors: 1.1.1 1648 | postcss: 8.5.3 1649 | postcss-import: 15.1.0(postcss@8.5.3) 1650 | postcss-js: 4.0.1(postcss@8.5.3) 1651 | postcss-load-config: 4.0.2(postcss@8.5.3) 1652 | postcss-nested: 6.2.0(postcss@8.5.3) 1653 | postcss-selector-parser: 6.1.2 1654 | resolve: 1.22.10 1655 | sucrase: 3.35.0 1656 | transitivePeerDependencies: 1657 | - ts-node 1658 | 1659 | thenify-all@1.6.0: 1660 | dependencies: 1661 | thenify: 3.3.1 1662 | 1663 | thenify@3.3.1: 1664 | dependencies: 1665 | any-promise: 1.3.0 1666 | 1667 | to-regex-range@5.0.1: 1668 | dependencies: 1669 | is-number: 7.0.0 1670 | 1671 | ts-interface-checker@0.1.13: {} 1672 | 1673 | tslib@2.8.1: {} 1674 | 1675 | typescript@4.9.5: {} 1676 | 1677 | update-browserslist-db@1.1.3(browserslist@4.24.4): 1678 | dependencies: 1679 | browserslist: 4.24.4 1680 | escalade: 3.2.0 1681 | picocolors: 1.1.1 1682 | 1683 | util-deprecate@1.0.2: {} 1684 | 1685 | vite@3.2.11: 1686 | dependencies: 1687 | esbuild: 0.15.18 1688 | postcss: 8.5.3 1689 | resolve: 1.22.10 1690 | rollup: 2.79.2 1691 | optionalDependencies: 1692 | fsevents: 2.3.3 1693 | 1694 | which@2.0.2: 1695 | dependencies: 1696 | isexe: 2.0.0 1697 | 1698 | wrap-ansi@7.0.0: 1699 | dependencies: 1700 | ansi-styles: 4.3.0 1701 | string-width: 4.2.3 1702 | strip-ansi: 6.0.1 1703 | 1704 | wrap-ansi@8.1.0: 1705 | dependencies: 1706 | ansi-styles: 6.2.1 1707 | string-width: 5.1.2 1708 | strip-ansi: 7.1.0 1709 | 1710 | yallist@3.1.1: {} 1711 | 1712 | yaml@2.7.1: {} 1713 | -------------------------------------------------------------------------------- /frontend/postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/App.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | // ClipboardHistory.tsx 2 | import { useEffect, useState, memo } from 'react'; 3 | import { GetHistory, UpdateHistory } from '../wailsjs/go/main/App'; 4 | import { DndContext, closestCenter, useSensor, useSensors, PointerSensor } from '@dnd-kit/core'; 5 | import { 6 | arrayMove, 7 | SortableContext, 8 | useSortable, 9 | verticalListSortingStrategy 10 | } from '@dnd-kit/sortable'; 11 | import { CSS } from '@dnd-kit/utilities'; 12 | 13 | // Pre-rendered static SVG components with memoization 14 | const ScrollBackground = memo(() => ( 15 |
16 | {/* Simple texture pattern instead of complex SVG filter */} 17 |
23 |
24 |
25 | )); 26 | 27 | const InkwellIcon = memo(() => ( 28 | 29 | 33 | 34 | 35 | 39 | 40 | )); 41 | 42 | const QuillIcon = memo(() => ( 43 | 44 | 48 | 49 | 50 | 51 | )); 52 | 53 | const DeleteIcon = memo(() => ( 54 | 55 | 56 | 57 | )); 58 | 59 | // Memoized sortable item component 60 | const SortableItem = memo(({ id, onDelete }: { id: string, onDelete: (id: string) => void }) => { 61 | const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id }); 62 | const style = { 63 | transform: CSS.Transform.toString(transform), 64 | transition, 65 | }; 66 | 67 | const handleDelete = (e: React.MouseEvent) => { 68 | e.stopPropagation(); 69 | onDelete(id); 70 | }; 71 | 72 | return ( 73 |
80 |
81 |
82 | 83 |
84 | {id} 85 |
86 |
87 | 94 |
95 | {/* Simplified decorative elements */} 96 |
97 |
98 | ); 99 | }); 100 | 101 | // Main component with performance optimizations 102 | export default function ClipboardHistory() { 103 | const [items, setItems] = useState([]); 104 | const [isRefreshing, setIsRefreshing] = useState(false); 105 | const [isClearing, setIsClearing] = useState(false); 106 | const [confirmClear, setConfirmClear] = useState(false); 107 | 108 | const sensors = useSensors(useSensor(PointerSensor, { 109 | activationConstraint: { 110 | distance: 5, // Small distance threshold to avoid accidental drags 111 | }, 112 | })); 113 | 114 | const fetchHistory = async () => { 115 | if (isRefreshing) return; // Prevent multiple simultaneous requests 116 | 117 | setIsRefreshing(true); 118 | try { 119 | const history = await GetHistory(); 120 | setItems(history); 121 | } catch (error) { 122 | console.error("Failed to fetch history:", error); 123 | } finally { 124 | // Use requestAnimationFrame for smoother UI updates 125 | requestAnimationFrame(() => { 126 | setTimeout(() => setIsRefreshing(false), 300); 127 | }); 128 | } 129 | }; 130 | 131 | useEffect(() => { 132 | fetchHistory(); 133 | }, []); 134 | 135 | const handleDragEnd = async (event: any) => { 136 | const { active, over } = event; 137 | if (!active || !over || active.id === over.id) return; 138 | 139 | const oldIndex = items.indexOf(active.id); 140 | const newIndex = items.indexOf(over.id); 141 | 142 | if (oldIndex !== -1 && newIndex !== -1) { 143 | const newItems = arrayMove(items, oldIndex, newIndex); 144 | setItems(newItems); 145 | 146 | // Optimistic UI update, then sync with backend 147 | try { 148 | await UpdateHistory(newItems); 149 | } catch (error) { 150 | console.error("Failed to update history:", error); 151 | // Could revert items here on error 152 | } 153 | } 154 | }; 155 | 156 | const handleDeleteItem = async (id: string) => { 157 | const newItems = items.filter(item => item !== id); 158 | setItems(newItems); 159 | 160 | try { 161 | await UpdateHistory(newItems); 162 | } catch (error) { 163 | console.error("Failed to delete item:", error); 164 | // Rollback on error 165 | await fetchHistory(); 166 | } 167 | }; 168 | 169 | const handleClearAll = async () => { 170 | if (!confirmClear) { 171 | setConfirmClear(true); 172 | setTimeout(() => setConfirmClear(false), 3000); // Reset after 3 seconds 173 | return; 174 | } 175 | 176 | setIsClearing(true); 177 | try { 178 | await UpdateHistory([]); 179 | setItems([]); 180 | setConfirmClear(false); 181 | } catch (error) { 182 | console.error("Failed to clear all items:", error); 183 | await fetchHistory(); 184 | } finally { 185 | setIsClearing(false); 186 | } 187 | }; 188 | 189 | return ( 190 |
191 | 192 | 193 |
194 |
195 |

196 | ClipCapsule 197 |

198 |
199 | 216 | 217 | 228 |
229 |
230 | 231 |
232 |
233 | 234 |

Clipboard History

235 |
236 |

237 | Use CTRL+SHIFT+[1-9] to select an item 238 |

239 |
240 | 241 |
242 | 247 | 248 | {items.length > 0 ? ( 249 |
250 | {items.map((text) => ( 251 | 256 | ))} 257 |
258 | ) : ( 259 |
260 | {isRefreshing ? "Loading..." : "No clipboard history found. Copy something to see it here."} 261 |
262 | )} 263 |
264 |
265 |
266 | 267 |
268 |

ClipCapsule · A Vintage Clipboard Manager

269 |
270 |
271 |
272 | ); 273 | } -------------------------------------------------------------------------------- /frontend/src/assets/logo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Victor-Evogor/clipcapsule/5370e2b20f46ce75f7f3a6254fc5c570fc7ffeed/frontend/src/assets/logo-2.png -------------------------------------------------------------------------------- /frontend/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Victor-Evogor/clipcapsule/5370e2b20f46ce75f7f3a6254fc5c570fc7ffeed/frontend/src/assets/logo.png -------------------------------------------------------------------------------- /frontend/src/assets/wails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Victor-Evogor/clipcapsule/5370e2b20f46ce75f7f3a6254fc5c570fc7ffeed/frontend/src/assets/wails.png -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /frontend/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /frontend/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/tailwind.config.cjs: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/**/*.{js,jsx,ts,tsx}", 5 | ], 6 | theme: { 7 | extend: {}, 8 | }, 9 | plugins: [], 10 | } 11 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /frontend/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /frontend/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()] 7 | }) 8 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module clipcapsule 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.8 6 | 7 | require ( 8 | github.com/MarinX/keylogger v0.0.0-20240620105846-48ca9d01f566 9 | github.com/mattn/go-sqlite3 v1.14.27 10 | github.com/wailsapp/wails/v2 v2.10.1 11 | golang.design/x/clipboard v0.7.0 12 | ) 13 | 14 | require ( 15 | github.com/bep/debounce v1.2.1 // indirect 16 | github.com/go-ole/go-ole v1.3.0 // indirect 17 | github.com/godbus/dbus/v5 v5.1.0 // indirect 18 | github.com/google/uuid v1.6.0 // indirect 19 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect 20 | github.com/labstack/echo/v4 v4.13.3 // indirect 21 | github.com/labstack/gommon v0.4.2 // indirect 22 | github.com/leaanthony/go-ansi-parser v1.6.1 // indirect 23 | github.com/leaanthony/gosod v1.0.4 // indirect 24 | github.com/leaanthony/slicer v1.6.0 // indirect 25 | github.com/leaanthony/u v1.1.1 // indirect 26 | github.com/mattn/go-colorable v0.1.13 // indirect 27 | github.com/mattn/go-isatty v0.0.20 // indirect 28 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect 29 | github.com/pkg/errors v0.9.1 // indirect 30 | github.com/rivo/uniseg v0.4.7 // indirect 31 | github.com/samber/lo v1.49.1 // indirect 32 | github.com/tkrajina/go-reflector v0.5.8 // indirect 33 | github.com/valyala/bytebufferpool v1.0.0 // indirect 34 | github.com/valyala/fasttemplate v1.2.2 // indirect 35 | github.com/wailsapp/go-webview2 v1.0.19 // indirect 36 | github.com/wailsapp/mimetype v1.4.1 // indirect 37 | golang.org/x/crypto v0.33.0 // indirect 38 | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect 39 | golang.org/x/image v0.12.0 // indirect 40 | golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c // indirect 41 | golang.org/x/net v0.35.0 // indirect 42 | golang.org/x/sys v0.32.0 // indirect 43 | golang.org/x/text v0.22.0 // indirect 44 | ) 45 | 46 | // replace github.com/wailsapp/wails/v2 v2.10.1 => /home/victor/go/pkg/mod 47 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= 2 | github.com/MarinX/keylogger v0.0.0-20240620105846-48ca9d01f566 h1:3uD1lmRbdt8Ho73IcAUTxRQtksuupGMigYG0x+yOi+o= 3 | github.com/MarinX/keylogger v0.0.0-20240620105846-48ca9d01f566/go.mod h1:aKzZ7D15UvH5LboXkeLmcNi+s/f805vUfB+BfW1fqd4= 4 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= 5 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= 9 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 10 | github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= 11 | github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 12 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 13 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 14 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= 15 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= 16 | github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY= 17 | github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g= 18 | github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= 19 | github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= 20 | github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= 21 | github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= 22 | github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A= 23 | github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU= 24 | github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI= 25 | github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw= 26 | github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js= 27 | github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8= 28 | github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M= 29 | github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI= 30 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 31 | github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= 32 | github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= 33 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 34 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 35 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 36 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 37 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 38 | github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU= 39 | github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= 40 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= 41 | github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= 42 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 43 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 44 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 45 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 46 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 47 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 48 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 49 | github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= 50 | github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= 51 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 52 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 53 | github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ= 54 | github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= 55 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 56 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 57 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= 58 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 59 | github.com/wailsapp/go-webview2 v1.0.19 h1:7U3QcDj1PrBPaxJNCui2k1SkWml+Q5kvFUFyTImA6NU= 60 | github.com/wailsapp/go-webview2 v1.0.19/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc= 61 | github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= 62 | github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= 63 | github.com/wailsapp/wails/v2 v2.10.1 h1:QWHvWMXII2nI/nXz77gpPG8P3ehl6zKe+u4su5BWIns= 64 | github.com/wailsapp/wails/v2 v2.10.1/go.mod h1:zrebnFV6MQf9kx8HI4iAv63vsR5v67oS7GTEZ7Pz1TY= 65 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 66 | golang.design/x/clipboard v0.7.0 h1:4Je8M/ys9AJumVnl8m+rZnIvstSnYj1fvzqYrU3TXvo= 67 | golang.design/x/clipboard v0.7.0/go.mod h1:PQIvqYO9GP29yINEfsEn5zSQKAz3UgXmZKzDA6dnq2E= 68 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 69 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 70 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 71 | golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= 72 | golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= 73 | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU= 74 | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= 75 | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= 76 | golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ= 77 | golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk= 78 | golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= 79 | golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c h1:Gk61ECugwEHL6IiyyNLXNzmu8XslmRP2dS0xjIYhbb4= 80 | golang.org/x/mobile v0.0.0-20230301163155-e0f57694e12c/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= 81 | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= 82 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 83 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 84 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 85 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 86 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 87 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 88 | golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 89 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 90 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 91 | golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= 92 | golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= 93 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 94 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 95 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 96 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 97 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 98 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 99 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 100 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 101 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 102 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 103 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 104 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 105 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 106 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 107 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 108 | golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 109 | golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 110 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 111 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 112 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 113 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 114 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 115 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 116 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 117 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 118 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 119 | golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= 120 | golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= 121 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 122 | golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 123 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 124 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 125 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 126 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 127 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 128 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 129 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "clipcapsule/utils" 5 | "embed" 6 | 7 | "github.com/wailsapp/wails/v2" 8 | "github.com/wailsapp/wails/v2/pkg/options" 9 | "github.com/wailsapp/wails/v2/pkg/options/linux" 10 | ) 11 | 12 | //go:embed all:frontend/dist 13 | var assets embed.FS 14 | 15 | //go:embed favicon.ico 16 | var logo_embed embed.FS 17 | 18 | func main() { 19 | // Create an instance of the app structure 20 | app := NewApp() 21 | 22 | go utils.MonitorKeyboardGlobal() 23 | 24 | logo, logo_err := logo_embed.ReadFile("favicon.ico") 25 | if logo_err != nil { 26 | panic(logo_err) 27 | } 28 | 29 | // Create application with options 30 | err := wails.Run(&options.App{ 31 | Title: "clipcapsule", 32 | Width: 1024, 33 | Height: 768, 34 | Assets: assets, 35 | BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1}, 36 | OnStartup: app.startup, 37 | Bind: []interface{}{ 38 | app, 39 | }, 40 | Linux: &linux.Options{ 41 | Icon: logo, 42 | ProgramName: "clipcapsule", 43 | }, 44 | }) 45 | 46 | if err != nil { 47 | println("Error:", err.Error()) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /scripts/build-macos-arm.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -e "Start running the script..." 4 | cd ../ 5 | 6 | echo -e "Start building the app for macos platform..." 7 | wails build --clean --platform darwin/arm64 8 | 9 | echo -e "End running the script!" 10 | -------------------------------------------------------------------------------- /scripts/build-macos-intel.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -e "Start running the script..." 4 | cd ../ 5 | 6 | echo -e "Start building the app for macos platform..." 7 | wails build --clean --platform darwin 8 | 9 | echo -e "End running the script!" 10 | -------------------------------------------------------------------------------- /scripts/build-macos.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -e "Start running the script..." 4 | cd ../ 5 | 6 | echo -e "Start building the app for macos platform..." 7 | wails build --clean --platform darwin/universal 8 | 9 | echo -e "End running the script!" 10 | -------------------------------------------------------------------------------- /scripts/build-windows.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -e "Start running the script..." 4 | cd ../ 5 | 6 | echo -e "Start building the app for windows platform..." 7 | wails build --clean --platform windows/amd64 8 | 9 | echo -e "End running the script!" 10 | -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -e "Start running the script..." 4 | cd ../ 5 | 6 | echo -e "Start building the app..." 7 | wails build --clean 8 | 9 | echo -e "End running the script!" 10 | -------------------------------------------------------------------------------- /scripts/install-wails-cli.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo -e "Start running the script..." 4 | cd ../ 5 | 6 | echo -e "Current Go version: \c" 7 | go version 8 | 9 | echo -e "Install the Wails command line tool..." 10 | go install github.com/wailsapp/wails/v2/cmd/wails@latest 11 | 12 | echo -e "Successful installation!" 13 | 14 | echo -e "End running the script!" 15 | -------------------------------------------------------------------------------- /utils/db.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | 7 | _ "github.com/mattn/go-sqlite3" 8 | ) 9 | 10 | var dbURL = "db/cliphistory.db" 11 | 12 | type ClipboardItem struct { 13 | ID int 14 | Content string 15 | Position int 16 | } 17 | 18 | type Db struct { 19 | conn *sql.DB 20 | } 21 | 22 | // New initializes the database connection and creates the table if it doesn't exist 23 | func (d *Db) New() error { 24 | db, err := sql.Open("sqlite3", dbURL) 25 | if err != nil { 26 | return fmt.Errorf("failed to open database: %w", err) 27 | } 28 | d.conn = db 29 | 30 | return d.createTable() 31 | } 32 | 33 | // createTable ensures the clipboard_items table exists 34 | func (d *Db) createTable() error { 35 | query := ` 36 | CREATE TABLE IF NOT EXISTS clipboard_items ( 37 | id INTEGER PRIMARY KEY AUTOINCREMENT, 38 | content TEXT NOT NULL, 39 | position INTEGER NOT NULL 40 | ); 41 | ` 42 | _, err := d.conn.Exec(query) 43 | return err 44 | } 45 | 46 | func CopyFirstDbEntryToClipboard(d *Db) { 47 | 48 | } 49 | 50 | // UpdateAllItems replaces all clipboard items with the provided ordered texts 51 | func (d *Db) UpdateAllItems(texts []string) []ClipboardItem { 52 | tx, err := d.conn.Begin() 53 | if err != nil { 54 | panic(fmt.Sprint("failed to begin transaction: %w", err)) 55 | } 56 | 57 | // Clear existing records 58 | if _, err := tx.Exec(`DELETE FROM clipboard_items`); err != nil { 59 | tx.Rollback() 60 | panic(fmt.Sprint("failed to clear clipboard_items: %w", err)) 61 | } 62 | 63 | // Insert all new items in order 64 | stmt, err := tx.Prepare(`INSERT INTO clipboard_items (content, position) VALUES (?, ?)`) 65 | if err != nil { 66 | tx.Rollback() 67 | panic(fmt.Sprint("failed to prepare insert: %w", err)) 68 | } 69 | defer stmt.Close() 70 | 71 | for i, text := range texts { 72 | if _, err := stmt.Exec(text, i); err != nil { 73 | tx.Rollback() 74 | panic(fmt.Sprint("failed to insert item %d: %w", i, err)) 75 | } 76 | } 77 | 78 | if tx.Commit() != nil { 79 | panic("Failed to commit transaction") 80 | } 81 | 82 | items, err := d.FetchAllItems() 83 | if err != nil { 84 | panic(err) 85 | } 86 | 87 | return items 88 | } 89 | 90 | // Optional: FetchAllItems returns all clipboard items in order 91 | func (d *Db) FetchAllItems() ([]ClipboardItem, error) { 92 | rows, err := d.conn.Query(`SELECT id, content, position FROM clipboard_items ORDER BY position ASC`) 93 | if err != nil { 94 | return nil, err 95 | } 96 | defer rows.Close() 97 | 98 | var items []ClipboardItem 99 | for rows.Next() { 100 | var item ClipboardItem 101 | if err := rows.Scan(&item.ID, &item.Content, &item.Position); err != nil { 102 | return nil, err 103 | } 104 | items = append(items, item) 105 | } 106 | 107 | return items, nil 108 | } 109 | 110 | // GetItemByPosition returns a clipboard item based on its position 111 | func (d *Db) GetItemByPosition(position int) (ClipboardItem, error) { 112 | var item ClipboardItem 113 | query := `SELECT id, content, position FROM clipboard_items WHERE position = ? LIMIT 1` 114 | 115 | row := d.conn.QueryRow(query, position) 116 | err := row.Scan(&item.ID, &item.Content, &item.Position) 117 | if err != nil { 118 | if err == sql.ErrNoRows { 119 | return item, fmt.Errorf("no item found at position %d", position) 120 | } 121 | return item, fmt.Errorf("failed to get item by position: %w", err) 122 | } 123 | 124 | return item, nil 125 | } 126 | -------------------------------------------------------------------------------- /utils/monitorClipboard.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "strconv" 7 | 8 | "github.com/MarinX/keylogger" 9 | "golang.design/x/clipboard" 10 | ) 11 | 12 | func MonitorKeyboardGlobal() { 13 | eventPath := keylogger.FindKeyboardDevice() 14 | if eventPath == "" { 15 | log.Fatal("No keyboard found") 16 | } 17 | 18 | keyLogger, err := keylogger.New(eventPath) 19 | if err != nil { 20 | log.Fatal("Failed to open keyboard:", err) 21 | } 22 | 23 | keysPressed := map[string]bool{} 24 | 25 | if clErr := clipboard.Init(); clErr != nil { 26 | log.Fatal(clErr) 27 | } 28 | 29 | db := Db{} 30 | if err := db.New(); err != nil { 31 | log.Fatal(err) 32 | } 33 | 34 | // Start the clipboard monitoring in a separate goroutine 35 | go MonitorClipboardChanges(&db) 36 | 37 | for event := range keyLogger.Read() { 38 | key := event.KeyString() 39 | 40 | if event.Type == keylogger.EvKey { 41 | if event.Value == 1 { 42 | keysPressed[key] = true 43 | } 44 | if event.Value == 0 { 45 | keysPressed[key] = false 46 | } 47 | 48 | isCtrl := keysPressed["L_CTRL"] || keysPressed["R_CTRL"] 49 | isShift := keysPressed["L_SHIFT"] || keysPressed["R_SHIFT"] 50 | 51 | // Handle Ctrl + Shift + [1-9] 52 | if isCtrl && isShift { 53 | for i := 1; i <= 9; i++ { 54 | keyStr := strconv.Itoa(i) 55 | if keysPressed[keyStr] { 56 | items, err := db.FetchAllItems() 57 | if err != nil { 58 | log.Println("Error fetching items:", err) 59 | continue 60 | } 61 | if i > len(items) { 62 | log.Printf("No item at position %d\n", i) 63 | continue 64 | } 65 | 66 | selected := items[i-1].Content 67 | newList := []string{selected} 68 | for _, item := range items { 69 | if item.Content != selected { 70 | newList = append(newList, item.Content) 71 | } 72 | } 73 | 74 | db.UpdateAllItems(newList) 75 | 76 | clipboard.Write(clipboard.FmtText, []byte(selected)) // set new #1 as clipboard 77 | } 78 | } 79 | } 80 | 81 | } 82 | } 83 | } 84 | 85 | // MonitorClipboardChanges watches for any changes to the clipboard content 86 | func MonitorClipboardChanges(db *Db) { 87 | // Create a channel to receive clipboard change notifications 88 | ch := clipboard.Watch(context.Background(), clipboard.FmtText) 89 | 90 | var lastContent string 91 | 92 | for data := range ch { 93 | clipboardText := string(data) 94 | 95 | // Skip if clipboard is empty or same as last content 96 | if clipboardText == "" || clipboardText == lastContent { 97 | continue 98 | } 99 | 100 | log.Printf("Clipboard changed, new content: %s", clipboardText[:min(20, len(clipboardText))]) 101 | lastContent = clipboardText 102 | 103 | // Update database 104 | items, err := db.FetchAllItems() 105 | if err != nil { 106 | log.Println("Error fetching items:", err) 107 | continue 108 | } 109 | 110 | // Check if content already at position 1 111 | if len(items) > 0 && items[0].Content == clipboardText { 112 | log.Println("Content already at top position, no update needed") 113 | continue 114 | } 115 | 116 | newList := []string{clipboardText} 117 | for _, item := range items { 118 | if item.Content != clipboardText { 119 | newList = append(newList, item.Content) 120 | } 121 | } 122 | 123 | db.UpdateAllItems(newList) 124 | } 125 | } 126 | 127 | // Helper function for string length limiting 128 | func min(a, b int) int { 129 | if a < b { 130 | return a 131 | } 132 | return b 133 | } 134 | -------------------------------------------------------------------------------- /wails.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "clipcapsule", 3 | "outputfilename": "clipcapsule", 4 | "frontend:install": "npm install", 5 | "frontend:build": "npm run build", 6 | "frontend:dev:watcher": "npm run dev", 7 | "frontend:dev:serverUrl": "auto", 8 | "author": { 9 | "name": "Victor Evogor", 10 | "email": "victorevogor0001@gmail.com" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /wails.toml: -------------------------------------------------------------------------------- 1 | [platform.windows] 2 | icon = "frontend/src/assets/logo-2.png" 3 | 4 | [platform.darwin] 5 | icon = "frontend/src/assets/logo-2.png" 6 | 7 | [platform.linux] 8 | icon = "frontend/src/assets/logo-2.png" 9 | --------------------------------------------------------------------------------