├── static ├── .nojekyll ├── CNAME └── img │ ├── logo.png │ └── favicon.ico ├── src ├── .gitignore ├── components │ ├── Description │ │ └── index.tsx │ ├── UiScreenshot │ │ ├── styles.module.css │ │ └── index.tsx │ ├── CodeExample │ │ ├── styles.module.css │ │ └── index.tsx │ ├── PropsTable │ │ └── index.tsx │ ├── PerTypeMembersTable │ │ └── index.tsx │ ├── OrderedMembersTable │ │ └── index.tsx │ └── types.ts ├── pages │ ├── index.tsx │ └── index.module.css └── css │ └── custom.css ├── component-generator ├── .gitignore ├── tsconfig.json ├── package.json └── src │ └── component-generator.ts ├── docs ├── information │ ├── _category_.json │ ├── versioning.md │ ├── terminology.md │ └── architecture.md ├── api-reference │ ├── _category_.json │ ├── entrypoint-types │ │ ├── _category_.json │ │ ├── view │ │ │ ├── _category_.json │ │ │ ├── form.mdx │ │ │ ├── grid.mdx │ │ │ ├── details.mdx │ │ │ └── list.mdx │ │ ├── command.mdx │ │ ├── entrypoint-generator.mdx │ │ └── inline-view.mdx │ ├── clipboard.mdx │ ├── navigation.mdx │ ├── icons-and-images.mdx │ ├── storage-and-cache.mdx │ ├── assets.mdx │ ├── environment.mdx │ ├── preferences.mdx │ ├── actions.mdx │ └── promise-helpers.mdx ├── bundled-plugins │ ├── _category_.json │ ├── calculator.md │ └── applications.md ├── plugin-development │ ├── _category_.json │ ├── file-structure.md │ ├── getting-started.md │ └── manifest.md ├── introduction.mdx ├── plugin-installation.md ├── feature-support.md ├── theming.md ├── troubleshooting.md ├── cli.md ├── application-config.md └── installation.md ├── babel.config.js ├── dummy └── dummy.md ├── tsconfig.json ├── sidebars.ts ├── .gitignore ├── README.md ├── package.json ├── darcula.theme.ts └── docusaurus.config.ts /static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | generated -------------------------------------------------------------------------------- /static/CNAME: -------------------------------------------------------------------------------- 1 | gauntlet.sh 2 | -------------------------------------------------------------------------------- /component-generator/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /docs/information/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": 3, 3 | "label": "Information" 4 | } -------------------------------------------------------------------------------- /static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0PandaDEV/website/main/static/img/logo.png -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0PandaDEV/website/main/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/api-reference/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": 12, 3 | "label": "API Reference" 4 | } 5 | -------------------------------------------------------------------------------- /docs/bundled-plugins/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": 10, 3 | "label": "Bundled Plugins" 4 | } 5 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": 1, 3 | "label": "Entrypoints" 4 | } -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/view/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": 1, 3 | "label": "View" 4 | } -------------------------------------------------------------------------------- /docs/plugin-development/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "position": 11, 3 | "label": "Plugin Development" 4 | } 5 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /dummy/dummy.md: -------------------------------------------------------------------------------- 1 | # This file exists to allow development of landing page without having to compile the Gauntlet itself 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /docs/bundled-plugins/calculator.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Calculator Plugin" 3 | sidebar_position: 2 4 | sidebar_label: "Calculator" 5 | draft: true 6 | --- 7 | 8 | :::warning 9 | 10 | Work In Progress 11 | 12 | ::: -------------------------------------------------------------------------------- /component-generator/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "ESNext", 5 | "baseUrl": ".", 6 | "esModuleInterop": true, 7 | "moduleResolution": "node", 8 | } 9 | } -------------------------------------------------------------------------------- /docs/bundled-plugins/applications.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Applications Plugin" 3 | sidebar_position: 1 4 | sidebar_label: "Applications" 5 | draft: true 6 | --- 7 | 8 | :::warning 9 | 10 | Work In Progress 11 | 12 | ::: -------------------------------------------------------------------------------- /sidebars.ts: -------------------------------------------------------------------------------- 1 | import type {SidebarsConfig} from '@docusaurus/plugin-content-docs'; 2 | 3 | const sidebars: SidebarsConfig = { 4 | docsSidebar: [{type: 'autogenerated', dirName: '.'}], 5 | }; 6 | 7 | export default sidebars; 8 | -------------------------------------------------------------------------------- /src/components/Description/index.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | 3 | interface Data { 4 | description: string 5 | } 6 | 7 | export default function Default({ data }: { data: Data }): ReactNode { 8 | return ( 9 |

10 | {data.description} 11 |

12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | /.idea 23 | 24 | /static/img/generated-screenshots 25 | -------------------------------------------------------------------------------- /component-generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gauntlet-docs-component-generator", 3 | "version": "0.0.0", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "run-generator": "tsx src/component-generator.ts" 8 | }, 9 | "dependencies": { 10 | "dedent": "^1.5.3", 11 | "toml": "^3.0.0" 12 | }, 13 | "devDependencies": { 14 | "tsx": "~4.19.2", 15 | "typescript": "~5.6.3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/UiScreenshot/styles.module.css: -------------------------------------------------------------------------------- 1 | .uiScreenshotContainer { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | width: 100%; 6 | padding: 50px 10px; 7 | 8 | border-radius: 6px; 9 | 10 | background: linear-gradient(to right, #eea849, #f46b45); 11 | } 12 | 13 | .uiScreenshot { 14 | border-radius: 10px; 15 | box-shadow: 0 22px 70px 4px rgba(0, 0, 0, 0.56); 16 | } 17 | -------------------------------------------------------------------------------- /src/components/UiScreenshot/index.tsx: -------------------------------------------------------------------------------- 1 | import useBaseUrl from "@docusaurus/useBaseUrl"; 2 | import React from "react"; 3 | import styles from './styles.module.css'; 4 | 5 | export default function Default({ imgPath }: { imgPath: string }): JSX.Element { 6 | return ( 7 |
8 | {"Gauntlet 9 |
10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /docs/api-reference/clipboard.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Clipboard" 3 | sidebar_position: 8 4 | sidebar_label: "Clipboard" 5 | --- 6 | 7 | import ClipboardCode from '@site/src/generated/code_example/ui_clipboard/clipboard'; 8 | 9 | ## Overview 10 | 11 | Clipboard API provides a way to read from, write to and clear OS clipboard 12 | 13 | ## Examples 14 | 15 | 16 | 17 | [//]: # (## API Reference) 18 | 19 | [//]: # (TODO per each method in Clipboard) 20 | -------------------------------------------------------------------------------- /docs/introduction.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Introduction" 3 | sidebar_position: 1 4 | sidebar_label: "Introduction" 5 | slug: "/" 6 | --- 7 | 8 | import UiScreenshot from '@site/src/components/UiScreenshot'; 9 | 10 | Gauntlet is an open source cross-platform plugin-first application launcher. 11 | In this documentation you'll find guides and examples that will help you with everything Gauntlet related, including installation, theming and plugin development 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/api-reference/navigation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Navigation" 3 | sidebar_position: 3 4 | sidebar_label: "Navigation" 5 | --- 6 | 7 | import NavigationCode from '@site/src/generated/code_example/ui_navigation/navigation'; 8 | 9 | ## Overview 10 | 11 | Views support simple stack-based navigation. 12 | Push new view onto stack by using `useNavigation` React Hook's `push` function, go back by using `pop` function or pressing Escape 13 | 14 | ## `useNavigation` 15 | 16 | ### Example 17 | 18 | 19 | 20 | [//]: # (### Api Reference) 21 | 22 | [//]: # (TODO type) 23 | -------------------------------------------------------------------------------- /src/components/CodeExample/styles.module.css: -------------------------------------------------------------------------------- 1 | .codeBlockOverlayContainer { 2 | position: relative; 3 | } 4 | 5 | .codeBlockOverlayGithubIcon { 6 | position: absolute; 7 | right: calc(var(--ifm-pre-padding) / 2); 8 | bottom: calc(var(--ifm-pre-padding) / 2); 9 | 10 | width: 2.125rem; 11 | height: 2.125rem; 12 | 13 | display: flex; 14 | align-items: center; 15 | justify-content: center; 16 | background: var(--prism-background-color); 17 | color: var(--prism-color); 18 | border: 1px solid var(--ifm-color-emphasis-300); 19 | border-radius: var(--ifm-global-radius); 20 | } 21 | -------------------------------------------------------------------------------- /docs/information/versioning.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Versioning" 3 | sidebar_position: 3 4 | sidebar_label: "Versioning" 5 | --- 6 | 7 | ## Application 8 | 9 | Application uses simple incremental integers starting from `1`. 10 | It doesn't follow the SemVer versioning. 11 | Given application's reliance on plugins, once it is stable, 12 | introducing breaking changes will be done carefully (if at all) and will be given a reasonable grace period to migrate. 13 | Before application is declared stable, breaking changes could be done without a grace period. 14 | 15 | ## Tools 16 | 17 | [`@project-gauntlet/tools`](https://www.npmjs.com/package/@project-gauntlet/tools) uses SemVer. 18 | 19 | ## Plugins 20 | 21 | Plugins only have the latest published "version" described by release date -------------------------------------------------------------------------------- /docs/information/terminology.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Terminology" 3 | sidebar_position: 1 4 | sidebar_label: "Terminology" 5 | --- 6 | 7 | An explanation of various terms used in this documentation 8 | 9 | ## Action 10 | 11 | Action is a piece of functionality created by plugin that is executed on some kind of user action, be it mouse click or shortcut press. 12 | 13 | See [Action](../api-reference/actions.mdx) documentation 14 | 15 | ## Entrypoint 16 | 17 | Entrypoint is a collective term for Views and Commands created by plugins. All available entrypoints can be searched in main window search 18 | 19 | ## View 20 | 21 | Type of Entrypoint that has a UI and uses React to create it 22 | 23 | ## Command 24 | 25 | Type of Entrypoint that doesn't have a UI and instead just executes piece of code 26 | 27 | -------------------------------------------------------------------------------- /docs/api-reference/icons-and-images.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Icons and Images" 3 | sidebar_position: 2 4 | sidebar_label: "Icons and Images" 5 | --- 6 | 7 | import IconCode from '@site/src/generated/code_example/ui_icons_and_images/icon'; 8 | import UrlCode from '@site/src/generated/code_example/ui_icons_and_images/url'; 9 | import AssetCode from '@site/src/generated/code_example/ui_icons_and_images/asset'; 10 | 11 | ## Overview 12 | 13 | There are a lot of places in views where images or icons can be displayed 14 | 15 | ## Icons 16 | 17 | Icons can be used in all places where regular images are accepted 18 | 19 | 20 | 21 | ## Image from URL 22 | 23 | 24 | 25 | ## Image from Assets 26 | 27 | 28 | 29 | [//]: # (## API Reference) 30 | 31 | [//]: # (TODO list of icons) 32 | -------------------------------------------------------------------------------- /docs/plugin-installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Plugin Installation" 3 | sidebar_position: 4 4 | sidebar_label: "Plugin Installation" 5 | --- 6 | 7 | 1. Find git repository of the plugin you want to install. Gauntlet Plugin repository will always have `gauntlet.toml` file in root directory 8 | 2. Copy url of the git repository, same one that will usually be used for cloning 9 | 3. In Gauntlet main window search for "Gauntlet Settings" and open it 10 | 4. In Settings, in Plugins tab click bit '+' button 11 | 5. Paste the git url into newly appeared text field under '+' button and press Enter 12 | 6. UI will show check mark on top right if plugin is successfully installed 13 | 14 | :::warning 15 | 16 | Currently, Gauntlet doesn't support installation of plugins if git repository requires authentication to download 17 | 18 | ::: -------------------------------------------------------------------------------- /docs/feature-support.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Feature Support" 3 | sidebar_position: 8 4 | sidebar_label: "Feature Support" 5 | --- 6 | 7 | Only features that are not supported on all operating systems are listed here 8 | 9 | ## Features 10 | - Window tracking: whether Gauntlet is able to track which windows are open and which application created them 11 | 12 | ## Matrix 13 | - ✅ - supported 14 | - ❌ - not currently supported/possible/explored 15 | 16 | | | macOS | Linux X11 | Linux Wayland | Windows | 17 | |------------------|-------|-----------|---------------|---------| 18 | | Window Tracking | ❌ | ✅ | ✅ [1] | ❌ | 19 | | Global Shortcuts | ✅ | ✅ | ❌ [2] | ✅ | 20 | 21 | ## Notes 22 | 1. Window Tracking on Wayland is currently only supported on wlroots-based window managers and Cosmic 23 | 2. Some Wayland window managers like KDE or Cosmic support legacy X11 API for registering global shortcuts 24 | - See [`wayland.global_shortcuts_api`](application-config.md#waylandglobal_shortcuts_api) for more information 25 | -------------------------------------------------------------------------------- /docs/api-reference/storage-and-cache.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Storage and Cache" 3 | sidebar_position: 7 4 | sidebar_label: "Storage and Cache" 5 | --- 6 | 7 | import StorageCode from '@site/src/generated/code_example/ui_storage/storage'; 8 | 9 | ## Overview 10 | 11 | In Gauntlet there are 3 tiers of hooks to manage your React view state: `useState`, `useCache` and `useStorage` 12 | 13 | - `useState` 14 | - Provided by React 15 | - State is not saved between view re-openings 16 | - `useCache` 17 | - Provided by Gauntlet 18 | - Ephemeral, state saved between view re-openings, but not between plugin restarts 19 | - Internally uses `sessionStorage` 20 | - Max size of session storage is 10MB per plugin 21 | - `useStorage` 22 | - Provided by Gauntlet 23 | - Persistent, state saved between view re-openings and between plugin restarts 24 | - Internally uses `localStorage` 25 | - Max size of local storage is 10MB per plugin 26 | 27 | ## Example 28 | 29 | 30 | 31 | [//]: # (## Api Reference) 32 | 33 | [//]: # (TODO type) 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/theming.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Theming" 3 | sidebar_position: 7 4 | sidebar_label: "Theming" 5 | --- 6 | 7 | Currently, in Gauntlet with themes it is possible to change: 8 | - Colors of text and background 9 | - Window border color, width and radius 10 | - Border radius of components in content 11 | 12 | Theming is only affects main window and doesn't affect Settings UI 13 | 14 | Theme config file is in [TOML](https://toml.io) format 15 | 16 | Theme config file locations: 17 | - Windows: `C:\Users\Username\AppData\Roaming\Gauntlet\config\theme.toml` 18 | - Linux: `$HOME/.config/gauntlet/theme.toml` or `$XDG_CONFIG_HOME/gauntlet/theme.toml` 19 | - macOS: `$HOME/Library/Application Support/dev.project-gauntlet.gauntlet/theme.toml` 20 | 21 | On theme may look slightly different on each system because of OS-provided window decorations 22 | 23 | Currently, changes to theme config are only applied after application restart 24 | 25 | Any errors in theme config file will be shown in application logs 26 | 27 | See bundled themes for examples [here](https://github.com/project-gauntlet/gauntlet/tree/main/bundled_themes) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Preparation 6 | 7 | In main repo 8 | ```bash 9 | npm run run-component-model-gen 10 | npm run run-scenarios 11 | ``` 12 | 13 | In this repo 14 | ```bash 15 | yarn 16 | yarn run run-generator ../gauntlet # path to main gauntlet repo 17 | ``` 18 | 19 | ### Local Development 20 | 21 | ```bash 22 | yarn start 23 | ``` 24 | 25 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 26 | 27 | ### Build 28 | 29 | ```bash 30 | yarn build 31 | ``` 32 | 33 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 34 | 35 | ### Deployment 36 | 37 | Using SSH: 38 | 39 | ```bash 40 | USE_SSH=true yarn deploy 41 | ``` 42 | 43 | Not using SSH: 44 | 45 | ```bash 46 | GIT_USER= yarn deploy 47 | ``` 48 | 49 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 50 | -------------------------------------------------------------------------------- /docs/api-reference/assets.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Assets" 3 | sidebar_position: 6 4 | sidebar_label: "Assets" 5 | --- 6 | 7 | import AssetImageCode from '@site/src/generated/code_example/ui_icons_and_images/asset'; 8 | import AssetsByteArrayCode from '@site/src/generated/code_example/command/assets'; 9 | 10 | ## Overview 11 | 12 | Assets are all files located in `assets` directory in root of plugin repository, be it image, text file or anything else. 13 | Asset files can be referenced in various predefined places in plugin manifest or code, or be imported as a byte array in your code 14 | 15 | 16 | ## Icon of entrypoint 17 | 18 | Every entrypoint can have an icon. For non-generated entrypoints this icon is defined in Plugin Manifest. 19 | See [Plugin Manifest](../plugin-development/manifest#entrypointicon) page for specific property 20 | 21 | ## Image in component 22 | 23 | Images in React views can also be fetched directly from assets 24 | 25 | 26 | 27 | ## Byte array 28 | 29 | Assets can also be fetched on demand as `ArrayBuffer` 30 | 31 | 32 | 33 | [//]: # (## API Reference) 34 | 35 | [//]: # (TODO) 36 | -------------------------------------------------------------------------------- /src/components/PropsTable/index.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | import { Property, renderPropertyType } from "@site/src/components/types"; 3 | 4 | interface Data { 5 | internalName: string 6 | props: Property[] 7 | } 8 | 9 | export default function Default({ data }: { data: Data }): ReactNode { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {data.props.map(property => { 22 | return ( 23 | 24 | 25 | 26 | 29 | 30 | 31 | ); 32 | })} 33 | 34 |
NameIs RequiredTypeDescription
{property.name}{property.optional ? "Optional" : "Required"} 27 | {renderPropertyType(property.type)} 28 | {property.description}
35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import Link from '@docusaurus/Link'; 2 | import Layout from '@theme/Layout'; 3 | 4 | import styles from './index.module.css'; 5 | import { ReactElement } from "react"; 6 | 7 | export default function Home(): ReactElement { 8 | return ( 9 | 14 |
15 |
16 | 17 | Work In Progress 18 | 19 | 20 | 21 | Work In Progress 22 | 23 |
24 |
25 | 28 | Go To Documentation 29 | 30 | 33 | Discord Server 34 | 35 |
36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /docs/troubleshooting.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Troubleshooting" 3 | sidebar_position: 9 4 | sidebar_label: "Troubleshooting" 5 | --- 6 | 7 | 8 | ## Crash logs 9 | 10 | If application panics, the crash logs are saved at following locations: 11 | 12 | - Windows: `{FOLDERID_LocalAppData}\Gauntlet\data\logs\crash.txt` 13 | - macOS: `$HOME/Library/Application Support/dev.project-gauntlet.gauntlet/logs/crash.txt` 14 | - Linux: `$HOME/.local/state/gauntlet/logs/crash.txt` or `$XDG_STATE_HOME/gauntlet/logs/crash.txt` 15 | 16 | In Gauntlet each plugin is run in separate plugin runtime process, 17 | if that process panics the logs will also be saved at that location but with following name: `crash-{plugin-internal-uuid}.txt` 18 | 19 | ## macOS 20 | 21 | ### Gauntlet Logs 22 | To see the Gauntlet application logs on macOS do the following: 23 | - Stop any running instance of Gauntlet 24 | - In terminal run: `open -n /Applications/Gauntlet.app --stdout ./gauntlet.log --stderr ./gauntlet.log` 25 | - `gauntlet.log` file in current directory will contain the logs 26 | 27 | ### Console.app 28 | macOS does a some additional validation on the binary before it is even started, 29 | any errors that occur at this stage should be visible in Console.app 30 | 31 | ## Linux 32 | 33 | ### Gauntlet Logs 34 | On Linux on Systemd-based systems Gauntlet is usually started as user service. 35 | To get logs Gauntlet Application logs in this setup run: `journalctl --user -u gauntlet` 36 | 37 | -------------------------------------------------------------------------------- /src/components/PerTypeMembersTable/index.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentRef, renderArity } from "@site/src/components/types"; 2 | 3 | interface Data { 4 | tableKey: string 5 | members: Record, 6 | } 7 | 8 | export default function Default({ data }: { data: Data }): JSX.Element { 9 | return ( 10 | <> 11 |

12 | Available non-order-sensitive React children components. The position in children doesn't matter for 13 | these elements 14 |

15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | {Object.entries(data.members).map(([name, componentRef]) => { 25 | return ( // TODO Link to section 26 | 27 | 28 | 31 | 32 | 33 | ); 34 | })} 35 | 36 |
NameReact Component TypeAmount
{name} 29 | <{componentRef.componentName}/> 30 | {renderArity(componentRef.arity)}
37 | 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/command.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Command" 3 | sidebar_position: 3 4 | sidebar_label: "Command" 5 | --- 6 | 7 | import CommandSimpleCode from '@site/src/generated/code_example/command/simple'; 8 | import CommandPreferencesCode from '@site/src/generated/code_example/command/preferences'; 9 | 10 | ## Overview 11 | 12 | Command is used to run straightforward, fire and forget piece of code. 13 | 14 | ### Plugin Manifest 15 | 16 | To use commands, entrypoint with type `"command"` is required 17 | 18 | #### Example 19 | ```toml 20 | [[entrypoint]] 21 | id = 'main' 22 | name = 'Main' 23 | path = 'src/main.tsx' 24 | type = 'command' 25 | description = 'Description of a command' 26 | ``` 27 | 28 | ## Note on usage of `async` 29 | 30 | JavaScript is a single-threaded language, at any time only one chunk of code is being executed. 31 | 32 | This has implications on Gauntlet plugins. 33 | 34 | Let's say in the same plugin you have 2 entrypoints: view and command, let's also say that your command entrypoint needs to scan some directories. 35 | If you are using synchronous versions of functions to access file system, user will not be able to open any views 36 | because JS runtime is being busy with scanning directories. For this reason prefer using async versions of APIs where possible, 37 | or if your code is computationally intensive, offload the computation to a worker 38 | 39 | ## Examples 40 | 41 | ### Simple 42 | 43 | 44 | 45 | ### Preferences 46 | 47 | 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gauntlet-docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc", 16 | "run-generator": "npm run run-generator --workspace component-generator" 17 | }, 18 | "workspaces": [ 19 | "component-generator" 20 | ], 21 | "dependencies": { 22 | "@docusaurus/core": "3.6.1", 23 | "@docusaurus/preset-classic": "3.6.1", 24 | "@iconify/react": "^5.0.2", 25 | "@mdx-js/react": "^3.0.0", 26 | "clsx": "^2.0.0", 27 | "prism-react-renderer": "^2.3.0", 28 | "react": "^18.0.0", 29 | "react-dom": "^18.0.0" 30 | }, 31 | "devDependencies": { 32 | "@docusaurus/module-type-aliases": "3.6.1", 33 | "@docusaurus/tsconfig": "3.6.1", 34 | "@docusaurus/types": "3.6.1", 35 | "buffer": "~6.0.3", 36 | "typescript": "~5.6.3" 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.5%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 3 chrome version", 46 | "last 3 firefox version", 47 | "last 5 safari version" 48 | ] 49 | }, 50 | "engines": { 51 | "node": ">=18.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /docs/api-reference/environment.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Gauntlet Environment" 3 | sidebar_position: 9 4 | sidebar_label: "Environment" 5 | --- 6 | 7 | import EnvironmentCode from '@site/src/generated/code_example/command_environment/environment'; 8 | 9 | ## Overview 10 | 11 | Environment API provides information about the environment in which the plugin is running and additional information about runtime 12 | 13 | ## Example 14 | 15 | 16 | 17 | ## `Environment.gauntletVersion` 18 | Type: `number` 19 | 20 | Returns currently Gauntlet version 21 | 22 | ## `Environment.isDevelopment` 23 | Type: `boolean` 24 | 25 | Returns true if the plugin was installed using `npm run dev` command from dev tools as opposed to Settings UI 26 | 27 | ## `Environment.pluginDataDir` 28 | Type: `string` 29 | 30 | Returns absolute path to directory that is assigned to current plugin only and is meant for storing general data. 31 | If writing or reading to/from this directory Plugin must declare it in permissions using `{common:plugin-data}` [path variable](../plugin-development/manifest#path-variables). 32 | The directory will be created automatically during plugin startup 33 | 34 | ## `Environment.pluginCacheDir` 35 | Type: `string` 36 | 37 | Returns absolute path to directory that is assigned to current plugin only and is meant for storing cache. 38 | If writing or reading to/from this directory Plugin must declare it in permissions using `{common:plugin-cache}` [path variable](../plugin-development/manifest#path-variables). 39 | The directory will be created automatically during plugin startup 40 | -------------------------------------------------------------------------------- /src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .layoutWrapper { 2 | overflow: hidden; 3 | display: flex; 4 | justify-content: center; 5 | align-items: center; 6 | position: relative; 7 | } 8 | 9 | .hazardTapeContainer { 10 | z-index: -1; 11 | transform: rotate(30deg); 12 | position: absolute; 13 | } 14 | 15 | @media (max-width: 500px) { 16 | .hazardTapeContainer { 17 | transform: rotate(60deg); 18 | } 19 | } 20 | 21 | .hazardTapeContainer::before, 22 | .hazardTapeContainer::after { 23 | content: ""; 24 | position: absolute; 25 | inset: 0; 26 | z-index: -1; 27 | background: linear-gradient( 28 | 0deg, 29 | transparent, 30 | #FBB517, 31 | transparent 32 | ); 33 | } 34 | 35 | .hazardTapeContainer::after { 36 | filter: blur(3.5rem); 37 | } 38 | 39 | .hazardTape { 40 | width: 2000px; 41 | height: 100px; 42 | 43 | display: flex; 44 | justify-content: center; 45 | align-items: center; 46 | 47 | background: repeating-linear-gradient( 48 | 45deg, 49 | black, 50 | black 10px, 51 | #FBB517 10px, 52 | #FBB517 20px 53 | ); 54 | } 55 | 56 | 57 | .hazardTapeSpacer { 58 | width: 350px; 59 | } 60 | 61 | @media (max-width: 500px) { 62 | .hazardTapeSpacer { 63 | width: 150px; 64 | } 65 | } 66 | 67 | .hazardTapeText { 68 | padding: 0 10px 3px 10px; 69 | font-size: x-large; 70 | font-weight: bold; 71 | color: black; 72 | background-color: #FBB517; 73 | border-radius: 5px; 74 | } 75 | 76 | .docsLink { 77 | margin: 30px; 78 | } 79 | -------------------------------------------------------------------------------- /docs/api-reference/preferences.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Preferences" 3 | sidebar_position: 5 4 | sidebar_label: "Preferences" 5 | --- 6 | 7 | import ViewPreferenceCode from '@site/src/generated/code_example/ui_preferences/preferences'; 8 | 9 | ## Overview 10 | 11 | Preferences are a way for plugins to be configured. Value of preference can be changed in Settings UI. 12 | 13 | There are 2 types of preferences: plugin (scoped to whole plugin) and entrypoint (specific to given entrypoint). 14 | 15 | Preferences are defined in manifest. 16 | Preference can be defined with default value, if default value is not provided preference is considered to be required 17 | and user will be prompted before running the command or opening view to set preference value. 18 | 19 | Currently supported types of values: 20 | - number 21 | - string 22 | - bool 23 | - enum (string, but only predefined list of values is allowed) 24 | - list of strings 25 | - list of numbers 26 | - list of enums 27 | 28 | :::note 29 | 30 | Currently, lists do not support specifying default value, and it will always be an empty list 31 | 32 | ::: 33 | 34 | ## Preferences In View 35 | 36 | ### Example 37 | 38 | 39 | 40 | [//]: # (### Api Reference) 41 | 42 | [//]: # (TODO types) 43 | 44 | ## Preferences In Command 45 | 46 | ### Example 47 | 48 | See [Preference Section](../api-reference/entrypoint-types/entrypoint-generator.mdx#preferences) on Command page for example 49 | 50 | ## Preferences In Entrypoint Generator 51 | 52 | ### Example 53 | 54 | See [Preference Section](../api-reference/entrypoint-types/entrypoint-generator.mdx#preferences) on Entrypoint Generator page for example 55 | -------------------------------------------------------------------------------- /docs/plugin-development/file-structure.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Plugin File Structure" 3 | sidebar_position: 2 4 | sidebar_label: "File Structure" 5 | --- 6 | 7 | ## Overview 8 | 9 | Here file structure of a plugin is described 10 | 11 | Notable directories and files of a plugin are following: 12 | ``` 13 | plugin 14 | ├── assets 15 | │ └── icon.png 16 | ├── src 17 | │ └── entrypoint.tsx 18 | ├── dist 19 | ├── node_modules 20 | ├── gauntlet.toml 21 | ├── package-lock.json 22 | ├── package.json 23 | └── tsconfig.json 24 | ``` 25 | 26 | ## Plugin manifest 27 | 28 | `gauntlet.toml` is a plugin manifest. 29 | It is used to describe the plugin, what entrypoints does it have, what preferences, what permissions it requires 30 | 31 | See [Plugin Manifest](manifest.md) 32 | 33 | ## Source Code 34 | 35 | All source files go into `src` directory. Currently, only TypeScript language is officially supported, which uses `.ts` or `.tsx` file extensions. 36 | `.tsx` is used everywhere where some kind of UI is being created 37 | 38 | ## Assets 39 | 40 | `assets` directory contains files which will be downloaded together with the plugin itself. 41 | It is optional and is only required if plugin has at least one asset 42 | 43 | See [Assets](../api-reference/assets.mdx) 44 | 45 | ## `dist` directory 46 | 47 | `dist` directory contains compiled plugin. It is created when starting dev server or when publishing the plugin 48 | 49 | ## Dependency management 50 | 51 | `node_modules`, `package-lock.json` and `package.json` all belong to Node.js and npm. 52 | Even though Gauntlet uses Deno to run plugins, Node.js is used to run tooling: gather dependencies, run dev server, publish, etc. 53 | 54 | ## Other 55 | 56 | `tsconfig.json` is a configuration file for TypeScript language compiler 57 | -------------------------------------------------------------------------------- /src/components/OrderedMembersTable/index.tsx: -------------------------------------------------------------------------------- 1 | import { ComponentRef, renderArity, renderPropertyType } from "@site/src/components/types"; 2 | 3 | interface Data { 4 | tableKey: string 5 | members: Record, 6 | withString: boolean 7 | } 8 | 9 | export default function Default({ data }: { data: Data }): JSX.Element { 10 | return ( 11 | <> 12 |

13 | Available order-sensitive React children components. The order in which these elements 14 | are be placed in code will 15 | be reflected in UI 16 |

17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {data.withString && ( 27 | 28 | 29 | 30 | 31 | 32 | )} 33 | {Object.entries(data.members).map(([name, componentRef]) => { 34 | return ( // TODO Link to section 35 | 36 | 37 | 40 | 41 | 42 | ); 43 | })} 44 | 45 |
NameReact Component TypeAmount
string{renderArity({ type: "zero_or_more" })}
{name} 38 | <{componentRef.componentName}/> 39 | {renderArity(componentRef.arity)}
46 | 47 | ) 48 | } 49 | -------------------------------------------------------------------------------- /docs/cli.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Gauntlet CLI" 3 | sidebar_position: 5 4 | sidebar_label: "CLI" 5 | --- 6 | 7 | Gauntlet has a simple command line interface 8 | 9 | ## Commands 10 | 11 | ### `gauntlet` 12 | 13 | Without any arguments calling Gauntlet binary will start the Gauntlet application. 14 | If application is already opened, the window of already opened application will be shown 15 | 16 | ### `gauntlet --minimized` 17 | 18 | By default, starting the application will open the main window. 19 | `--minimized` flag will start the application without opening the window. 20 | Useful when starting the application automatically on OS startup 21 | 22 | ### `gauntlet open` 23 | 24 | Opens main application window, if application is already running. Can be used instead of global shortcut 25 | 26 | ### `gauntlet settings` 27 | 28 | Opens Gauntlet settings 29 | 30 | ### `gauntlet run ` 31 | 32 | Runs commands, opens views, runs specific actions, can be used as a replacement for entrypoint-specific global shortcuts, 33 | e.g. if global shortcuts are not supported on your system 34 | 35 | - `` 36 | - Plugin ID, same value as the one used during installation 37 | - Also shown in Settings UI 38 | - `` 39 | - Entrypoint ID 40 | - Value can be found in [Plugin Manifest](http://localhost:3000/docs/plugin-development/manifest#entrypointid) 41 | - For [generated entrypoints](http://localhost:3000/docs/api-reference/entrypoint-types/entrypoint-generator), value is specified in plugin code 42 | - `` 43 | - Action ID 44 | - Value can be found in [Plugin Manifest](http://localhost:3000/docs/plugin-development/manifest#entrypointactionsid) 45 | - Also accepts special values 46 | - `:primary`: runs [primary action](https://gauntlet.sh/docs/api-reference/actions#overview) of the entrypoint 47 | - `:secondary`: runs [secondary action](https://gauntlet.sh/docs/api-reference/actions#overview) of the entrypoint 48 | 49 | ### `gauntlet --version` 50 | 51 | Shows Gauntlet version 52 | -------------------------------------------------------------------------------- /docs/information/architecture.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Architecture" 3 | sidebar_position: 2 4 | sidebar_label: "Architecture" 5 | --- 6 | 7 | ## Overview 8 | 9 | The application consists of 4 modules: server, frontend, plugin runtime and settings. 10 | 11 | ### Plugin Runtime 12 | Gauntlet plugins are written in TypeScript. 13 | As JavaScript runtime [Deno](https://deno.com) is used. 14 | Each plugin runtime runs in a separate Deno Worker in a separate OS process and communicates with server using inter-process communication. 15 | Deno Workers are sandboxed using [Deno's permission model](https://docs.deno.com/runtime/fundamentals/security). 16 | Each plugin must define permissions in [Plugin Manifest](../plugin-development/manifest#permissions) what external resources it needs: 17 | filesystem, network, environment variables or subprocess execution, some Gauntlet-specific permissions, etc. 18 | 19 | Plugins can use [React](https://github.com/facebook/react) to create UI that will be rendered by frontend. 20 | This is implemented using custom React Reconciler (similar to React Native). 21 | 22 | The Deno runtime is kept alive by the always running event loop that handles incoming events from frontend/server 23 | 24 | Plugins are distributed inside the same Git repository which contains the plugin code. 25 | There is no central distribution system currently. 26 | Plugins are installed using the Git repository URL 27 | 28 | 29 | :::warning 30 | 31 | Due to limited resources, security measures for Gauntlet application are implemented on a best-effort basis and are not guaranteed 32 | 33 | ::: 34 | 35 | ### Frontend 36 | 37 | As GUI framework [iced-rs](https://github.com/iced-rs/iced) is used. 38 | Frontend runs inside the same OS process as server. 39 | 40 | ### Server 41 | 42 | The server is fairly straightforward [Tokio](https://tokio.rs/) runtime. 43 | All requests or events from frontend to plugin runtime and vice versa go through the server. 44 | Server state is stored inside SQLite database 45 | 46 | ### Settings 47 | 48 | Settings UI also uses [iced-rs](https://github.com/iced-rs/iced) as a GUI framework. 49 | It is run in separate OS process which communicates with server using inter-process communication 50 | -------------------------------------------------------------------------------- /docs/api-reference/actions.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Actions" 3 | sidebar_position: 4 4 | sidebar_label: "Actions" 5 | --- 6 | 7 | import ActionPanelProps from '@site/src/generated/tables/action_panel/props'; 8 | import ActionPanelOrderedMembers from '@site/src/generated/tables/action_panel/ordered-members'; 9 | 10 | import ActionDescription from '@site/src/generated/tables/action/description'; 11 | import ActionCode from '@site/src/generated/code_example/ui_action_panel/action'; 12 | import ActionProps from '@site/src/generated/tables/action/props'; 13 | 14 | import SectionDescription from '@site/src/generated/tables/action_panel_section/description'; 15 | import SectionProps from '@site/src/generated/tables/action_panel_section/props'; 16 | import SectionOrderedMembers from '@site/src/generated/tables/action_panel_section/ordered-members'; 17 | 18 | import SectionActionCode from '@site/src/generated/code_example/ui_action_panel/section'; 19 | 20 | ## Overview 21 | 22 | Action is a piece of code executed on some kind of user action, be it mouse click or shortcut press. 23 | 24 | In UI list of actions is displayed in the Action Panel. 25 | 26 | Actions can be executed using shortcuts, custom and predefined ones. 27 | First and second actions in Action Panel become primary and secondary actions respectively. 28 | Primary action gets automatically assigned Enter shortcut and secondary - Shift + Enter. 29 | Even though it is still possible to assign custom shortcuts to primary and secondary actions, they will not be visible in action panel in UI 30 | 31 | Actions can be defined for entrypoints or views. 32 | 33 | ## Actions in Generated Entrypoints 34 | 35 | See [Entrypoint Generator](entrypoint-types/entrypoint-generator.mdx) 36 | 37 | ## Actions in View and Command Entrypoints 38 | 39 | For `"view"` and `"command"` entrypoints, currently, it is not possible to define additional actions. 40 | The file referenced in manifest becomes primary action 41 | 42 | ## Actions inside Views 43 | 44 | Actions in views are often context-aware, e.g. based on the selected list item. 45 | Actions in Action Panel can be grouped into semantic sections and have keyboard shortcuts assigned. 46 | 47 | ## View Api Reference 48 | 49 | ### ActionPanel 50 | 51 | #### Props 52 | 53 | 54 | #### Children components (order-sensitive) 55 | 56 | 57 | 58 | 59 | ### ActionPanel.Action 60 | 61 | 62 | #### Example 63 | 64 | 65 | #### Props 66 | 67 | 68 | 69 | 70 | ### ActionPanel.Section 71 | 72 | 73 | #### Props 74 | 75 | 76 | #### Children components (order-sensitive) 77 | 78 | 79 | 80 | 81 | ### ActionPanel.Section.Action 82 | 83 | #### Example 84 | 85 | -------------------------------------------------------------------------------- /docs/application-config.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Application Config" 3 | sidebar_position: 6 4 | sidebar_label: "Config" 5 | --- 6 | 7 | ## Overview 8 | 9 | Application Config uses [TOML](https://toml.io) file format 10 | 11 | Location: 12 | - Windows: `C:\Users\Username\AppData\Roaming\Gauntlet\config\config.toml` 13 | - Linux: `$HOME/.config/gauntlet/config.toml` or `$XDG_CONFIG_HOME/gauntlet/config.toml` 14 | - macOS: `$HOME/Library/Application Support/dev.project-gauntlet.gauntlet/config.toml` 15 | 16 | ### `main_window.close_on_unfocus` 17 | 18 | Whether main window is closed when it receives unfocus event. Useful for tiling window managers 19 | 20 | **Type**: `bool`
21 | **Default**: `true` 22 | 23 | ### `wayland.main_window_surface` 24 | 25 | Allows to specify which API will be used to display, position and order main window. Doesn't have effect on non-Wayland environments 26 | 27 | **Type**: `enum`
28 | **Default**: `"prefer_wlr_layer_shell"` 29 | 30 | | Value | Description | 31 | |----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 32 | | `"wlr_layer_shell"` | Use [layer shell protocol](https://wayland.app/protocols/wlr-layer-shell-unstable-v1) | 33 | | `"xdg_shell"` | Use regular window, useful for cases where layer shell protocol is not supported. May result in incorrect window sizing, positioning and/or ordering of the window depending on window manager/desktop environment used | 34 | | `"prefer_wlr_layer_shell"` | Use `wlr_layer_shell`, but fall back to `xdg_shell` if layer shell protocol is not supported | 35 | 36 | 37 | ### `wayland.global_shortcuts_api` 38 | 39 | Allows to specify which API (if any) will be used to register global shortcuts. Doesn't have effect on non-Wayland environments 40 | 41 | **Type**: `enum`
42 | **Default**: `"none"` 43 | 44 | | Value | Description | 45 | |--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------| 46 | | `"none"` | Disable global shortcut functionality. User should instead use [CLI commands](./cli.md) instead and register them in windows manager/desktop environment specific way | 47 | | `"legacy_x11_api"` | Should be used if your windows manager/desktop environment supports legacy X11 api for global shortcuts. Notably KDE's "Legacy X11 App Support" settings option | 48 | -------------------------------------------------------------------------------- /docs/plugin-development/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting Started" 3 | sidebar_position: 1 4 | sidebar_label: "Getting Started" 5 | --- 6 | 7 | This page describes what you need to get started with creating your first Gauntlet plugin 8 | 9 | ## Prerequisites 10 | 11 | - You have Gauntlet [installed and running](../installation.md) 12 | - You have [Node.js](https://nodejs.org/en) installed 13 | - You have [npm](https://www.npmjs.com/) installed 14 | 15 | :::note 16 | 17 | Gauntlet documentation will assume some basic knowledge of React and TypeScript. 18 | If you need some help with that, check out TypeScript's [Handbook](https://www.typescriptlang.org/docs/handbook/intro.html) and React's [Getting Started](https://react.dev/learn) guide 19 | 20 | ::: 21 | 22 | :::note 23 | 24 | Gauntlet documentation also assumes that you have Plugin API TypeScript Declarations files of `@project-gauntlet/api` package open in your favourite IDE alongside this documentation 25 | 26 | ::: 27 | 28 | :::note 29 | 30 | This page assumes that you will be using GitHub and GitHub Actions to host plugin repository and publish it. 31 | It is possible to use any other hosting solution with some minor changes to the plugin template, but it is outside the scope of this documentation 32 | 33 | ::: 34 | 35 | ## Getting development environment ready 36 | 37 | 1. Using https://github.com/project-gauntlet/plugin-template template, create your own repository from it 38 | 2. Clone newly created repository to your machine 39 | 3. Run `npm install` to install dependencies 40 | 41 | ## Running dev server 42 | 43 | To run the dev server, run `npm run dev` command 44 | 45 | 1. Make sure that Gauntlet is running on your system 46 | 2. Dev server will compile the plugin, do the type checking and validate the manifest 47 | 3. Dev server will then connect to Gauntlet and install dev plugin so it is usable like a regular plugin 48 | 4. Any changes made to plugin's source code and manifest will be automatically reflected in Gauntlet UI when file is saved while the dev server is running 49 | 50 | :::note 51 | 52 | Plugins installed via `npm run dev` are using React Dev mode to have better error messages for development. 53 | This comes with a tradeoff of having worse performance when rendering the view 54 | 55 | ::: 56 | 57 | ## Building 58 | 59 | Dev server will automatically build plugin, but sometimes it is useful to build the plugin without running the dev server. 60 | For this `npm run build` command is available 61 | 62 | ## Publishing 63 | 64 | Publishing a plugin may be a different in Gauntlet than use are used to. It is distributed, and doesn't have any central system 65 | 66 | Plugins are distributed as a part of the same git repository which contains the code (similar to GitHub Pages). 67 | To publish the plugin you need to run `npm run publish`. But because during publishing process changes are being made to the git repository, 68 | it is **strongly** encouraged to use CI/CD to do it, template repository has predefined workflow already available 69 | 70 | Compiled plugin is stored on `gauntlet/release` branch and when installing plugin using git repository url (same as the one used for `git clone`), 71 | Gauntlet will download that branch and install plugin from there. 72 | -------------------------------------------------------------------------------- /src/components/CodeExample/index.tsx: -------------------------------------------------------------------------------- 1 | import Tabs from '@theme/Tabs'; 2 | import TabItem from '@theme/TabItem'; 3 | import React from 'react'; 4 | import CodeBlock from "@theme/CodeBlock"; 5 | import UiScreenshot from "../UiScreenshot"; 6 | import styles from './styles.module.css'; 7 | import { Icon } from '@iconify/react' 8 | import Link from "@docusaurus/Link"; 9 | 10 | interface GauntletGithubCodeEntrypointData { 11 | codeFilePathRootRelative: string 12 | codeFilePathPluginRelative: string 13 | codeSegments: { 14 | id: string, 15 | value: string, 16 | lines?: [number, number], 17 | screenshotFilePath: string, 18 | }[] 19 | manifestFilePathRootRelative: string 20 | manifestFilePathPluginRelative: string 21 | manifestSegment: { 22 | value: string 23 | manifestFileLines: [number, number] 24 | } 25 | } 26 | 27 | export default function Default({ data, screenshot }: { data: GauntletGithubCodeEntrypointData, screenshot?: boolean }): JSX.Element { 28 | function githubLink(rootRelativePath: string, lines?: [number, number]): string { 29 | if (lines) { 30 | const [startLine, endLine] = lines 31 | return `https://github.com/project-gauntlet/gauntlet/blob/main/${rootRelativePath}#L${startLine}-L${endLine}`; 32 | } else { 33 | return `https://github.com/project-gauntlet/gauntlet/blob/main/${rootRelativePath}`; 34 | } 35 | } 36 | 37 | let elements = data.codeSegments 38 | .map(value => { 39 | const label = value.id === "default" ? data.codeFilePathPluginRelative : `${data.codeFilePathPluginRelative} - ${value.id}` 40 | 41 | return ( 42 | 43 |
44 | 48 | {value.value} 49 | 50 | 52 | 53 | 54 |
55 | {(screenshot ?? true) && } 56 |
57 | ) 58 | }); 59 | 60 | elements.push( 61 | 62 |
63 | 64 | {data.manifestSegment.value} 65 | 66 | 68 | 69 | 70 |
71 |
72 | ) 73 | 74 | return ( 75 | 76 | {elements} 77 | 78 | ); 79 | } 80 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Installation" 3 | sidebar_position: 2 4 | sidebar_label: "Installation" 5 | --- 6 | 7 | ## OS Support 8 | 9 | ### Official 10 | 11 | - Linux X11 x86_64 12 | - macOS M1 13 | 14 | ### Best-effort 15 | 16 | - Linux Wayland x86_64 17 | - Windows x86_64 18 | - macOS x86_64 19 | 20 | ## macOS 21 | 22 | Although it is possible to install Gauntlet by using `.dmg` directly, application doesn't have auto-update functionality so it is recommended to install using `brew` package manager 23 | 24 | Brew package: [link](https://formulae.brew.sh/cask/gauntlet) 25 | 26 | To install run: 27 | 28 | ``` 29 | brew install --cask gauntlet 30 | ``` 31 | 32 | To start, manually open application. 33 | 34 | ## Arch Linux 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
gauntlet-binLatest released version as a pre compiled binary. Recommended
gauntlet-gitFresh changes built from the latest git commit. Unstable, may result in missing functionality or data corruption. Use at your own risk
46 | 47 | To install run: 48 | 49 | ``` 50 | yay -S gauntlet-bin 51 | ``` 52 | 53 | Or if you prefer a fresh build directly from github: 54 | 55 | ``` 56 | yay -S gauntlet-git 57 | ``` 58 | 59 | To start `systemd` service run: 60 | 61 | ``` 62 | systemctl --user enable --now gauntlet.service 63 | ``` 64 | 65 | ## Nix 66 | 67 | See installation instructions [here](https://github.com/project-gauntlet/gauntlet/blob/main/nix/README.md) 68 | 69 | ## Other Linux Distributions 70 | 71 | At the moment application is available only for Arch Linux and Nix. If you want to create a package for other distributions see [Application packaging for Linux](#application-packaging-for-linux) 72 | 73 | ## Windows 74 | 75 | Download `.msi` at [Releases page](https://github.com/project-gauntlet/gauntlet/releases/latest) and open to install Gauntlet 76 | 77 | Note: application doesn't have auto-update functionality, and has to be updated manually 78 | 79 | To start, manually open application. 80 | 81 | ## Application packaging for Linux 82 | 83 | This section contains a list of things that could be useful for someone who wants to package application for Linux distribution. 84 | If something is missing, please [create an issue](https://github.com/project-gauntlet/gauntlet/issues) 85 | 86 | Application is already packaged for [Arch Linux](#arch-linux) and [Nix](#nix) so you can use them as examples 87 | 88 | Relevant CLI commands: 89 | 90 | - `gauntlet --minimized` 91 | - Server needs to be started when user logs in, e.g. using `systemd` service 92 | - `gauntlet open` 93 | - Main windows is usually opened using global shortcut, this CLI command can be used in cases where global shortcut functionality is not available 94 | - `gauntlet settings` 95 | - Settings are usually started on demand from Gauntlet itself 96 | 97 | `.desktop` sample file can be found [here](https://github.com/project-gauntlet/gauntlet/blob/main/assets/linux/gauntlet.desktop) 98 | 99 | `systemd` service sample file can be found [here](https://github.com/project-gauntlet/gauntlet/blob/main/assets/linux/gauntlet.service) 100 | 101 | Application plugin depends on `gtk-launch` 102 | 103 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/entrypoint-generator.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Entrypoint Generator" 3 | sidebar_position: 4 4 | sidebar_label: "Entrypoint Generator" 5 | --- 6 | 7 | import GeneratorSimpleCode from '@site/src/generated/code_example/entrypoint_generator_simple/simple'; 8 | import GeneratorFsEventsCode from '@site/src/generated/code_example/entrypoint_generator_fs_events/fs-events'; 9 | import GeneratorAccessoriesCode from '@site/src/generated/code_example/entrypoint_generator_accessories/accessories'; 10 | import GeneratorIconsCode from '@site/src/generated/code_example/entrypoint_generator_icons/icons'; 11 | import GeneratorPreferencesCode from '@site/src/generated/code_example/entrypoint_generator_preferences/preferences'; 12 | import GeneratorActionShortcutCode from '@site/src/generated/code_example/entrypoint_generator_action_shortcut/action-shortcut'; 13 | 14 | ## Overview 15 | 16 | Entrypoint generator is used for procedural generation of entrypoints. 17 | 18 | ### Functionality 19 | - Dynamically add, remove, update one or more entrypoints at any point in plugin lifetime 20 | - Generated entrypoints can have accessories 21 | - Generated entrypoints can have multiple actions, each of which can be a command or a view 22 | 23 | For performance reasons, the entrypoints are generated once and stored for later use instead of being generated each time when main window is opened. 24 | This means that after initial generator run the only way to add, delete or remove generated entrypoint is based on some external event e.g. file change 25 | 26 | ### Plugin Manifest 27 | 28 | To use entrypoint generator, entrypoint with type `"entrypoint-generator"` is required 29 | 30 | #### Example 31 | ```toml 32 | [[entrypoint]] 33 | id = 'main' 34 | name = 'Main' 35 | path = 'src/main.tsx' 36 | type = 'entrypoint-generator' 37 | description = 'Description of a entrypoint generator' 38 | ``` 39 | 40 | ## Note on usage of `async` 41 | 42 | JavaScript is a single-threaded language, at any time only one chunk of code is being executed. 43 | 44 | This has implications on Gauntlet plugins. 45 | 46 | Let's say in the same plugin you have 2 entrypoints: view and entrypoint generator, let's also say that your generator entrypoint needs to scan some directories. 47 | If you are using synchronous versions of functions to access file system, user will not be able to open any views 48 | because JS runtime is being busy with scanning directories. For this reason prefer using async versions of APIs where possible, 49 | or if your code is computationally intensive, offload the computation to a worker 50 | 51 | ## Examples 52 | 53 | [//]: # (TODO screenshots for the main search list) 54 | 55 | ### Simple 56 | 57 | 58 | 59 | ### Update based on file system events 60 | 61 | This example shows how the name of the generated item can be dependent on the content of the file and will be updated when content of the file is updated 62 | 63 | 64 | 65 | ### Accessories 66 | 67 | 68 | 69 | ### Icons 70 | 71 | 72 | 73 | ### Preferences 74 | 75 | Try changing the preference values in Settings UI, the change will be automatically reflected in the entrypoint list 76 | 77 | 78 | 79 | ### Action shortcuts 80 | 81 | It is possible to assign specific shortcut to Entrypoint Action that works when the Entrypoint is focused 82 | 83 | See [Plugin Manifest](../../plugin-development/manifest#entrypoint-actions) for more information on meaning of manifest property values 84 | 85 | 86 | 87 | [//]: # (## Api Reference) 88 | 89 | [//]: # (TODO Context type) 90 | -------------------------------------------------------------------------------- /darcula.theme.ts: -------------------------------------------------------------------------------- 1 | import { PrismTheme } from "prism-react-renderer"; 2 | 3 | // https://github.com/LucaScorpion/prismjs-darcula-theme/blob/main/darcula.scss 4 | 5 | const background = "#2b2b2b"; 6 | const foreground = "#a3b7c6"; 7 | const comment = "#808080"; 8 | 9 | const orange = "#cc7832"; 10 | const yellow = "#e8bf6a"; 11 | const brightYellow = "#bbb529"; 12 | const green = "#6a8759"; 13 | const brightGreen = "#a5c261"; 14 | const purple = "#9876aa"; 15 | const blue = "#6897bb"; 16 | const brown = "#8a653b"; 17 | 18 | export default { 19 | plain: { 20 | color: foreground, 21 | background: background, 22 | }, 23 | styles: [ 24 | { 25 | types: ["comment"], 26 | style: { 27 | color: comment, 28 | } 29 | }, 30 | { 31 | types: ["keyword", "boolean", "constant", "null", "important", "rule"], 32 | style: { 33 | color: orange, 34 | } 35 | }, 36 | { 37 | types: ["number"], 38 | style: { 39 | color: blue, 40 | } 41 | }, 42 | { 43 | types: ["doctype", "function", "selector"], 44 | style: { 45 | color: yellow, 46 | } 47 | }, 48 | { 49 | types: ["tag"], 50 | style: { 51 | color: yellow, 52 | } 53 | }, 54 | { 55 | types: ["literal-property"], 56 | style: { 57 | color: foreground, 58 | } 59 | }, 60 | { 61 | types: ["attr-name"], 62 | style: { 63 | color: foreground, 64 | } 65 | }, 66 | { 67 | types: ["attr-value"], 68 | style: { 69 | color: brightGreen, 70 | } 71 | }, 72 | { 73 | types: ["string", "regex", "char"], 74 | style: { 75 | color: green, 76 | } 77 | }, 78 | { 79 | types: ["doc-comment"], 80 | style: { 81 | color: green, 82 | fontStyle: "italic", 83 | } 84 | }, 85 | { 86 | types: ["keyword"], 87 | style: { 88 | color: orange, 89 | } 90 | }, 91 | { 92 | types: ["parameter"], 93 | style: { 94 | color: foreground, 95 | } 96 | }, 97 | { 98 | types: ["annotation"], 99 | style: { 100 | color: brightYellow, 101 | } 102 | }, 103 | { 104 | types: ["constant"], 105 | style: { 106 | color: purple, 107 | } 108 | }, 109 | { 110 | types: ["important"], 111 | style: { 112 | fontWeight: "bold", 113 | } 114 | }, 115 | { 116 | types: ["bold"], 117 | style: { 118 | fontWeight: "bold", 119 | } 120 | }, 121 | { 122 | types: ["italic"], 123 | style: { 124 | fontStyle: "italic", 125 | } 126 | }, 127 | { 128 | types: ["entity"], 129 | style: { 130 | cursor: "help", 131 | } 132 | }, 133 | { 134 | languages: ["toml"], 135 | types: ["table"], 136 | style: { 137 | color: orange, 138 | } 139 | }, 140 | { 141 | languages: ["toml"], 142 | types: ["key"], 143 | style: { 144 | color: orange, 145 | } 146 | }, 147 | ] 148 | } satisfies PrismTheme 149 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/view/form.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Form" 3 | sidebar_position: 2 4 | sidebar_label: "Form" 5 | --- 6 | import UiScreenshot from '@site/src/components/UiScreenshot'; 7 | 8 | import FormDescription from '@site/src/generated/tables/form/description'; 9 | import FormCode from '@site/src/generated/code_example/ui_form/main'; 10 | import FormProps from '@site/src/generated/tables/form/props'; 11 | import FormOrderedMembers from '@site/src/generated/tables/form/ordered-members'; 12 | 13 | import TextFieldDescription from '@site/src/generated/tables/text_field/description'; 14 | import TextFieldCode from '@site/src/generated/code_example/ui_form/text-field'; 15 | import TextFieldProps from '@site/src/generated/tables/text_field/props'; 16 | 17 | import PasswordFieldDescription from '@site/src/generated/tables/password_field/description'; 18 | import PasswordFieldCode from '@site/src/generated/code_example/ui_form/password-field'; 19 | import PasswordFieldProps from '@site/src/generated/tables/password_field/props'; 20 | 21 | import CheckboxDescription from '@site/src/generated/tables/text_field/description'; 22 | import CheckboxCode from '@site/src/generated/code_example/ui_form/checkbox'; 23 | import CheckboxProps from '@site/src/generated/tables/text_field/props'; 24 | 25 | import SelectDescription from '@site/src/generated/tables/select/description'; 26 | import SelectCode from '@site/src/generated/code_example/ui_form/select'; 27 | import SelectProps from '@site/src/generated/tables/select/props'; 28 | import SelectOrderedMembers from '@site/src/generated/tables/select/ordered-members'; 29 | 30 | import SelectItemDescription from '@site/src/generated/tables/select_item/description'; 31 | import SelectItemProps from '@site/src/generated/tables/select_item/props'; 32 | import SelectItemOrderedMembers from '@site/src/generated/tables/select_item/ordered-members'; 33 | 34 | import SeparatorDescription from '@site/src/generated/tables/separator/description'; 35 | import SeparatorCode from '@site/src/generated/code_example/ui_form/separator'; 36 | 37 | 38 | ## Overview 39 | 40 | Form is a view which provides a way to collect different types information 41 | 42 | 43 | 44 | [//]: # (Functionality section when there is more features) 45 | [//]: # (As with all other views can be made highly dynamic with help of React) 46 | 47 | ### Plugin Manifest 48 | 49 | To use this view, entrypoint with type `"view"` is required 50 | 51 | #### Example 52 | ```toml 53 | [[entrypoint]] 54 | id = 'main' 55 | name = 'Main' 56 | path = 'src/main.tsx' 57 | type = 'view' 58 | description = 'Description of a Form view' 59 | ``` 60 | 61 | ## API Reference 62 | 63 | ### Form 64 | 65 | 66 | #### Example 67 | 68 | 69 | #### Props 70 | 71 | 72 | #### Children components (order-sensitive) 73 | 74 | 75 | 76 | 77 | ### Form.TextField 78 | 79 | 80 | #### Example 81 | 82 | 83 | #### Props 84 | 85 | 86 | 87 | 88 | ### Form.PasswordField 89 | 90 | 91 | #### Example 92 | 93 | 94 | #### Props 95 | 96 | 97 | 98 | 99 | ### Form.Checkbox 100 | 101 | 102 | #### Example 103 | 104 | 105 | #### Props 106 | 107 | 108 | 109 | 110 | ### Form.Select 111 | 112 | 113 | #### Example 114 | 115 | 116 | #### Props 117 | 118 | 119 | #### Children components (order-sensitive) 120 | 121 | 122 | 123 | 124 | ### Form.Select.Item 125 | 126 | 127 | #### Props 128 | 129 | 130 | #### Children components (order-sensitive) 131 | 132 | 133 | 134 | 135 | ### Form.Separator 136 | 137 | 138 | #### Example 139 | 140 | -------------------------------------------------------------------------------- /docusaurus.config.ts: -------------------------------------------------------------------------------- 1 | import { themes as prismThemes } from 'prism-react-renderer'; 2 | import type { Config } from '@docusaurus/types'; 3 | import type * as Preset from '@docusaurus/preset-classic'; 4 | import darculaTheme from "./darcula.theme"; 5 | 6 | 7 | const config: Config = { 8 | title: 'Gauntlet', 9 | favicon: 'img/favicon.ico', 10 | 11 | // Set the production url of your site here 12 | url: 'https://gauntlet.sh', 13 | // Set the // pathname under which your site is served 14 | // For GitHub pages deployment, it is often '//' 15 | baseUrl: '/', 16 | 17 | // GitHub pages deployment config. 18 | organizationName: 'project-gauntlet', 19 | projectName: 'website', 20 | deploymentBranch: 'gh-pages', 21 | 22 | trailingSlash: false, 23 | 24 | onBrokenLinks: 'throw', 25 | onBrokenMarkdownLinks: 'throw', 26 | 27 | // Even if you don't use internationalization, you can use this field to set 28 | // useful metadata like html lang. For example, if your site is Chinese, you 29 | // may want to replace "en" with "zh-Hans". 30 | i18n: { 31 | defaultLocale: 'en', 32 | locales: ['en'], 33 | }, 34 | 35 | presets: [ 36 | [ 37 | 'classic', 38 | { 39 | docs: { 40 | // TODO uncomment next page if you don't want to compile the Gauntlet 41 | // path: "dummy", 42 | sidebarPath: './sidebars.ts', 43 | sidebarCollapsible: false, 44 | editUrl: 'https://github.com/project-gauntlet/website/tree/main/', 45 | }, 46 | theme: { 47 | customCss: './src/css/custom.css', 48 | }, 49 | } satisfies Preset.Options, 50 | ], 51 | ], 52 | 53 | themeConfig: { 54 | colorMode: { 55 | defaultMode: "dark" 56 | }, 57 | navbar: { 58 | title: 'Gauntlet', 59 | logo: { 60 | alt: 'Gauntlet Logo', 61 | src: 'img/logo.png', 62 | style: { 63 | 'border-radius': '8px' 64 | } 65 | }, 66 | items: [ 67 | { 68 | type: 'docSidebar', 69 | sidebarId: 'docsSidebar', 70 | position: 'left', 71 | label: 'Docs', 72 | }, 73 | { 74 | href: 'https://github.com/project-gauntlet/gauntlet', 75 | label: 'GitHub', 76 | position: 'right', 77 | }, 78 | ], 79 | }, 80 | footer: { 81 | style: 'dark', 82 | links: [ 83 | { 84 | title: 'Website', 85 | items: [ 86 | { 87 | label: 'Docs', 88 | to: '/docs', 89 | }, 90 | ], 91 | }, 92 | { 93 | title: 'Community', 94 | items: [ 95 | { 96 | label: 'Discord', 97 | href: 'https://discord.gg/gFTqYUkBrW', 98 | }, 99 | ], 100 | }, 101 | { 102 | title: 'More', 103 | items: [ 104 | { 105 | label: 'GitHub', 106 | href: 'https://github.com/project-gauntlet/gauntlet', 107 | }, 108 | ], 109 | }, 110 | ], 111 | // copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, 112 | copyright: `Built with Docusaurus.`, 113 | }, 114 | prism: { 115 | theme: prismThemes.github, 116 | darkTheme: darculaTheme, 117 | additionalLanguages: ["toml"] 118 | }, 119 | } satisfies Preset.ThemeConfig, 120 | }; 121 | 122 | export default config; 123 | -------------------------------------------------------------------------------- /src/components/types.ts: -------------------------------------------------------------------------------- 1 | import { ReactNode } from "react"; 2 | 3 | export type Component = StandardComponent | RootComponent | TextPartComponent 4 | 5 | export type StandardComponent = { 6 | type: "standard", 7 | internalName: string, 8 | name: string, 9 | description: string 10 | props: Property[], 11 | children: Children, 12 | } 13 | 14 | export type RootComponent = { 15 | type: "root", 16 | internalName: string, 17 | children: ComponentRef[], 18 | sharedTypes: Record 19 | } 20 | 21 | export type SharedType = SharedTypeEnum | SharedTypeObject | SharedTypeUnion 22 | 23 | export type SharedTypeEnum = { 24 | type: "enum", 25 | items: string[], 26 | } 27 | 28 | export type SharedTypeObject = { 29 | type: "object", 30 | items: Record 31 | } 32 | 33 | export type SharedTypeUnion = { 34 | type: "union", 35 | items: PropertyType[] 36 | } 37 | 38 | export type TextPartComponent = { 39 | type: "text_part", 40 | internalName: string, 41 | } 42 | 43 | export type Property = { 44 | name: string 45 | optional: boolean 46 | description: string 47 | type: PropertyType 48 | } 49 | export type Children = ChildrenMembers | ChildrenString | ChildrenNone | ChildrenStringOrMembers 50 | 51 | export type ChildrenMembers = { 52 | type: "members", 53 | ordered_members: Record 54 | per_type_members: Record 55 | } 56 | export type ChildrenStringOrMembers = { 57 | type: "string_or_members", 58 | textPartInternalName: string, 59 | ordered_members: Record 60 | per_type_members: Record 61 | } 62 | export type ChildrenString = { 63 | type: "string" 64 | textPartInternalName: string, 65 | } 66 | export type ChildrenNone = { 67 | type: "none" 68 | } 69 | 70 | export type ComponentRef = { 71 | componentInternalName: string, 72 | componentName: string, 73 | arity: Arity 74 | } 75 | 76 | export type PropertyType = TypeString | TypeNumber | TypeBoolean | TypeComponent | TypeFunction | TypeSharedTypeRef | TypeImageArray | TypeImageUnion 77 | 78 | export type TypeString = { 79 | type: "string" 80 | } 81 | export type TypeNumber = { 82 | type: "number" 83 | } 84 | export type TypeBoolean = { 85 | type: "boolean" 86 | } 87 | export type TypeComponent = { 88 | type: "component" 89 | reference: ComponentRef, 90 | } 91 | export type TypeFunction = { 92 | type: "function" 93 | arguments: Property[] 94 | } 95 | export type TypeSharedTypeRef = { 96 | type: "shared_type_ref" 97 | name: string 98 | } 99 | export type TypeImageUnion = { 100 | type: "union" 101 | items: PropertyType[] 102 | } 103 | export type TypeImageArray = { 104 | type: "array" 105 | item: PropertyType 106 | } 107 | 108 | export type Arity = ArityZeroOrOne | ArityOne | ArityZeroOrMore 109 | 110 | export type ArityZeroOrOne = { 111 | type: "zero_or_one" 112 | } 113 | 114 | export type ArityOne = { 115 | type: "one" 116 | } 117 | 118 | export type ArityZeroOrMore = { 119 | type: "zero_or_more" 120 | } 121 | 122 | export function renderPropertyType(propertyType: PropertyType): ReactNode { 123 | switch (propertyType.type) { 124 | case "string": { 125 | return "string"; 126 | } 127 | case "number": { 128 | return "number"; 129 | } 130 | case "boolean": { 131 | return "boolean" 132 | } 133 | case "component": { 134 | return `<${propertyType.reference.componentName}/>` // TODO link 135 | } 136 | case "function": { 137 | const args = propertyType 138 | .arguments 139 | .map(prop => { 140 | const optional = prop.optional ? '?' : ''; 141 | 142 | `${prop.name}${optional}: ${renderPropertyType(prop.type)}` 143 | }) 144 | .join(); 145 | 146 | return `(${args}) => void` 147 | } 148 | case "shared_type_ref": { 149 | return propertyType.name // TODO link 150 | } 151 | case "array": { 152 | return `${renderPropertyType(propertyType.item)}[]` 153 | } 154 | case "union": { 155 | return propertyType.items.map(value => renderPropertyType(value)).join(" | ") 156 | } 157 | } 158 | } 159 | 160 | export function renderArity(arity: Arity): ReactNode { 161 | switch (arity.type) { 162 | case "zero_or_one": { 163 | return "Zero or One" 164 | } 165 | case "one": { 166 | return "Exactly One" 167 | } 168 | case "zero_or_more": { 169 | return "Zero or More" 170 | } 171 | } 172 | } -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/inline-view.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Inline View" 3 | sidebar_position: 2 4 | sidebar_label: "Inline View" 5 | --- 6 | import UiScreenshot from '@site/src/components/UiScreenshot'; 7 | 8 | import InlineDescription from '@site/src/generated/tables/inline/description'; 9 | import InlineProps from '@site/src/generated/tables/inline/props'; 10 | import InlineOrderedMembers from '@site/src/generated/tables/inline/ordered-members'; 11 | 12 | import InlineSeparatorDescription from '@site/src/generated/tables/inline/description'; 13 | 14 | import ContentDescription from '@site/src/generated/tables/content/description'; 15 | import ContentOrderedMembers from '@site/src/generated/tables/content/ordered-members'; 16 | 17 | import ParagraphDescription from '@site/src/generated/tables/paragraph/description'; 18 | import ParagraphOrderedMembers from '@site/src/generated/tables/paragraph/ordered-members'; 19 | 20 | import ImageDescription from '@site/src/generated/tables/image/description'; 21 | import ImageProps from '@site/src/generated/tables/image/props'; 22 | 23 | import SvgDescription from '@site/src/generated/tables/svg/description'; 24 | import SvgProps from '@site/src/generated/tables/svg/props'; 25 | 26 | import HXMembers from '@site/src/generated/tables/h1/ordered-members'; 27 | 28 | import HorizontalBreakDescription from '@site/src/generated/tables/horizontal_break/description'; 29 | 30 | import CodeBlockDescription from '@site/src/generated/tables/code_block/description'; 31 | import CodeBlockMembers from '@site/src/generated/tables/code_block/ordered-members'; 32 | 33 | 34 | import InlineCode from '@site/src/generated/code_example/ui_inline_main/main'; 35 | import InlineSeparatorsCode from '@site/src/generated/code_example/ui_inline_separator/main'; 36 | import InlineTwoSectionsCode from '@site/src/generated/code_example/ui_inline_two_sections/main'; 37 | import InlineThreeSectionsCode from '@site/src/generated/code_example/ui_inline_three_sections/main'; 38 | import InlineHXCode from '@site/src/generated/code_example/ui_inline_header/main'; 39 | import InlineCodeBlockCode from '@site/src/generated/code_example/ui_inline_code_block/main'; 40 | import InlineParagraphCode from '@site/src/generated/code_example/ui_inline_paragraph/main'; 41 | import InlineImageCode from '@site/src/generated/code_example/ui_inline_image/main'; 42 | import InlineSvgCode from '@site/src/generated/code_example/ui_inline_svg/main'; 43 | import InlineHorizontalBreakCode from '@site/src/generated/code_example/ui_inline_horizontal_break/main'; 44 | 45 | ## Overview 46 | 47 | Inline is a view that is displayed directly under search bar in main window. 48 | Content of view as well as whether the view is displayed at all will depend on the text typed in search bar 49 | 50 | Plugin can declare only one Inline view. 51 | 52 | Although it can be made dynamic with React, static content should be preferred 53 | 54 | 55 | 56 | ### Functionality 57 | - Show content right under search bar in main window based on content of search bar 58 | - While inline view is displayed separate set of actions defined in the view is available 59 | 60 | ### Plugin Manifest 61 | 62 | To use this view, entrypoint with type `"inline-view"` and `main_search_bar` `read` permission are required 63 | 64 | #### Example 65 | ```toml 66 | [[entrypoint]] 67 | id = 'main' 68 | name = 'Main' 69 | path = 'src/main.tsx' 70 | type = 'inline-view' 71 | description = 'Description of a inline view' 72 | 73 | [permissions] 74 | main_search_bar = ["read"] 75 | ``` 76 | 77 | ## API Reference 78 | 79 | 80 | ### Inline 81 | 82 | 83 | #### Example 84 | 85 | 86 | #### Props 87 | 88 | 89 | #### Children components (order-sensitive) 90 | 91 | 92 | 93 | 94 | ### Inline Content 95 | 96 | 97 | #### Example Two Columns 98 | 99 | 100 | #### Example Three Columns 101 | 102 | 103 | #### Children components (order-sensitive) 104 | 105 | 106 | 107 | 108 | ### Inline.Center.Paragraph 109 | 110 | 111 | #### Example 112 | 113 | 114 | #### Children components (order-sensitive) 115 | 116 | 117 | 118 | ### Inline.Center.Image 119 | 120 | 121 | #### Example 122 | 123 | 124 | #### Props 125 | 126 | 127 | 128 | ### Inline.Center.Svg 129 | 130 | 131 | #### Example 132 | 133 | 134 | #### Props 135 | 136 | 137 | 138 | ### Inline.Center.H1-6 139 | Headers 140 | 141 | #### Example 142 | 143 | 144 | #### Children components (order-sensitive) 145 | 146 | 147 | 148 | 149 | ### Inline.Center.HorizontalBreak 150 | 151 | 152 | #### Example 153 | 154 | 155 | 156 | 157 | ### Inline.Center.CodeBlock 158 | 159 | 160 | #### Example 161 | 162 | 163 | #### Children components (order-sensitive) 164 | 165 | 166 | 167 | 168 | 169 | ### Inline.Separator 170 | 171 | 172 | #### Example 173 | 174 | -------------------------------------------------------------------------------- /docs/api-reference/promise-helpers.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Promise Helpers" 3 | sidebar_position: 8 4 | sidebar_label: "Promise Helpers" 5 | --- 6 | 7 | import UsePromiseBasicCode from '@site/src/generated/code_example/ui_promise_helpers/basic'; 8 | import UsePromiseRevalidateCode from '@site/src/generated/code_example/ui_promise_helpers/revalidate'; 9 | import UsePromiseAbortableRevalidateCode from '@site/src/generated/code_example/ui_promise_helpers/abortable-revalidate'; 10 | import UsePromiseExecuteFalseCode from '@site/src/generated/code_example/ui_promise_helpers/execute-false'; 11 | import UsePromiseMutateCode from '@site/src/generated/code_example/ui_promise_helpers/mutate'; 12 | import UsePromiseMutateNoRevalidateCode from '@site/src/generated/code_example/ui_promise_helpers/mutate-no-revalidate'; 13 | import UsePromiseMutateOptimisticCode from '@site/src/generated/code_example/ui_promise_helpers/mutate-optimistic'; 14 | import UsePromiseMutateOptimisticRollbackCode from '@site/src/generated/code_example/ui_promise_helpers/mutate-optimistic-rollback'; 15 | 16 | import UseCachedPromiseBasicCode from '@site/src/generated/code_example/ui_promise_helpers/cached-basic'; 17 | import UseCachedPromiseInitialCode from '@site/src/generated/code_example/ui_promise_helpers/cached-basic-initial-value'; 18 | 19 | import UseFetchBasicCode from '@site/src/generated/code_example/ui_promise_helpers/fetch-basic'; 20 | import UseFetchMapCode from '@site/src/generated/code_example/ui_promise_helpers/fetch-map'; 21 | 22 | ## Overview 23 | 24 | To make operations with promises in views easier, Gauntlet provides set of helper hooks 25 | 26 | ## `usePromise` 27 | 28 | Helper to run promises in a context of React view 29 | 30 | ### Examples 31 | 32 | #### Basic 33 | 34 | 35 | 36 | #### Revalidate 37 | 38 | Usually the promise will be executed only on initial load of the view. It is often desired to manually refresh the state of the hook which can be done by calling `revalidate()` 39 | 40 | 41 | 42 | #### Abortable 43 | 44 | Occasionally, revalidation can be started while the main promise is still in progress, if you want to detect when that happens `abortable` can be provided 45 | 46 | 47 | 48 | #### No execution on load 49 | 50 | If `execute` option is set to `false`, the promise will be executed only on revalidation 51 | 52 | 53 | 54 | #### Mutate 55 | 56 | "Mutation" is an action that is supposed to change the returned value of the main promise. 57 | E.g. if the main promise is the `fetch()` to backend to get list of items, 58 | the "mutation" would be an action that adds or removes items of that list. 59 | 60 | After the mutation is executed, this helper will automatically refresh the state of the hook by calling `revalidate()` 61 | 62 | 63 | 64 | #### Mutate Without Revalidations 65 | 66 | But sometimes it is not desirable to do revalidation after mutation, so it can be disabled 67 | 68 | 69 | 70 | #### Mutate With Optimistic Update 71 | 72 | If the promise is for example the call to backend, it will usually take some time. 73 | And because the update is done from the current UI, it often can be assumed that the update (aka mutation) will be successful (i.e. we are optimistic that it will succeed), 74 | and the UI can be updated right away to get much more responsive experience 75 | 76 | 77 | 78 | #### Mutate With Optimistic Update And Rollback 79 | 80 | When using optimistic update, if the mutation promise was rejected the value will be automatically reverted to what it was before the start of mutation. 81 | This behavior can be disabled by setting `rollbackOnError` option to `false` or, if set to a function, custom behaviour can be executed instead 82 | 83 | 84 | 85 | [//]: # (### Api Reference) 86 | 87 | [//]: # (TODO type) 88 | 89 | ## `useCachedPromise` 90 | 91 | Helper to run promises with caching done automatically 92 | 93 | The main difference from `usePromise` is that the state stored in session storage. 94 | So it is reused from previous time this entrypoint view was opened, but not since before the plugin is restarted 95 | 96 | Follows "stale-while-revalidate" caching strategy 97 | 98 | All options from `usePromise` are also available in this hook 99 | 100 | ### Examples 101 | 102 | #### Basic 103 | 104 | 105 | 106 | #### Initial Value 107 | 108 | If the view is opened for the first time, the cache state will be empty. It is possible to assign default initial value of the cache 109 | 110 | 111 | 112 | [//]: # (### Api Reference) 113 | 114 | [//]: # (TODO type) 115 | 116 | ## `useFetch` 117 | 118 | Helper to run `fetch()` with caching done automatically. 119 | 120 | Uses `useCachedPromise` internally, so all parameters from it are exposed in this hook as well 121 | 122 | The state stored in session storage 123 | 124 | Follows "stale-while-revalidate" caching strategy 125 | 126 | If revalidation is done while `fetch()` is still in progress it will be canceled automatically 127 | 128 | ### Examples 129 | 130 | #### Basic 131 | 132 | 133 | 134 | #### Map the returned value 135 | 136 | 137 | 138 | [//]: # (### Api Reference) 139 | 140 | [//]: # (TODO type) 141 | -------------------------------------------------------------------------------- /src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | /* node_modules/infima/dist/css/default/default.css */ 9 | :root { 10 | --ifm-code-font-size: 95%; 11 | --ifm-font-size-base: 95%; 12 | 13 | --ifm-background-color: rgb(250, 250, 250); 14 | 15 | --ifm-color-primary: #2e8555; 16 | --ifm-color-primary-dark: #29784c; 17 | --ifm-color-primary-darker: #277148; 18 | --ifm-color-primary-darkest: #205d3b; 19 | --ifm-color-primary-light: #33925d; 20 | --ifm-color-primary-lighter: #359962; 21 | --ifm-color-primary-lightest: #3cad6e; 22 | --ifm-color-primary-contrast-background: rgb(235, 242, 252); 23 | --ifm-color-primary-contrast-foreground: rgb(16, 36, 69); 24 | 25 | --ifm-color-secondary: #ebedf0; 26 | --ifm-color-secondary-dark: rgb(212, 213, 216); 27 | --ifm-color-secondary-darker: rgb(200, 201, 204); 28 | --ifm-color-secondary-darkest: rgb(164, 166, 168); 29 | --ifm-color-secondary-light: rgb(238, 240, 242); 30 | --ifm-color-secondary-lighter: rgb(241, 242, 245); 31 | --ifm-color-secondary-lightest: rgb(245, 246, 248); 32 | --ifm-color-secondary-contrast-background: rgb(253, 253, 254); 33 | --ifm-color-secondary-contrast-foreground: rgb(71, 71, 72); 34 | 35 | --ifm-color-success: #00a400; 36 | --ifm-color-success-dark: rgb(0, 148, 0); 37 | --ifm-color-success-darker: rgb(0, 139, 0); 38 | --ifm-color-success-darkest: rgb(0, 115, 0); 39 | --ifm-color-success-light: rgb(38, 178, 38); 40 | --ifm-color-success-lighter: rgb(77, 191, 77); 41 | --ifm-color-success-lightest: rgb(128, 210, 128); 42 | --ifm-color-success-contrast-background: rgb(230, 246, 230); 43 | --ifm-color-success-contrast-foreground: rgb(0, 49, 0); 44 | 45 | --ifm-color-info: #54c7ec; 46 | --ifm-color-info-dark: rgb(76, 179, 212); 47 | --ifm-color-info-darker: rgb(71, 169, 201); 48 | --ifm-color-info-darkest: rgb(59, 139, 165); 49 | --ifm-color-info-light: rgb(110, 207, 239); 50 | --ifm-color-info-lighter: rgb(135, 216, 242); 51 | --ifm-color-info-lightest: rgb(170, 227, 246); 52 | --ifm-color-info-contrast-background: rgb(238, 249, 253); 53 | --ifm-color-info-contrast-foreground: rgb(25, 60, 71); 54 | 55 | --ifm-color-warning: #ffba00; 56 | --ifm-color-warning-dark: rgb(230, 167, 0); 57 | --ifm-color-warning-darker: rgb(217, 158, 0); 58 | --ifm-color-warning-darkest: rgb(179, 130, 0); 59 | --ifm-color-warning-light: rgb(255, 196, 38); 60 | --ifm-color-warning-lighter: rgb(255, 207, 77); 61 | --ifm-color-warning-lightest: rgb(255, 221, 128); 62 | --ifm-color-warning-contrast-background: rgb(255, 248, 230); 63 | --ifm-color-warning-contrast-foreground: rgb(77, 56, 0); 64 | 65 | --ifm-color-danger: #fa383e; 66 | --ifm-color-danger-dark: rgb(225, 50, 56); 67 | --ifm-color-danger-darker: rgb(213, 48, 53); 68 | --ifm-color-danger-darkest: rgb(175, 39, 43); 69 | --ifm-color-danger-light: rgb(251, 86, 91); 70 | --ifm-color-danger-lighter: rgb(251, 116, 120); 71 | --ifm-color-danger-lightest: rgb(253, 156, 159); 72 | --ifm-color-danger-contrast-background: rgb(255, 235, 236); 73 | --ifm-color-danger-contrast-foreground: rgb(75, 17, 19); 74 | 75 | --ifm-color-content-secondary: #525860; 76 | 77 | --ifm-code-background: rgb(246, 247, 248); 78 | /*--ifm-code-background: rgb(250, 250, 250);*/ 79 | 80 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 81 | } 82 | 83 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 84 | html[data-theme='dark'] { 85 | --ifm-background-color: oklch(24.353% 0 0); 86 | --ifm-background-surface-color: oklch(20.944% 0 0); 87 | 88 | --ifm-color-primary-darkest: #a3804e; 89 | --ifm-color-primary-darker: #bb9359; 90 | --ifm-color-primary-dark: #d2a564; 91 | --ifm-color-primary: rgb(255, 197, 113); 92 | --ifm-color-primary-light: #eab870; 93 | --ifm-color-primary-lighter: #ecbf7e; 94 | --ifm-color-primary-lightest: #f0cd9a; 95 | 96 | 97 | --ifm-hover-overlay: rgba(255, 255, 255, 0.05); 98 | 99 | --ifm-color-content: #e3e3e3; 100 | --ifm-color-content-secondary: rgba(255, 255, 255, 1); 101 | 102 | --ifm-code-background: rgba(255, 255, 255, 0.1); 103 | 104 | --ifm-scrollbar-track-background-color: #444444; 105 | --ifm-scrollbar-thumb-background-color: #686868; 106 | --ifm-scrollbar-thumb-hover-background-color: #7a7a7a; 107 | 108 | --ifm-table-stripe-background: rgba(255, 255, 255, 0.07); 109 | 110 | --ifm-color-primary-contrast-background: rgb(16, 36, 69); 111 | --ifm-color-primary-contrast-foreground: rgb(235, 242, 252); 112 | --ifm-color-secondary-contrast-background: rgb(71, 71, 72); 113 | --ifm-color-secondary-contrast-foreground: rgb(253, 253, 254); 114 | --ifm-color-success-contrast-background: rgb(0, 49, 0); 115 | --ifm-color-success-contrast-foreground: rgb(230, 246, 230); 116 | --ifm-color-info-contrast-background: rgb(25, 60, 71); 117 | --ifm-color-info-contrast-foreground: rgb(238, 249, 253); 118 | --ifm-color-warning-contrast-background: rgba(141, 103, 46, 0.79); 119 | --ifm-color-warning-contrast-foreground: rgb(255, 248, 230); 120 | --ifm-color-danger-contrast-background: rgb(75, 17, 19); 121 | --ifm-color-danger-contrast-foreground: rgb(255, 235, 236); 122 | 123 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 124 | } 125 | 126 | .markdown { 127 | --ifm-h1-vertical-rhythm-top: 4; 128 | --ifm-h2-vertical-rhythm-top: 3.5; 129 | --ifm-h3-vertical-rhythm-top: 3; 130 | --ifm-heading-vertical-rhythm-top: 2.25; 131 | } 132 | 133 | .footer--dark { 134 | --ifm-footer-background-color: oklch(22.648% 0 0); 135 | } 136 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/view/grid.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Grid" 3 | sidebar_position: 3 4 | sidebar_label: "Grid" 5 | --- 6 | import UiScreenshot from '@site/src/components/UiScreenshot'; 7 | 8 | import GridDescription from '@site/src/generated/tables/grid/description'; 9 | import GridCode from '@site/src/generated/code_example/ui_grid/main'; 10 | import GridMoreColumnsCode from '@site/src/generated/code_example/ui_grid/more-columns'; 11 | import GridFocusCode from '@site/src/generated/code_example/ui_grid/focus'; 12 | import GridProps from '@site/src/generated/tables/grid/props'; 13 | import GridOrderedMembers from '@site/src/generated/tables/grid/ordered-members'; 14 | import GridPerTypeMembers from '@site/src/generated/tables/grid/per-type-members'; 15 | 16 | import GridItemDescription from '@site/src/generated/tables/grid_item/description'; 17 | import GridItemProps from '@site/src/generated/tables/grid_item/props'; 18 | 19 | import GridSectionDescription from '@site/src/generated/tables/grid_section/description'; 20 | import GridSectionCode from '@site/src/generated/code_example/ui_grid/section'; 21 | import GridSectionProps from '@site/src/generated/tables/grid_section/props'; 22 | import GridSectionOrderedMembers from '@site/src/generated/tables/grid_section/ordered-members'; 23 | 24 | import SearchBarDescription from '@site/src/generated/tables/search_bar/description'; 25 | import SearchBarCode from '@site/src/generated/code_example/ui_grid/search-bar'; 26 | import SearchBarSetSearchText from '@site/src/generated/code_example/ui_grid/search-bar-set-search-text'; 27 | import SearchBarProps from '@site/src/generated/tables/search_bar/props'; 28 | 29 | import EmptyViewDescription from '@site/src/generated/tables/empty_view/description'; 30 | import EmptyViewCode from '@site/src/generated/code_example/ui_grid/empty-view'; 31 | import EmptyViewProps from '@site/src/generated/tables/empty_view/props'; 32 | 33 | import ContentDescription from '@site/src/generated/tables/content/description'; 34 | import ContentOrderedMembers from '@site/src/generated/tables/content/ordered-members'; 35 | 36 | import ParagraphDescription from '@site/src/generated/tables/paragraph/description'; 37 | import ParagraphCode from '@site/src/generated/code_example/ui_grid/content-paragraph'; 38 | import ParagraphOrderedMembers from '@site/src/generated/tables/paragraph/ordered-members'; 39 | 40 | import ImageDescription from '@site/src/generated/tables/image/description'; 41 | import ImageCode from '@site/src/generated/code_example/ui_grid/content-image'; 42 | import ImageProps from '@site/src/generated/tables/image/props'; 43 | 44 | import SvgDescription from '@site/src/generated/tables/svg/description'; 45 | import SvgCode from '@site/src/generated/code_example/ui_grid/content-svg'; 46 | import SvgProps from '@site/src/generated/tables/svg/props'; 47 | 48 | import HXCode from '@site/src/generated/code_example/ui_grid/content-headers'; 49 | import HXMembers from '@site/src/generated/tables/h1/ordered-members'; 50 | 51 | import HorizontalBreakDescription from '@site/src/generated/tables/horizontal_break/description'; 52 | import HorizontalBreakCode from '@site/src/generated/code_example/ui_grid/content-horizontal-break'; 53 | 54 | import CodeBlockDescription from '@site/src/generated/tables/code_block/description'; 55 | import CodeBlockCode from '@site/src/generated/code_example/ui_grid/content-code-block'; 56 | import CodeBlockMembers from '@site/src/generated/tables/code_block/ordered-members'; 57 | 58 | 59 | ## Overview 60 | 61 | Grid is a view that is very similar to List view with the main difference that items are arranged into a grid allowing for items to be an image 62 | 63 | 64 | 65 | ### Functionality 66 | - Items can have title, subtitle and icon accessory 67 | - Items can be grouped in sections with titles and subtitles 68 | - Can optionally have a search bar 69 | - If no items exist, text with image can be shown in the middle 70 | - As with all other views can be made highly dynamic with help of React 71 | 72 | ### Plugin Manifest 73 | 74 | To use this view, entrypoint with type `"view"` is required 75 | 76 | #### Example 77 | ```toml 78 | [[entrypoint]] 79 | id = 'main' 80 | name = 'Main' 81 | path = 'src/main.tsx' 82 | type = 'view' 83 | description = 'Description of a Grid view' 84 | ``` 85 | 86 | ## API Reference 87 | 88 | ### Grid 89 | 90 | 91 | #### Example 92 | 93 | 94 | #### More Columns Example 95 | 96 | 97 | 98 | #### Focus Change Example 99 | 100 | 101 | 102 | #### Props 103 | 104 | 105 | #### Children components (order-sensitive) 106 | 107 | 108 | #### Children components (non-order-sensitive) 109 | 110 | 111 | 112 | 113 | ### Grid.Section 114 | 115 | 116 | #### Example 117 | 118 | 119 | #### Props 120 | 121 | 122 | #### Children components (order-sensitive) 123 | 124 | 125 | 126 | 127 | ### Grid.SearchBar 128 | 129 | 130 | #### Example 131 | 132 | 133 | #### Programmatic Search Bar Update Example 134 | 135 | 136 | #### Props 137 | 138 | 139 | 140 | 141 | ### Grid.EmptyView 142 | 143 | 144 | #### Example 145 | 146 | 147 | #### Props 148 | 149 | 150 | 151 | 152 | ### Grid.Item 153 | 154 | 155 | #### Props 156 | 157 | 158 | 159 | 160 | ### Grid.Item.Content 161 | 162 | 163 | #### Children components (order-sensitive) 164 | 165 | 166 | 167 | 168 | ### Grid.Item.Content.Paragraph 169 | 170 | 171 | #### Example 172 | 173 | 174 | #### Children components (order-sensitive) 175 | 176 | 177 | 178 | 179 | ### Grid.Item.Content.Image 180 | 181 | 182 | #### Example 183 | 184 | 185 | #### Props 186 | 187 | 188 | 189 | ### Grid.Item.Content.Svg 190 | 191 | 192 | #### Example 193 | 194 | 195 | #### Props 196 | 197 | 198 | 199 | ### Grid.Item.Content.H1-6 200 | Headers 201 | 202 | #### Example 203 | 204 | 205 | #### Children components (order-sensitive) 206 | 207 | 208 | 209 | 210 | ### Grid.Item.Content.HorizontalBreak 211 | 212 | 213 | #### Example 214 | 215 | 216 | 217 | 218 | ### Grid.Item.Content.CodeBlock 219 | 220 | 221 | #### Example 222 | 223 | 224 | #### Children components (order-sensitive) 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/view/details.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Detail" 3 | sidebar_position: 1 4 | sidebar_label: "Detail" 5 | --- 6 | import UiScreenshot from '@site/src/components/UiScreenshot'; 7 | 8 | import DetailDescription from '@site/src/generated/tables/detail/description'; 9 | import DetailCode from '@site/src/generated/code_example/ui_detail/main'; 10 | import DetailProps from '@site/src/generated/tables/detail/props'; 11 | import DetailPerTypeMembers from '@site/src/generated/tables/detail/per-type-members'; 12 | 13 | import MetadataDescription from '@site/src/generated/tables/metadata/description'; 14 | import MetadataCode from '@site/src/generated/code_example/ui_detail/metadata'; 15 | import MetadataOrderedMembers from '@site/src/generated/tables/metadata/ordered-members'; 16 | 17 | import MetadataTagListDescription from '@site/src/generated/tables/metadata_tag_list/description'; 18 | import MetadataTagListCode from '@site/src/generated/code_example/ui_detail/metadata-tag-list'; 19 | import MetadataTagListProps from '@site/src/generated/tables/metadata_tag_list/props'; 20 | import MetadataTagListOrderedMembers from '@site/src/generated/tables/metadata_tag_list/ordered-members'; 21 | 22 | import MetadataTagListItemDescription from '@site/src/generated/tables/metadata_tag_item/description'; 23 | import MetadataTagListItemProps from '@site/src/generated/tables/metadata_tag_item/props'; 24 | import MetadataTagListItemOrderedMembers from '@site/src/generated/tables/metadata_tag_item/ordered-members'; 25 | 26 | import MetadataLinkDescription from '@site/src/generated/tables/metadata_link/description'; 27 | import MetadataLinkCode from '@site/src/generated/code_example/ui_detail/metadata-link'; 28 | import MetadataLinkProps from '@site/src/generated/tables/metadata_link/props'; 29 | import MetadataLinkOrderedMembers from '@site/src/generated/tables/metadata_link/ordered-members'; 30 | 31 | import MetadataValueDescription from '@site/src/generated/tables/metadata_value/description'; 32 | import MetadataValueCode from '@site/src/generated/code_example/ui_detail/metadata-value' 33 | import MetadataValueProps from '@site/src/generated/tables/metadata_value/props'; 34 | import MetadataValueOrderedMembers from '@site/src/generated/tables/metadata_value/ordered-members'; 35 | 36 | import MetadataIconDescription from '@site/src/generated/tables/metadata_icon/description'; 37 | import MetadataIconCode from '@site/src/generated/code_example/ui_detail/metadata-icon'; 38 | import MetadataIconProps from '@site/src/generated/tables/metadata_icon/props'; 39 | 40 | import MetadataSeparatorDescription from '@site/src/generated/tables/metadata_separator/description'; 41 | import MetadataSeparatorCode from '@site/src/generated/code_example/ui_detail/metadata-separator'; 42 | 43 | import ContentDescription from '@site/src/generated/tables/content/description'; 44 | import ContentCode from '@site/src/generated/code_example/ui_detail/content'; 45 | import ContentOrderedMembers from '@site/src/generated/tables/content/ordered-members'; 46 | 47 | import ParagraphDescription from '@site/src/generated/tables/paragraph/description'; 48 | import ParagraphCode from '@site/src/generated/code_example/ui_detail/content-paragraph'; 49 | import ParagraphOrderedMembers from '@site/src/generated/tables/paragraph/ordered-members'; 50 | 51 | import ImageDescription from '@site/src/generated/tables/image/description'; 52 | import ImageCode from '@site/src/generated/code_example/ui_detail/content-image'; 53 | import ImageProps from '@site/src/generated/tables/image/props'; 54 | 55 | import SvgDescription from '@site/src/generated/tables/svg/description'; 56 | import SvgCode from '@site/src/generated/code_example/ui_detail/content-svg'; 57 | import SvgProps from '@site/src/generated/tables/svg/props'; 58 | 59 | import HXCode from '@site/src/generated/code_example/ui_detail/content-header'; 60 | import HXMembers from '@site/src/generated/tables/h1/ordered-members'; 61 | 62 | import HorizontalBreakDescription from '@site/src/generated/tables/horizontal_break/description'; 63 | import HorizontalBreakCode from '@site/src/generated/code_example/ui_detail/content-horizontal-break'; 64 | 65 | import CodeBlockDescription from '@site/src/generated/tables/code_block/description'; 66 | import CodeBlockCode from '@site/src/generated/code_example/ui_detail/content-code-block'; 67 | import CodeBlockMembers from '@site/src/generated/tables/code_block/ordered-members'; 68 | 69 | 70 | ## Overview 71 | 72 | Detail is a view which can display everything that could go into an article: text, images, code block etc. 73 | It can appear as a standalone view or as a part of List view on the right-hand side 74 | 75 | 76 | 77 | ### Functionality 78 | - Can have some structured data on the right-hand side 79 | - As with all other views can be made highly dynamic with help of React 80 | 81 | ### Plugin Manifest 82 | 83 | To use this view, entrypoint with type `"view"` is required 84 | 85 | #### Example 86 | ```toml 87 | [[entrypoint]] 88 | id = 'main' 89 | name = 'Main' 90 | path = 'src/main.tsx' 91 | type = 'view' 92 | description = 'Description of a Detail view' 93 | ``` 94 | 95 | ## API Reference 96 | 97 | ### Detail 98 | 99 | 100 | #### Example 101 | 102 | 103 | #### Props 104 | 105 | 106 | #### Children components (non-order-sensitive) 107 | 108 | 109 | 110 | 111 | ### Detail.Metadata 112 | 113 | 114 | #### Example 115 | 116 | 117 | #### Children components (order-sensitive) 118 | 119 | 120 | 121 | 122 | ### Detail.Metadata.TagList 123 | 124 | 125 | #### Example 126 | 127 | 128 | #### Props 129 | 130 | 131 | #### Children components (order-sensitive) 132 | 133 | 134 | 135 | 136 | ### Detail.Metadata.TagList.Item 137 | 138 | 139 | #### Props 140 | 141 | 142 | #### Children components (order-sensitive) 143 | 144 | 145 | 146 | 147 | ### Detail.Metadata.Link 148 | 149 | 150 | #### Example 151 | 152 | 153 | #### Props 154 | 155 | 156 | #### Children components (order-sensitive) 157 | 158 | 159 | 160 | 161 | ### Detail.Metadata.Value 162 | 163 | 164 | #### Example 165 | 166 | 167 | #### Props 168 | 169 | 170 | #### Children components (order-sensitive) 171 | 172 | 173 | 174 | 175 | ### Detail.Metadata.Icon 176 | 177 | 178 | #### Example 179 | 180 | 181 | #### Props 182 | 183 | 184 | 185 | 186 | ### Detail.Metadata.Separator 187 | 188 | 189 | #### Example 190 | 191 | 192 | 193 | 194 | ### Detail.Content 195 | 196 | 197 | #### Example 198 | 199 | 200 | #### Children components (order-sensitive) 201 | 202 | 203 | 204 | 205 | ### Detail.Content.Paragraph 206 | 207 | 208 | #### Example 209 | 210 | 211 | #### Children components (order-sensitive) 212 | 213 | 214 | 215 | ### Detail.Content.Image 216 | 217 | 218 | #### Example 219 | 220 | 221 | #### Props 222 | 223 | 224 | 225 | ### Detail.Content.Svg 226 | 227 | 228 | #### Example 229 | 230 | 231 | #### Props 232 | 233 | 234 | 235 | ### Detail.Content.H1-6 236 | Headers 237 | 238 | #### Example 239 | 240 | 241 | #### Children components (order-sensitive) 242 | 243 | 244 | 245 | 246 | ### Detail.Content.HorizontalBreak 247 | 248 | 249 | #### Example 250 | 251 | 252 | 253 | 254 | ### Detail.Content.CodeBlock 255 | 256 | 257 | #### Example 258 | 259 | 260 | #### Children components (order-sensitive) 261 | 262 | 263 | 264 | 265 | 266 | -------------------------------------------------------------------------------- /docs/api-reference/entrypoint-types/view/list.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: "List" 3 | sidebar_position: 4 4 | sidebar_label: "List" 5 | --- 6 | import UiScreenshot from '@site/src/components/UiScreenshot'; 7 | 8 | import ListDescription from '@site/src/generated/tables/list/description'; 9 | import ListCode from '@site/src/generated/code_example/ui_list/main'; 10 | import ListFocusCode from '@site/src/generated/code_example/ui_list/focus'; 11 | import ListProps from '@site/src/generated/tables/list/props'; 12 | import ListOrderedMembers from '@site/src/generated/tables/list/ordered-members'; 13 | import ListPerTypeMembers from '@site/src/generated/tables/list/per-type-members'; 14 | 15 | import ListItemDescription from '@site/src/generated/tables/list_item/description'; 16 | import ListItemCode from '@site/src/generated/code_example/ui_list/item'; 17 | import ListItemProps from '@site/src/generated/tables/list_item/props'; 18 | 19 | import ListSectionDescription from '@site/src/generated/tables/list_section/description'; 20 | import ListSectionCode from '@site/src/generated/code_example/ui_list/section'; 21 | import ListSectionProps from '@site/src/generated/tables/list_section/props'; 22 | import ListSectionOrderedMembers from '@site/src/generated/tables/list_section/ordered-members'; 23 | 24 | import SearchBarDescription from '@site/src/generated/tables/search_bar/description'; 25 | import SearchBarCode from '@site/src/generated/code_example/ui_list/search-bar'; 26 | import SearchBarSetSearchText from '@site/src/generated/code_example/ui_list/search-bar-set-search-text'; 27 | import SearchBarProps from '@site/src/generated/tables/search_bar/props'; 28 | 29 | import EmptyViewDescription from '@site/src/generated/tables/empty_view/description'; 30 | import EmptyViewCode from '@site/src/generated/code_example/ui_list/empty-view'; 31 | import EmptyViewProps from '@site/src/generated/tables/empty_view/props'; 32 | 33 | import DetailDescription from '@site/src/generated/tables/detail/description'; 34 | import DetailCode from '@site/src/generated/code_example/ui_list/detail'; 35 | import DetailProps from '@site/src/generated/tables/detail/props'; 36 | import DetailPerTypeMembers from '@site/src/generated/tables/detail/per-type-members'; 37 | 38 | import MetadataDescription from '@site/src/generated/tables/metadata/description'; 39 | import MetadataCode from '@site/src/generated/code_example/ui_list/metadata'; 40 | import MetadataOrderedMembers from '@site/src/generated/tables/metadata/ordered-members'; 41 | 42 | import MetadataTagListDescription from '@site/src/generated/tables/metadata_tag_list/description'; 43 | import MetadataTagListCode from '@site/src/generated/code_example/ui_list/metadata-tag-list'; 44 | import MetadataTagListProps from '@site/src/generated/tables/metadata_tag_list/props'; 45 | import MetadataTagListOrderedMembers from '@site/src/generated/tables/metadata_tag_list/ordered-members'; 46 | 47 | import MetadataTagListItemDescription from '@site/src/generated/tables/metadata_tag_item/description'; 48 | import MetadataTagListItemProps from '@site/src/generated/tables/metadata_tag_item/props'; 49 | import MetadataTagListItemOrderedMembers from '@site/src/generated/tables/metadata_tag_item/ordered-members'; 50 | 51 | import MetadataLinkDescription from '@site/src/generated/tables/metadata_link/description'; 52 | import MetadataLinkCode from '@site/src/generated/code_example/ui_list/metadata-link'; 53 | import MetadataLinkProps from '@site/src/generated/tables/metadata_link/props'; 54 | import MetadataLinkOrderedMembers from '@site/src/generated/tables/metadata_link/ordered-members'; 55 | 56 | import MetadataValueDescription from '@site/src/generated/tables/metadata_value/description'; 57 | import MetadataValueCode from '@site/src/generated/code_example/ui_list/metadata-value'; 58 | import MetadataValueProps from '@site/src/generated/tables/metadata_value/props'; 59 | import MetadataValueOrderedMembers from '@site/src/generated/tables/metadata_value/ordered-members'; 60 | 61 | import MetadataIconDescription from '@site/src/generated/tables/metadata_icon/description'; 62 | import MetadataIconCode from '@site/src/generated/code_example/ui_list/metadata-icon'; 63 | import MetadataIconProps from '@site/src/generated/tables/metadata_icon/props'; 64 | 65 | import MetadataSeparatorDescription from '@site/src/generated/tables/metadata_separator/description'; 66 | import MetadataSeparatorCode from '@site/src/generated/code_example/ui_list/metadata-separator'; 67 | 68 | import ContentDescription from '@site/src/generated/tables/content/description'; 69 | import ContentCode from '@site/src/generated/code_example/ui_list/content'; 70 | import ContentOrderedMembers from '@site/src/generated/tables/content/ordered-members'; 71 | 72 | import ParagraphDescription from '@site/src/generated/tables/paragraph/description'; 73 | import ParagraphCode from '@site/src/generated/code_example/ui_list/content-paragraph'; 74 | import ParagraphOrderedMembers from '@site/src/generated/tables/paragraph/ordered-members'; 75 | 76 | import ImageDescription from '@site/src/generated/tables/image/description'; 77 | import ImageCode from '@site/src/generated/code_example/ui_list/content-image'; 78 | import ImageProps from '@site/src/generated/tables/image/props'; 79 | 80 | import SvgDescription from '@site/src/generated/tables/svg/description'; 81 | import SvgCode from '@site/src/generated/code_example/ui_list/content-svg'; 82 | import SvgProps from '@site/src/generated/tables/svg/props'; 83 | 84 | import HXCode from '@site/src/generated/code_example/ui_list/content-headers'; 85 | import HXMembers from '@site/src/generated/tables/h1/ordered-members'; 86 | 87 | import HorizontalBreakDescription from '@site/src/generated/tables/horizontal_break/description'; 88 | import HorizontalBreakCode from '@site/src/generated/code_example/ui_list/content-horizontal-break'; 89 | 90 | import CodeBlockDescription from '@site/src/generated/tables/code_block/description'; 91 | import CodeBlockCode from '@site/src/generated/code_example/ui_list/content-code-block'; 92 | import CodeBlockMembers from '@site/src/generated/tables/code_block/ordered-members'; 93 | 94 | 95 | ## Overview 96 | 97 | List is a view that displays a list (duh...) of items with some bells and whistles 98 | 99 | 100 | 101 | ### Functionality 102 | - Items can have icons on left, title, subtitle and icons with optional text on right 103 | - Items can be grouped in sections with titles and subtitles 104 | - Can optionally have a search bar 105 | - Can have a Detail side view 106 | - If no items exist, text with image can be shown in the middle 107 | - As with all other views can be made highly dynamic with help of React 108 | 109 | ### Plugin Manifest 110 | 111 | To use this view, entrypoint with type `"view"` is required 112 | 113 | #### Example 114 | ```toml 115 | [[entrypoint]] 116 | id = 'main' 117 | name = 'Main' 118 | path = 'src/main.tsx' 119 | type = 'view' 120 | description = 'Description of a List view' 121 | ``` 122 | 123 | ## API Reference 124 | 125 | ### List 126 | 127 | 128 | #### Example 129 | 130 | 131 | #### Props 132 | 133 | 134 | #### Children components (order-sensitive) 135 | 136 | 137 | #### Children components (non-order-sensitive) 138 | 139 | 140 | 141 | 142 | ### List.Item 143 | 144 | 145 | #### Example 146 | 147 | 148 | #### Focus Change Example 149 | 150 | 151 | 152 | #### Props 153 | 154 | 155 | 156 | 157 | ### List.Section 158 | 159 | 160 | #### Example 161 | 162 | 163 | #### Props 164 | 165 | 166 | #### Children components (order-sensitive) 167 | 168 | 169 | 170 | 171 | ### List.SearchBar 172 | 173 | 174 | #### Example 175 | 176 | 177 | #### Programmatic Search Bar Update Example 178 | 179 | 180 | #### Props 181 | 182 | 183 | 184 | 185 | ### List.EmptyView 186 | 187 | 188 | #### Example 189 | 190 | 191 | #### Props 192 | 193 | 194 | 195 | 196 | ### List.Detail 197 | 198 | 199 | #### Example 200 | 201 | 202 | #### Props 203 | 204 | 205 | #### Children components (non-order-sensitive) 206 | 207 | 208 | 209 | 210 | ### List.Detail.Metadata 211 | 212 | 213 | #### Example 214 | 215 | 216 | #### Children components (order-sensitive) 217 | 218 | 219 | 220 | 221 | ### List.Detail.Metadata.TagList 222 | 223 | 224 | #### Example 225 | 226 | 227 | #### Props 228 | 229 | 230 | #### Children components (order-sensitive) 231 | 232 | 233 | 234 | 235 | ### List.Detail.Metadata.TagList.Item 236 | 237 | 238 | #### Props 239 | 240 | 241 | #### Children components (order-sensitive) 242 | 243 | 244 | 245 | 246 | ### List.Detail.Metadata.Link 247 | 248 | 249 | #### Example 250 | 251 | 252 | #### Props 253 | 254 | 255 | #### Children components (order-sensitive) 256 | 257 | 258 | 259 | 260 | ### List.Detail.Metadata.Value 261 | 262 | 263 | #### Example 264 | 265 | 266 | #### Props 267 | 268 | 269 | #### Children components (order-sensitive) 270 | 271 | 272 | 273 | 274 | ### List.Detail.Metadata.Icon 275 | 276 | 277 | #### Example 278 | 279 | 280 | #### Props 281 | 282 | 283 | 284 | 285 | ### List.Detail.Metadata.Separator 286 | 287 | 288 | #### Example 289 | 290 | 291 | 292 | 293 | ### List.Detail.Content 294 | 295 | 296 | #### Example 297 | 298 | 299 | #### Children components (order-sensitive) 300 | 301 | 302 | 303 | 304 | ### List.Detail.Content.Paragraph 305 | 306 | 307 | #### Example 308 | 309 | 310 | #### Children components (order-sensitive) 311 | 312 | 313 | 314 | ### List.Detail.Content.Image 315 | 316 | 317 | #### Example 318 | 319 | 320 | #### Props 321 | 322 | 323 | 324 | ### List.Detail.Content.Svg 325 | 326 | 327 | #### Example 328 | 329 | 330 | #### Props 331 | 332 | 333 | 334 | ### List.Detail.Content.H1-6 335 | Headers 336 | 337 | #### Example 338 | 339 | 340 | #### Children components (order-sensitive) 341 | 342 | 343 | 344 | 345 | ### List.Detail.Content.HorizontalBreak 346 | 347 | 348 | #### Example 349 | 350 | 351 | 352 | 353 | ### List.Detail.Content.CodeBlock 354 | 355 | 356 | #### Example 357 | 358 | 359 | #### Children components (order-sensitive) 360 | 361 | 362 | -------------------------------------------------------------------------------- /docs/plugin-development/manifest.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Plugin Manifest" 3 | sidebar_position: 3 4 | sidebar_label: "Manifest" 5 | --- 6 | 7 | ## Overview 8 | 9 | Plugin Manifest uses [TOML](https://toml.io) file format 10 | 11 | ## Main 12 | 13 | ### `$schema` 14 | 15 | Some editors use `$schema` field to validate the content of the file. It is not used by Gauntlet. 16 | The schema can be found at `https://raw.githubusercontent.com/project-gauntlet/gauntlet/refs/heads/main/docs/schema/plugin_manifest.schema.json` 17 | 18 | | Type | Required | 19 | |----------|----------| 20 | | `string` | no | 21 | 22 | ### `gauntlet.name` 23 | 24 | Name of the plugin. Displayed in main search view on each item and in settings 25 | 26 | | Type | Required | 27 | |----------|----------| 28 | | `string` | yes | 29 | 30 | ### `gauntlet.description` 31 | 32 | Description of the plugin. Displayed in settings 33 | 34 | | Type | Required | 35 | |----------|----------| 36 | | `string` | yes | 37 | 38 | ### `gauntlet.authors.[*].name` 39 | 40 | Name of one of the author of the plugin 41 | 42 | | Type | Required | 43 | |----------|----------| 44 | | `string` | no | 45 | 46 | ### `gauntlet.authors.[*].uris` 47 | 48 | List of URIs that identify the author. Can be a link to social media page or an email. 49 | 50 | E.g. `https://github.com/Exidex` or `mailto:exidex@example.com` 51 | 52 | | Type | Required | 53 | |------------------|----------| 54 | | list of `string` | no | 55 | 56 | ## Plugin Preferences 57 | 58 | ### `preferences.[*].id` 59 | 60 | ID of the plugin preference. This will be used as name of the field in TypeScript. 61 | Can only contain: numbers, uppercase and lowercase letters 62 | 63 | | Type | Required | 64 | |----------|----------| 65 | | `string` | yes | 66 | 67 | ### `preferences.[*].name` 68 | 69 | Name of the plugin preference. Displayed in settings 70 | 71 | | Type | Required | 72 | |----------|----------| 73 | | `string` | yes | 74 | 75 | ### `preferences.[*].description` 76 | 77 | Description of the plugin preference. Displayed in settings 78 | 79 | | Type | Required | 80 | |----------|----------| 81 | | `string` | yes | 82 | 83 | ### `preferences.[*].type` 84 | 85 | Type of the plugin preference. 86 | Allowed values: `"number"`, `"string"`, `"enum"`, `"bool"`, `"list_of_strings"`, `"list_of_numbers"` and `"list_of_enums"` 87 | 88 | | Type | Required | 89 | |--------|----------| 90 | | `enum` | yes | 91 | 92 | ### `preferences.[*].default` 93 | 94 | Provides default value for the plugin preference. 95 | If not specified, preference will be considered required and user will be prompted to enter the value 96 | 97 | If preference type is `"enum"` or `"list_of_enums"`, `enum_values` property has to be provided and default value has to be one of values defined in `enum_values` 98 | 99 | Currently, not supported for list types, for which default value will be an empty list 100 | 101 | | Type | Required | 102 | |------------------------------------------------------------------------------------|----------| 103 | | `number`, `string`, `bool` or list of one of those depending on type of preference | no | 104 | 105 | ### `preferences.[*].enum_values.[*].label` 106 | 107 | Label of the enum value. Displayed in settings 108 | 109 | | Type | Required | 110 | |----------|----------| 111 | | `string` | yes | 112 | 113 | ### `preferences.[*].enum_values.[*].value` 114 | 115 | Value of the enum value. One of these values will be used as a value of the field in TypeScript and in `default` property 116 | 117 | | Type | Required | 118 | |----------|----------| 119 | | `string` | yes | 120 | 121 | 122 | ## Entrypoints 123 | 124 | ### `entrypoint.[*].id` 125 | 126 | Identifier of the entrypoint. Can only contain: numbers, lowercase letters and dash 127 | 128 | | Type | Required | 129 | |----------|----------| 130 | | `string` | yes | 131 | 132 | ### `entrypoint.[*].name` 133 | 134 | Name of the entrypoint. Displayed in main search view on each item, in settings and in bottom left of each plugin created view 135 | 136 | | Type | Required | 137 | |----------|----------| 138 | | `string` | yes | 139 | 140 | ### `entrypoint.[*].description` 141 | 142 | Description of the entrypoint. Displayed in settings 143 | 144 | | Type | Required | 145 | |----------|----------| 146 | | `string` | yes | 147 | 148 | ### `entrypoint.[*].path` 149 | 150 | Path to TypeScript source file (`.ts` or `.tsx`). Default export has to be a function, actual function signature depends on entrypoint type 151 | 152 | | Type | Required | 153 | |----------|----------| 154 | | `string` | yes | 155 | 156 | ### `entrypoint.[*].icon` 157 | 158 | Path to assets file image file relative to `assets` directory. Currently displayed size is 18x18 pixels 159 | 160 | | Type | Required | 161 | |----------|----------| 162 | | `string` | no | 163 | 164 | ### `entrypoint.[*].type` 165 | 166 | Type of the entrypoint. Only following values are allowed: `"command"`, `"view"`, `"inline-view"` and `"entrypoint-generator"` 167 | 168 | | Type | Required | 169 | |--------|----------| 170 | | `enum` | yes | 171 | 172 | 173 | ## Entrypoint Actions 174 | 175 | ### `entrypoint.[*].actions.[*].id` 176 | 177 | ID of an action. Referenced from code to assign shortcut to an action. 178 | Can only contain: numbers, uppercase and lowercase letters 179 | 180 | | Type | Required | 181 | |----------|----------| 182 | | `string` | yes | 183 | 184 | ### `entrypoint.[*].actions.[*].description` 185 | 186 | Description of the action. Displayed in settings 187 | 188 | | Type | Required | 189 | |----------|----------| 190 | | `string` | yes | 191 | 192 | ### `entrypoint.[*].actions.[*].shortcut` 193 | 194 | Shortcut that can be used to execute action 195 | 196 | | Type | Required | 197 | |----------|----------| 198 | | `object` | false | 199 | 200 | ### `entrypoint.[*].actions.[*].shortcut.key` 201 | 202 | Key part of the shortcut 203 | 204 |
205 | All possible key values... 206 | - `"0"` 207 | - `"1"` 208 | - `"2"` 209 | - `"3"` 210 | - `"4"` 211 | - `"5"` 212 | - `"6"` 213 | - `"7"` 214 | - `"8"` 215 | - `"9"` 216 | - `"!"` 217 | - `"@"` 218 | - `"#"` 219 | - `"$"` 220 | - `"%"` 221 | - `"^"` 222 | - `"&"` 223 | - `"*"` 224 | - `"("` 225 | - `")"` 226 | - `"a"` 227 | - `"b"` 228 | - `"c"` 229 | - `"d"` 230 | - `"e"` 231 | - `"f"` 232 | - `"g"` 233 | - `"h"` 234 | - `"i"` 235 | - `"j"` 236 | - `"k"` 237 | - `"l"` 238 | - `"m"` 239 | - `"n"` 240 | - `"o"` 241 | - `"p"` 242 | - `"q"` 243 | - `"r"` 244 | - `"s"` 245 | - `"t"` 246 | - `"u"` 247 | - `"v"` 248 | - `"w"` 249 | - `"x"` 250 | - `"y"` 251 | - `"z"` 252 | - `"A"` 253 | - `"B"` 254 | - `"C"` 255 | - `"D"` 256 | - `"E"` 257 | - `"F"` 258 | - `"G"` 259 | - `"H"` 260 | - `"I"` 261 | - `"J"` 262 | - `"K"` 263 | - `"L"` 264 | - `"M"` 265 | - `"N"` 266 | - `"O"` 267 | - `"P"` 268 | - `"Q"` 269 | - `"R"` 270 | - `"S"` 271 | - `"T"` 272 | - `"U"` 273 | - `"V"` 274 | - `"W"` 275 | - `"X"` 276 | - `"Y"` 277 | - `"Z"` 278 | - `"-"` 279 | - `"="` 280 | - `","` 281 | - `"."` 282 | - `"/"` 283 | - `"["` 284 | - `"]"` 285 | - `";"` 286 | - `"'"` 287 | - `"\\"` 288 | - `"_"` 289 | - `"+"` 290 | - `"<"` 291 | - `">"` 292 | - `"?"` 293 | - `"{"` 294 | - `"}"` 295 | - `":"` 296 | - `"\""` 297 | - `"|"` 298 |
299 | 300 | 301 | | Type | Required | 302 | |----------|----------| 303 | | `string` | yes | 304 | 305 | ### `entrypoint.[*].actions.[*].shortcut.kind` 306 | 307 | Kind of the shortcut. Allowed values: `"main"` and `"alternative"` 308 | 309 | Modifiers: 310 | 311 | - `"main"` 312 | - Windows and Linux: CTRL 313 | - macOS: CMD 314 | - `"alternative"` 315 | - Windows and Linux: ALT 316 | - macOS: OPT 317 | 318 | Whether SHIFT is also required depends on character specified for shortcut key, 319 | e.g. `key` property value `"$"` will require SHIFT to be pressed, while `"4"` will not 320 | 321 | | Type | Required | 322 | |--------|----------| 323 | | `enum` | yes | 324 | 325 | ## Entrypoint Preferences 326 | 327 | ### `entrypoint.[*].preferences.[*].id` 328 | 329 | ID of the entrypoint preference. This will be used as name of the field in TypeScript. 330 | Can only contain: numbers, uppercase and lowercase letters 331 | 332 | | Type | Required | 333 | |----------|----------| 334 | | `string` | yes | 335 | 336 | ### `entrypoint.[*].preferences.[*].name` 337 | 338 | Name of the entrypoint preference. Displayed in settings 339 | 340 | | Type | Required | 341 | |----------|----------| 342 | | `string` | yes | 343 | 344 | ### `entrypoint.[*].preferences.[*].description` 345 | 346 | Description of the entrypoint preference. Displayed in settings 347 | 348 | | Type | Required | 349 | |----------|----------| 350 | | `string` | yes | 351 | 352 | ### `entrypoint.[*].preferences.[*].type` 353 | 354 | Type of the entrypoint preference. 355 | Allowed values: `"number"`, `"string"`, `"enum"`, `"bool"`, `"list_of_strings"`, `"list_of_numbers"` and `"list_of_enums"` 356 | 357 | | Type | Required | 358 | |--------|----------| 359 | | `enum` | yes | 360 | 361 | ### `entrypoint.[*].preferences.[*].default` 362 | 363 | Provides default value for the entrypoint preference. 364 | If not specified, preference will be considered required and user will be prompted to enter the value 365 | 366 | If preference type is `"enum"` or `"list_of_enums"`, `enum_values` property has to be provided and default value has to be one of values defined in `enum_values` 367 | 368 | Currently, not supported for list types, for which default value will be an empty list 369 | 370 | | Type | Required | 371 | |------------------------------------------------------------------------------------|----------| 372 | | `number`, `string`, `bool` or list of one of those depending on type of preference | no | 373 | 374 | ### `entrypoint.[*].preferences.[*].enum_values.[*].label` 375 | 376 | Label of the enum value. Displayed in settings 377 | 378 | | Type | Required | 379 | |----------|----------| 380 | | `string` | yes | 381 | 382 | ### `entrypoint.[*].preferences.[*].enum_values.[*].value` 383 | 384 | Value of the enum value. One of these values will be used as a value of the field in TypeScript and in `default` property 385 | 386 | | Type | Required | 387 | |----------|----------| 388 | | `string` | yes | 389 | 390 | ## Permissions 391 | 392 | Permission system in Gauntlet relies on Deno Security model. See [Deno documentation](https://docs.deno.com/runtime/fundamentals/security) for in depth information 393 | 394 | ### `permissions.[*].environment` 395 | 396 | Allows plugin to set or read listed environment variables. Values are names of environment variables 397 | 398 | | Type | Required | 399 | |------------------|----------| 400 | | list of `string` | false | 401 | 402 | ### `permissions.[*].network` 403 | 404 | Allows plugin to make network requests, open network listeners or perform DNS resolution. 405 | This includes making HTTP requests, opening TCP/UDP sockets, and listening for incoming connections on TCP or UDP. 406 | Values are IPv4, IPv6 or domain name, with optional port number 407 | 408 | | Type | Required | 409 | |------------------|----------| 410 | | list of `string` | false | 411 | 412 | ### `permissions.[*].filesystem.read` 413 | 414 | Allows plugin to read files on the file system inside specified path. 415 | This includes listing the contents of directories, checking for the existence of a given file, and connecting to Unix sockets 416 | 417 | Only absolute paths are allowed 418 | 419 | For Windows paths only `C:` drive is allowed to be specified 420 | 421 | #### Path variables 422 | 423 | Path permissions can contain also variables which will be resolved at plugin load time 424 | 425 | Examples: `"{linux:user-home}/.local/share"`, `"{common:plugin-cache}/my-plugin-cache"` 426 | 427 | Variables can only be used at the beginning of the path 428 | 429 | List of currently available variables: 430 | - `{macos:user-home}` 431 | - Resolves to `$HOME`, i.e. `/Users/` 432 | - Only available if plugin supports macOS 433 | - `{linux:user-home}` 434 | - Resolves to `$HOME`, i.e. `/home/` 435 | - Only available if plugin supports Linux 436 | - `{windows:user-home}` 437 | - Resolves to `{FOLDERID_Profile}`, i.e. `C:\Users\` 438 | - Only available if plugin supports Windows 439 | - `{common:plugin-data}` 440 | - On Windows: `{FOLDERID_RoamingAppData}\Gauntlet\data\plugins\` 441 | - On Linux: `$XDG_DATA_HOME/gauntlet/plugins/` 442 | - On macOS: `$HOME/Library/Application Support/dev.project-gauntlet.gauntlet/plugins/` 443 | - `{common:plugin-cache}` 444 | - On Windows: `{FOLDERID_LocalAppData}\Gauntlet\cache\plugins\` 445 | - On Linux: `$XDG_CACHE_HOME/gauntlet/plugins/` 446 | - On macOS: `$HOME/Library/Application Support/dev.project-gauntlet.gauntlet/plugins/` 447 | 448 | | Type | Required | 449 | |------------------|----------| 450 | | list of `string` | false | 451 | 452 | ### `permissions.[*].filesystem.write` 453 | 454 | Allows plugin to write to files on the file system inside specified path. 455 | This includes creating files or directories, writing to files and opening to Unix sockets 456 | 457 | Only absolute paths are allowed 458 | 459 | For Windows paths only `C:` drive is allowed to be specified 460 | 461 | Path permissions can contain also variables which will be resolved at plugin load time. 462 | See [filesystem read permissions section](#path-variables) for allowed variables 463 | 464 | | Type | Required | 465 | |------------------|----------| 466 | | list of `string` | false | 467 | 468 | ### `permissions.[*].exec.command` 469 | 470 | Allows plugins to spawn subprocesses. 471 | 472 | :::warning 473 | 474 | Plugin with ability to create subprocesses can effectively do any arbitrary action on user machine without declaring proper permissions 475 | 476 | ::: 477 | 478 | Values are names of commands on `PATH` environment variable. 479 | Actual path to used executable is resolved at plugin runtime load time due to restriction in Deno, 480 | so spawning subprocess of command whose executable was created after plugin runtime load time will fail with permission error 481 | 482 | | Type | Required | 483 | |------------------|----------| 484 | | list of `string` | false | 485 | 486 | ### `permissions.[*].exec.executable` 487 | 488 | Allows plugins to spawn subprocesses 489 | 490 | :::warning 491 | 492 | Plugin with ability to create subprocesses can effectively do any arbitrary action on user machine without declaring proper permissions 493 | 494 | ::: 495 | 496 | Only absolute paths are allowed 497 | 498 | For Windows paths only `C:` drive is allowed to be specified 499 | 500 | Path permissions can contain also variables which will be resolved at plugin load time. 501 | See [filesystem read permissions section](#path-variables) for allowed variables 502 | 503 | | Type | Required | 504 | |------------------|----------| 505 | | list of `string` | false | 506 | 507 | ### `permissions.[*].system` 508 | 509 | Some APIs in Deno require special system information permission. See [Deno documentation](https://docs.deno.com/runtime/fundamentals/security/#system-information) 510 | 511 | | Type | Required | 512 | |------------------|----------| 513 | | list of `string` | false | 514 | 515 | ### `permissions.[*].clipboard` 516 | 517 | Allows plugin to read and manipulate OS clipboard via Gauntlet's [Clipboard API](../api-reference/clipboard.mdx) 518 | 519 | Allowed values: `"read"`, `"write"` and `"clear"` 520 | 521 | | Type | Required | 522 | |----------------|----------| 523 | | list of `enum` | false | 524 | 525 | 526 | ### `permissions.[*].main_search_bar` 527 | 528 | Allows plugin to read value of main search bar at any time. Required to use [Inline view entrypoint](../api-reference/entrypoint-types/inline-view.mdx) 529 | 530 | Allowed values: `"read"` 531 | 532 | | Type | Required | 533 | |----------------|----------| 534 | | list of `enum` | false | 535 | 536 | 537 | ## Other 538 | 539 | ### `supported_system.[*].os` 540 | 541 | Specifies which OS is supported by plugin. Only required if plugin uses one of the following permissions: 542 | environment variables, filesystem, system, exec. If plugin doesn't use any of those permissions, plugin is considered cross-platform 543 | 544 | Allowed values: `"linux"`, `"windows"` and `"macos"` 545 | 546 | | Type | Required | 547 | |--------|----------| 548 | | `enum` | true | 549 | -------------------------------------------------------------------------------- /component-generator/src/component-generator.ts: -------------------------------------------------------------------------------- 1 | import { EOL } from "node:os"; 2 | import { readdir } from "node:fs/promises"; 3 | import path from "node:path"; 4 | import { cpSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; 5 | import { parse as parseToml } from "toml"; 6 | import * as process from "node:process"; 7 | import dedent from "dedent"; 8 | 9 | interface GauntletGithubCodePluginData { 10 | pluginId: string 11 | entrypoints: GauntletGithubCodeEntrypointData[] 12 | } 13 | 14 | interface GauntletGithubCodeEntrypointData { 15 | entrypointId: string 16 | data: { 17 | codeFilePathRootRelative: string 18 | codeFilePathPluginRelative: string 19 | codeSegments: { 20 | id: string, 21 | value: string, 22 | lines?: [number, number], 23 | screenshotFilePath: string, 24 | }[] 25 | manifestFilePathRootRelative: string 26 | manifestFilePathPluginRelative: string 27 | manifestSegment: { 28 | value: string 29 | manifestFileLines: [number, number] 30 | } 31 | } 32 | } 33 | 34 | function findCodeSegments(fileContent: string): { 35 | id?: string, 36 | lines: string[], 37 | startIndex: number, 38 | endIndex?: number 39 | }[] | undefined { 40 | const lines = fileContent.split(EOL); 41 | 42 | const startString = "docs-code-segment:start"; 43 | const endString = "docs-code-segment:end"; 44 | 45 | return lines 46 | .map<{ line: string, isStart: boolean, isEnd: boolean, id?: string, index: number }>((line, index) => { 47 | const isStart = line.includes(startString); 48 | const isEnd = line.includes(endString); 49 | 50 | const indexOneBased = index + 1; 51 | 52 | if (isStart) { 53 | const id = line.trim().split(startString).pop()?.trim(); 54 | 55 | return { line, isStart, isEnd, id: id === "" ? undefined : id, index: indexOneBased }; 56 | } 57 | 58 | return { line, isStart, isEnd, index: indexOneBased }; 59 | }) 60 | .reduce<{ id?: string, lines: string[], startIndex: number, endIndex?: number }[]>((acc, curr) => { 61 | if (curr.isStart) { 62 | acc.push({ id: curr.id, lines: [], startIndex: curr.index + 1 }); 63 | } else if (curr.isEnd && acc.length > 0) { 64 | const accElement = acc[acc.length - 1]; 65 | accElement.endIndex = curr.index - 1; 66 | } else if (acc.length > 0) { 67 | const accElement = acc[acc.length - 1]; 68 | if (accElement.endIndex == undefined) { 69 | accElement.lines.push(curr.line); 70 | } 71 | } 72 | return acc; 73 | }, []) 74 | } 75 | 76 | async function readCodeExampleData(gauntletRepoPath: string) { 77 | const scenariosDocsPath = path.resolve(gauntletRepoPath, 'example_plugins') 78 | const pluginsDocsPath = path.resolve(scenariosDocsPath, 'plugins') 79 | 80 | return (await readdir(pluginsDocsPath, { withFileTypes: true })) 81 | .filter(dirent => dirent.isDirectory()) 82 | .map(dirent => dirent.name) 83 | .map(pluginId => { 84 | const pluginDirPath = path.resolve(pluginsDocsPath, pluginId) 85 | const manifestFilePath = path.resolve(pluginDirPath, 'gauntlet.toml') 86 | const manifestFileRootRelativePath = path.relative(gauntletRepoPath, manifestFilePath) 87 | const manifestFileRootPluginRelative = path.relative(pluginDirPath, manifestFilePath) 88 | 89 | const manifestFileContent = readFileSync(manifestFilePath, "utf8"); 90 | 91 | const findCodeSegmentsResult = findCodeSegments(manifestFileContent); 92 | 93 | if (findCodeSegmentsResult == undefined) { 94 | throw new Error("segments not found") 95 | } 96 | 97 | const manifestSegmentsArr = findCodeSegmentsResult 98 | .map(manifestSegment => { 99 | if (manifestSegment.id == null) { 100 | throw new Error(`manifest file segment doesn't have id: ${manifestFilePath}`) 101 | } 102 | 103 | return [ 104 | manifestSegment.id, 105 | { 106 | segment: manifestSegment.lines.join(EOL), 107 | startIndex: manifestSegment.startIndex, 108 | endIndex: manifestSegment.endIndex! 109 | } 110 | ] as [string, { segment: string, startIndex: number, endIndex: number }] 111 | }); 112 | 113 | const manifestSegmentMap = Object.fromEntries(manifestSegmentsArr) 114 | 115 | const manifest = parseToml(manifestFileContent) as { entrypoint: { id: string, path: string }[] } 116 | 117 | const entrypointData = manifest.entrypoint 118 | .map(entrypoint => { 119 | let entrypointId = entrypoint.id; 120 | let entrypointPath = entrypoint.path; 121 | const codeFilePath = path.resolve(pluginDirPath, entrypointPath) 122 | const codeFileRootRootRelativePath = path.relative(gauntletRepoPath, codeFilePath) 123 | const codeFileRootPluginRelativePath = path.relative(pluginDirPath, codeFilePath) 124 | 125 | const codeFileContent = readFileSync(codeFilePath, "utf8"); 126 | const codeSegments = findCodeSegments(codeFileContent); 127 | 128 | const codeSegmentsResult: GauntletGithubCodeEntrypointData['data']['codeSegments'] = []; 129 | if (codeSegments.length == 0) { 130 | const id = "default"; 131 | 132 | const screenshotFilePath = path.resolve('/img', 'generated-screenshots', pluginId, entrypointId, `${id}.png`) 133 | 134 | codeSegmentsResult.push({ 135 | id: id, 136 | value: codeFileContent, 137 | screenshotFilePath 138 | }) 139 | } else if (codeSegments.length == 1) { 140 | const [codeSegment] = codeSegments 141 | if (codeSegment.id != null) { 142 | throw new Error(`code file segment has id: ${codeSegment.id}, ${codeFilePath}`) 143 | } 144 | 145 | const id = "default"; 146 | 147 | const screenshotFilePath = path.resolve('/img', 'generated-screenshots', pluginId, entrypointId, `${id}.png`) 148 | 149 | codeSegmentsResult.push({ 150 | id, 151 | value: dedent(codeSegment.lines.join(EOL)), 152 | lines: [codeSegment.startIndex, codeSegment.endIndex!], 153 | screenshotFilePath 154 | }) 155 | } else { 156 | codeSegmentsResult.push( 157 | ...codeSegments.map(codeSegment => { 158 | if (codeSegment.id == null) { 159 | throw new Error(`code file segment doesn't have id: ${codeFilePath}`) 160 | } 161 | 162 | const screenshotFilePath = path.resolve('/img', 'generated-screenshots', pluginId, entrypointId, `${codeSegment.id}.png`) 163 | 164 | return { 165 | id: codeSegment.id, 166 | value: dedent(codeSegment.lines.join(EOL)), 167 | lines: [codeSegment.startIndex, codeSegment.endIndex!] as [number, number], 168 | screenshotFilePath 169 | } 170 | }) 171 | ) 172 | } 173 | 174 | const manifestSegment = manifestSegmentMap[entrypointId] 175 | 176 | if (manifestSegment == null) { 177 | throw new Error(`manifest not found for plugin id '${pluginId}' and entrypoint id '${entrypointId}'`) 178 | } 179 | 180 | return { 181 | entrypointId, 182 | data: { 183 | codeFilePathRootRelative: codeFileRootRootRelativePath, 184 | codeFilePathPluginRelative: codeFileRootPluginRelativePath, 185 | codeSegments: codeSegmentsResult, 186 | manifestFilePathRootRelative: manifestFileRootRelativePath, 187 | manifestFilePathPluginRelative: manifestFileRootPluginRelative, 188 | manifestSegment: { 189 | value: manifestSegment.segment, 190 | manifestFileLines: [manifestSegment.startIndex, manifestSegment.endIndex!], 191 | }, 192 | } 193 | } satisfies GauntletGithubCodeEntrypointData 194 | }) 195 | 196 | return { 197 | pluginId, 198 | entrypoints: entrypointData 199 | } 200 | }); 201 | } 202 | 203 | async function generateCodeExample(generatedPath: string, data: GauntletGithubCodePluginData[]) { 204 | const generatedPathCodeExample = path.resolve(generatedPath, 'code_example') 205 | 206 | mkdirSync(generatedPathCodeExample, { recursive: true }) 207 | 208 | for (const plugin of data) { 209 | const dir = path.resolve(generatedPathCodeExample, plugin.pluginId) 210 | mkdirSync(dir) 211 | } 212 | 213 | for (const plugin of data) { 214 | for (const entrypoint of plugin.entrypoints) { 215 | 216 | const jsxPath = path.resolve(generatedPathCodeExample, plugin.pluginId, `${entrypoint.entrypointId}.tsx`) 217 | 218 | createJsxWithDataInput("CodeExample", jsxPath, entrypoint.data, true) 219 | } 220 | } 221 | } 222 | 223 | function readComponentModel(gauntletRepoPath: string): any { 224 | const componentModelPath = path.resolve(gauntletRepoPath, 'js', 'api_build', 'component_model.json') 225 | 226 | return JSON.parse(readFileSync(componentModelPath, { encoding: "utf-8" })) 227 | } 228 | 229 | 230 | async function generatePropertyTables(generatedPath: string, components: any) { 231 | const generatedTablesPath = path.resolve(generatedPath, 'tables') 232 | 233 | mkdirSync(generatedTablesPath) 234 | 235 | for (const component of components) { 236 | switch (component.type) { 237 | case "text_part": { 238 | break 239 | } 240 | case "root": { 241 | break 242 | } 243 | case "standard": { 244 | const generatedTablesComponentPath = path.resolve(generatedTablesPath, component.internalName) 245 | 246 | mkdirSync(generatedTablesComponentPath) 247 | 248 | createJsxWithDataInput( 249 | "Description", 250 | path.resolve(generatedTablesComponentPath, `description.tsx`), 251 | { 252 | description: component.description, 253 | }, 254 | false 255 | ) 256 | 257 | if (component.props.length !== 0) { 258 | createJsxWithDataInput( 259 | "PropsTable", 260 | path.resolve(generatedTablesComponentPath, `props.tsx`), 261 | { 262 | internalName: component.internalName, 263 | props: component.props 264 | }, 265 | false 266 | ) 267 | } 268 | 269 | switch (component.children.type) { 270 | case "none": 271 | break; 272 | case "string": { 273 | 274 | createJsxWithDataInput( 275 | "OrderedMembersTable", 276 | path.resolve(generatedTablesComponentPath, `ordered-members.tsx`), 277 | { 278 | tableKey: component.internalName, 279 | members: {}, 280 | withString: true 281 | }, 282 | false 283 | ) 284 | 285 | break; 286 | } 287 | case "members": { 288 | 289 | if (Object.entries(component.children.ordered_members).length !== 0) { 290 | createJsxWithDataInput( 291 | "OrderedMembersTable", 292 | path.resolve(generatedTablesComponentPath, `ordered-members.tsx`), 293 | { 294 | tableKey: component.internalName, 295 | members: component.children.ordered_members, 296 | withString: false 297 | }, 298 | false 299 | ) 300 | } 301 | 302 | if (Object.entries(component.children.per_type_members).length !== 0) { 303 | createJsxWithDataInput( 304 | "PerTypeMembersTable", 305 | path.resolve(generatedTablesComponentPath, `per-type-members.tsx`), 306 | { 307 | tableKey: component.internalName, 308 | members: component.children.per_type_members, 309 | }, 310 | false 311 | ) 312 | } 313 | 314 | break; 315 | } 316 | case "string_or_members": { 317 | createJsxWithDataInput( 318 | "OrderedMembersTable", 319 | path.resolve(generatedTablesComponentPath, `ordered-members.tsx`), 320 | { 321 | tableKey: component.internalName, 322 | members: component.children.ordered_members, 323 | withString: true 324 | }, 325 | false 326 | ) 327 | 328 | if (Object.entries(component.children.per_type_members).length !== 0) { 329 | createJsxWithDataInput( 330 | "PerTypeMembersTable", 331 | path.resolve(generatedTablesComponentPath, `per-type-members.tsx`), 332 | { 333 | tableKey: component.internalName, 334 | members: component.children.per_type_members, 335 | }, 336 | false 337 | ) 338 | } 339 | 340 | break; 341 | } 342 | } 343 | } 344 | } 345 | } 346 | } 347 | 348 | function createJsxWithDataInput(name: string, filePath: string, data: object, screenshotFlag: boolean) { 349 | const pre = ` 350 | import ${name} from '@site/src/components/${name}'; 351 | import React from "react"; 352 | import { Buffer } from "buffer"; 353 | const data = JSON.parse(Buffer.from(\` 354 | ` 355 | 356 | const serializedData = Buffer.from(JSON.stringify(data), "utf-8").toString('base64'); 357 | 358 | const post = ` 359 | \`, 'base64').toString('utf-8')); 360 | export default function Default(${screenshotFlag ? "{ screenshot }: { screenshot?: boolean }" : ""}): JSX.Element { 361 | return ( 362 | <${name} data={data} ${screenshotFlag ? "screenshot={screenshot}" : ""}/> 363 | ); 364 | } 365 | ` 366 | 367 | writeFileSync(filePath, `${pre}${serializedData}${post}\n`) 368 | } 369 | 370 | async function run(args: string[]) { 371 | const argPathToMainRepo = args[0]; 372 | const gauntletRepoPath = path.resolve(process.cwd(), '..', argPathToMainRepo) 373 | 374 | // validate 375 | const packageJson = JSON.parse(readFileSync(path.resolve(gauntletRepoPath, 'package.json'), { encoding: "utf-8" })); 376 | if (packageJson.name != "project-gauntlet") { 377 | throw new Error("unexpected project") 378 | } 379 | 380 | const repoRootPath = path.resolve(process.cwd(), '..') 381 | const generatedPath = path.resolve(repoRootPath, 'src', 'generated') 382 | rmSync(generatedPath, { recursive: true, force: true }) 383 | 384 | const screenshots = path.resolve(gauntletRepoPath, 'example_plugins', 'out_screenshot') 385 | const generatedScreenshotsPath = path.resolve(repoRootPath, 'static', 'img', 'generated-screenshots') 386 | rmSync(generatedScreenshotsPath, { recursive: true, force: true }) 387 | cpSync(screenshots, generatedScreenshotsPath, { recursive: true }) 388 | 389 | await generateCodeExample(generatedPath, await readCodeExampleData(gauntletRepoPath)) 390 | 391 | await generatePropertyTables(generatedPath, readComponentModel(gauntletRepoPath)) 392 | } 393 | 394 | await run(process.argv.slice(2)) --------------------------------------------------------------------------------