Let Prettier format the code
This commit is contained in:
parent
c7866794c9
commit
3765caa811
90 changed files with 1907 additions and 1621 deletions
160
CHANGELOG.md
160
CHANGELOG.md
|
|
@ -9,201 +9,201 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
### New Features
|
||||
|
||||
* Support for Renardo (Foxdot fork)
|
||||
* web: Sandbox web languages using iframes
|
||||
* web: Toggle line numbers with <kbd>Shift</kbd>-<kbd>Ctrl</kbd>-<kbd>W</kbd>
|
||||
- Support for Renardo (Foxdot fork)
|
||||
- web: Sandbox web languages using iframes
|
||||
- web: Toggle line numbers with <kbd>Shift</kbd>-<kbd>Ctrl</kbd>-<kbd>W</kbd>
|
||||
and linewrap with <kbd>Shift</kbd>-<kbd>Ctrl</kbd>-<kbd>W</kbd>.
|
||||
* web(strudel): Code highlighting
|
||||
- web(strudel): Code highlighting
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* repl: Use `sardine` instead of `fishery` when running Sardine REPL
|
||||
* web(hydra): Use correct canvas size by default + pixelated image rendering
|
||||
* web(strudel): Misc fixse
|
||||
* Lots of name clashing between hydra, strudel and mercury-web were solved with
|
||||
- repl: Use `sardine` instead of `fishery` when running Sardine REPL
|
||||
- web(hydra): Use correct canvas size by default + pixelated image rendering
|
||||
- web(strudel): Misc fixse
|
||||
- Lots of name clashing between hydra, strudel and mercury-web were solved with
|
||||
language sandboxes.
|
||||
|
||||
## [1.1.1] - 2024-01-29
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* web(strudel): Use REPL evaluate method, this fixes the "`setcps` is not defined" error.
|
||||
- web(strudel): Use REPL evaluate method, this fixes the "`setcps` is not defined" error.
|
||||
|
||||
## [1.1.0] - 2024-01-28
|
||||
|
||||
### Bugfixes
|
||||
|
||||
* web(hydra): Fixed issues with P5 not loading properly
|
||||
* web(hydra): `await` now works properly
|
||||
* web: Fixed issue with `flok-web` binary script running in development mode
|
||||
- web(hydra): Fixed issues with P5 not loading properly
|
||||
- web(hydra): `await` now works properly
|
||||
- web: Fixed issue with `flok-web` binary script running in development mode
|
||||
|
||||
### New Features
|
||||
|
||||
* web: Share URL command for sharing session URL along with current layout and
|
||||
- web: Share URL command for sharing session URL along with current layout and
|
||||
code.
|
||||
* web: `hideErrors` query parameter option for hiding errors of web targets
|
||||
* web: `code` and `c0`..`c7` hash parameters to set code for each editor
|
||||
- web: `hideErrors` query parameter option for hiding errors of web targets
|
||||
- web: `code` and `c0`..`c7` hash parameters to set code for each editor
|
||||
|
||||
### Changed
|
||||
|
||||
* web(hydra): Updated P5 to 1.9.0
|
||||
* web(mercury): Updated Mercury to 0.14.0
|
||||
* web(strudel): Updated Strudel to 1.0.0
|
||||
* web: Updated Codemirror and related packages
|
||||
* web: Updated Yjs and related packages
|
||||
* web: Updated Vite 5
|
||||
* web: Moved `username` and `targets` query parameters as hash parameters
|
||||
- web(hydra): Updated P5 to 1.9.0
|
||||
- web(mercury): Updated Mercury to 0.14.0
|
||||
- web(strudel): Updated Strudel to 1.0.0
|
||||
- web: Updated Codemirror and related packages
|
||||
- web: Updated Yjs and related packages
|
||||
- web: Updated Vite 5
|
||||
- web: Moved `username` and `targets` query parameters as hash parameters
|
||||
|
||||
## [1.0.2] - 2024-01-13
|
||||
|
||||
### Changed
|
||||
|
||||
* repl: Fix error when trying to use flok-repl without `-T`/`--types` argument (default value)
|
||||
- repl: Fix error when trying to use flok-repl without `-T`/`--types` argument (default value)
|
||||
|
||||
## [1.0.1] - 2024-01-13
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Fixed and optimized flok-web package, by removing lots of runtime deps
|
||||
- web: Fixed and optimized flok-web package, by removing lots of runtime deps
|
||||
that were used on build time only.
|
||||
* web: Removed pinned flok-repl version from REPL instructions.
|
||||
- web: Removed pinned flok-repl version from REPL instructions.
|
||||
|
||||
## [1.0.0] - 2024-01-12
|
||||
|
||||
Complete rewrite of Flok, with a new architecture and new features. See
|
||||
Complete rewrite of Flok, with a new architecture and new features. See
|
||||
[README.md](../README.md) for more information.
|
||||
|
||||
* Started new web project, based on Vite, Tailwind, Radix UI and Shadcn CSS frameworks.
|
||||
* Upgraded CodeMirror to version 6
|
||||
* Upgraded Yjs to latest version
|
||||
* New modular architecture, with separate plugins related to codemirror
|
||||
- Started new web project, based on Vite, Tailwind, Radix UI and Shadcn CSS frameworks.
|
||||
- Upgraded CodeMirror to version 6
|
||||
- Upgraded Yjs to latest version
|
||||
- New modular architecture, with separate plugins related to codemirror
|
||||
(following their new architecture as well)
|
||||
* Document layout is now part of the session state, and can be changed
|
||||
- Document layout is now part of the session state, and can be changed
|
||||
dynamically, instead of being based on the query parameter `?layout`.
|
||||
* Improved REPL message handling and UI
|
||||
* Command palette for executing commands and configuring the editor
|
||||
* Added support for Strudel and Mercury as web targets
|
||||
- Improved REPL message handling and UI
|
||||
- Command palette for executing commands and configuring the editor
|
||||
- Added support for Strudel and Mercury as web targets
|
||||
|
||||
## [0.4.12] - 2024-01-06
|
||||
|
||||
### Added
|
||||
|
||||
* web: Toggle comment with Ctrl-/ or Cmd-/
|
||||
* web(sardine): Free all sound for Sardine
|
||||
- web: Toggle comment with Ctrl-/ or Cmd-/
|
||||
- web(sardine): Free all sound for Sardine
|
||||
|
||||
### Changed
|
||||
|
||||
* repl(sardine): Changed interpreter name (fishery -> sardine)
|
||||
* web: Bugfixes related to the server script (flok-web)
|
||||
* web: Fixed @types/react wrong version
|
||||
- repl(sardine): Changed interpreter name (fishery -> sardine)
|
||||
- web: Bugfixes related to the server script (flok-web)
|
||||
- web: Fixed @types/react wrong version
|
||||
|
||||
## [0.4.8] - 2022-05-26
|
||||
|
||||
### Added
|
||||
|
||||
* web: Add key binding Ctrl+Shift+H to hide or show editors
|
||||
- web: Add key binding Ctrl+Shift+H to hide or show editors
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Replace yjsdemo WebSocket Yjs server for an embedded WS server
|
||||
* web: Use a random english name + first 8 chars of uuid as default session name
|
||||
* web: Upgrade p5 to version 1.4.1
|
||||
* web: Upgrade hydra-synth to version 1.3.16
|
||||
* web: Upgrade Next to version 12
|
||||
* web: Restore package bundle
|
||||
- web: Replace yjsdemo WebSocket Yjs server for an embedded WS server
|
||||
- web: Use a random english name + first 8 chars of uuid as default session name
|
||||
- web: Upgrade p5 to version 1.4.1
|
||||
- web: Upgrade hydra-synth to version 1.3.16
|
||||
- web: Upgrade Next to version 12
|
||||
- web: Restore package bundle
|
||||
|
||||
## [0.4.6] - 2021-10-31
|
||||
|
||||
### Added
|
||||
|
||||
* web: Print possible network IPs when starting web server locally
|
||||
* web: New --static-dir option for setting a custom static files directory when
|
||||
- web: Print possible network IPs when starting web server locally
|
||||
- web: New --static-dir option for setting a custom static files directory when
|
||||
starting web server.
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Upgrade hydra-synth to 1.3.8
|
||||
* web: Upgrade next to 11
|
||||
* repl: Remove "tidal> " from stdout on tidal target; other minor improvements
|
||||
- web: Upgrade hydra-synth to 1.3.8
|
||||
- web: Upgrade next to 11
|
||||
- repl: Remove "tidal> " from stdout on tidal target; other minor improvements
|
||||
|
||||
## [0.4.5] - 2021-01-05
|
||||
|
||||
### Added
|
||||
|
||||
* web: Read-only mode by adding a `readonly=1` query parameter to a session URL
|
||||
* repl: In `foxdot` REPL, call `load_startup_file()` after loading Foxdot package.
|
||||
- web: Read-only mode by adding a `readonly=1` query parameter to a session URL
|
||||
- repl: In `foxdot` REPL, call `load_startup_file()` after loading Foxdot package.
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Upgrade hydra-synth to 1.3.6
|
||||
- web: Upgrade hydra-synth to 1.3.6
|
||||
|
||||
## [0.4.4] - 2020-12-23
|
||||
|
||||
### Added
|
||||
|
||||
* web: Follow remote cursors when moving (jump to line), but only if editor is
|
||||
- web: Follow remote cursors when moving (jump to line), but only if editor is
|
||||
blurred.
|
||||
* web: Make remote caret visible to current user too.
|
||||
* web: Properly support block evaluation with parens for
|
||||
- web: Make remote caret visible to current user too.
|
||||
- web: Properly support block evaluation with parens for
|
||||
`sclang`/`remote_sclang` targets.
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Skip 'hydra' as a flok-repl example when joining a session
|
||||
* repl: Bugfix when using custom REPL command
|
||||
* repl: On sclang targets, add semicolons after closing parens
|
||||
- web: Skip 'hydra' as a flok-repl example when joining a session
|
||||
- repl: Bugfix when using custom REPL command
|
||||
- repl: On sclang targets, add semicolons after closing parens
|
||||
|
||||
## [0.4.3] - 2020-12-04
|
||||
|
||||
### Added
|
||||
|
||||
* repl, web: Support for Mercury
|
||||
* web: When joining session, show flok-repl example based on first target in
|
||||
- repl, web: Support for Mercury
|
||||
- web: When joining session, show flok-repl example based on first target in
|
||||
layout.
|
||||
* web: New shortcut for evaluating web-target (e.g. Hydra) code only on local
|
||||
- web: New shortcut for evaluating web-target (e.g. Hydra) code only on local
|
||||
client (Ctrl-Alt-Enter for block execution, Shift-Alt-Enter for line
|
||||
execution).
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Upgrade to Hydra 1.3.4
|
||||
- web: Upgrade to Hydra 1.3.4
|
||||
|
||||
## [0.4.2] - 2020-11-12
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Better styles for selected text and remote caret
|
||||
* repl: Fix path to embedded BootTidal.hs when using fallback
|
||||
- web: Better styles for selected text and remote caret
|
||||
- repl: Fix path to embedded BootTidal.hs when using fallback
|
||||
|
||||
## [0.4.1] - 2020-10-11
|
||||
|
||||
### Added
|
||||
|
||||
* web: Copy button for copying flok-repl example when joining session
|
||||
* repl: Add package metadata and data dir, which includes a Tidal bootScript
|
||||
- web: Copy button for copying flok-repl example when joining session
|
||||
- repl: Add package metadata and data dir, which includes a Tidal bootScript
|
||||
file.
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Disable form when creating session, while session page loads
|
||||
* repl: If ghc-pkg fails to get tidal data dir, fallback to embedded bootScript
|
||||
- web: Disable form when creating session, while session page loads
|
||||
- repl: If ghc-pkg fails to get tidal data dir, fallback to embedded bootScript
|
||||
file.
|
||||
|
||||
## [0.4.0] - 2020-10-06
|
||||
|
||||
### Added
|
||||
|
||||
* repl: Add `--nickname/-N` to send REPL messages (out/err) to named user instead
|
||||
- repl: Add `--nickname/-N` to send REPL messages (out/err) to named user instead
|
||||
of all connected users.
|
||||
* repl: Add `--notify-to-all` to force send messages to all users (old behaviour).
|
||||
* repl: Add extra option `ghci` for `tidal` REPL type, for customizing ghci
|
||||
- repl: Add `--notify-to-all` to force send messages to all users (old behaviour).
|
||||
- repl: Add extra option `ghci` for `tidal` REPL type, for customizing ghci
|
||||
binary path.
|
||||
* web: Show current Flok version when joining session.
|
||||
* web: Include -N option on flok-repl example when joining session.
|
||||
- web: Show current Flok version when joining session.
|
||||
- web: Include -N option on flok-repl example when joining session.
|
||||
|
||||
### Changed
|
||||
|
||||
* Now, by default, `flok-repl` *will not* send messages to all users by default.
|
||||
- Now, by default, `flok-repl` _will not_ send messages to all users by default.
|
||||
You need to enable the `--notify-to-all` option if you want the old
|
||||
behaviour. If `--nickname/-N` and `--notify-to-all` are not present,
|
||||
flok-repl won't send any messages, only print them on standard output/error.
|
||||
|
|
@ -212,11 +212,11 @@ Complete rewrite of Flok, with a new architecture and new features. See
|
|||
|
||||
### Added
|
||||
|
||||
* repl: Add new `--config` option for customizing parameters from a JSON file
|
||||
* repl: Load config file from `FLOK_CONFIG` environment file, if defined. Also,
|
||||
load *.env files* automatically.
|
||||
- repl: Add new `--config` option for customizing parameters from a JSON file
|
||||
- repl: Load config file from `FLOK_CONFIG` environment file, if defined. Also,
|
||||
load _.env files_ automatically.
|
||||
|
||||
### Changed
|
||||
|
||||
* web: Bugfix: host prop was undefined on first page load, failing to connect
|
||||
- web: Bugfix: host prop was undefined on first page load, failing to connect
|
||||
afterwards.
|
||||
|
|
|
|||
|
|
@ -14,21 +14,21 @@ orientation.
|
|||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
|
|
|||
219
README.md
219
README.md
|
|
@ -4,9 +4,9 @@ Web-based P2P collaborative editor for live coding music and graphics
|
|||
|
||||
## Features
|
||||
|
||||
* Similar to Etherpad, but focused on code evaluation for livecoding.
|
||||
* Multiple separate slots for different languages and tools.
|
||||
* REPL plugins: allows user to locally evaluate code from interpreters (like
|
||||
- Similar to Etherpad, but focused on code evaluation for livecoding.
|
||||
- Multiple separate slots for different languages and tools.
|
||||
- REPL plugins: allows user to locally evaluate code from interpreters (like
|
||||
Haskell, Ruby, Python, etc.):
|
||||
- [TidalCycles](https://tidalcycles.org/)
|
||||
- [SuperCollider](https://supercollider.github.io/) (sclang)
|
||||
|
|
@ -14,66 +14,66 @@ Web-based P2P collaborative editor for live coding music and graphics
|
|||
- [Renardo](https://renardo.org/)
|
||||
- [Mercury](#mercury)
|
||||
- [Sardine](https://sardine.raphaelforment.fr)
|
||||
- [SonicPi](https://sonic-pi.net/) (*not implemented yet*, see [#29](https://github.com/munshkr/flok/issues/29))
|
||||
- [SonicPi](https://sonic-pi.net/) (_not implemented yet_, see [#29](https://github.com/munshkr/flok/issues/29))
|
||||
- ... any interpreter with a REPL (Python, Ruby, etc.)
|
||||
* Web Plugins, for languages embedded in editor:
|
||||
- Web Plugins, for languages embedded in editor:
|
||||
- [Hydra](https://github.com/ojack/hydra)
|
||||
- [p5.js](https://p5js.org/)
|
||||
- [Strudel](https://strudel.cc/)
|
||||
- [Mercury Web](https://www.timohoogland.com/mercury-livecoding/)
|
||||
- [VEDA.js](https://github.com/fand/vedajs) (*not implemented yet*, see [#82](https://github.com/munshkr/flok/pull/82))
|
||||
- [VEDA.js](https://github.com/fand/vedajs) (_not implemented yet_, see [#82](https://github.com/munshkr/flok/pull/82))
|
||||
|
||||
## Usage
|
||||
|
||||
### Public server
|
||||
|
||||
**WARNING - Please Read**: Using a public server can be dangerous as *anyone*
|
||||
can execute code on your computer via Flok, so *please* make sure you only
|
||||
**WARNING - Please Read**: Using a public server can be dangerous as _anyone_
|
||||
can execute code on your computer via Flok, so _please_ make sure you only
|
||||
share your session URL to trusted users and friends when you use a public
|
||||
server. I will not be held responsible for any damaged caused by Flok. You
|
||||
server. I will not be held responsible for any damaged caused by Flok. You
|
||||
have been warned.
|
||||
|
||||
This is a list of known public servers:
|
||||
|
||||
* [flok.cc](https://flok.cc)
|
||||
- [flok.cc](https://flok.cc)
|
||||
|
||||
#### Create a session
|
||||
|
||||
When you enter a Flok server, you will be shown an empty session with a single
|
||||
slot, with a _target_ selected (usually `hydra`). You can either change the
|
||||
slot, with a _target_ selected (usually `hydra`). You can either change the
|
||||
target by clicking on the target selector at the top-left corner of the slot, or
|
||||
add more slots by clicking on the *Command button* (at the top-right corner of the
|
||||
screen), and then clicking on *Add Pane*, or *Configure*.
|
||||
add more slots by clicking on the _Command button_ (at the top-right corner of the
|
||||
screen), and then clicking on _Add Pane_, or _Configure_.
|
||||
|
||||
A *target* is the language or tool that Flok will communicate to create sound or
|
||||
A _target_ is the language or tool that Flok will communicate to create sound or
|
||||
images within the web page, or through `flok-repl`.
|
||||
|
||||
If you clicked on *Configure*, enter the name of the targets, separated with
|
||||
commas. You can use a target multiple times and Flok will create that many
|
||||
If you clicked on _Configure_, enter the name of the targets, separated with
|
||||
commas. You can use a target multiple times and Flok will create that many
|
||||
number of slots to write code. Currently the maximum number of slots is 8.
|
||||
|
||||
Examples:
|
||||
|
||||
* `tidal, foxdot, hydra`: 3 slots, with tidal, foxdot and hydra respectively.
|
||||
* `sclang, sclang, sclang, hydra, hydra`: 5 slots total, the first 3 with
|
||||
- `tidal, foxdot, hydra`: 3 slots, with tidal, foxdot and hydra respectively.
|
||||
- `sclang, sclang, sclang, hydra, hydra`: 5 slots total, the first 3 with
|
||||
`sclang` and the last 2 with `hydra`.
|
||||
* `mercury, hydra`: 2 slots total, one with Mercury and one with Hydra.
|
||||
- `mercury, hydra`: 2 slots total, one with Mercury and one with Hydra.
|
||||
|
||||
You will also be asked to enter a nickname. This is the name that will be shown
|
||||
to other users under your cursor, when you write code. You can change it any
|
||||
time by clicking on the *Change Username* inside the *Command* menu.
|
||||
You will also be asked to enter a nickname. This is the name that will be shown
|
||||
to other users under your cursor, when you write code. You can change it any
|
||||
time by clicking on the _Change Username_ inside the _Command_ menu.
|
||||
|
||||
Now, just copy the URL and share it with your friends! They will be able to
|
||||
Now, just copy the URL and share it with your friends! They will be able to
|
||||
join the session and write code with you :-)
|
||||
|
||||
If you are using any target that requires a REPL, you will need to start it
|
||||
separately. See the *Connect REPLs to Flok* section below.
|
||||
separately. See the _Connect REPLs to Flok_ section below.
|
||||
|
||||
#### Connect REPLs to Flok
|
||||
|
||||
The last step is to start `flok-repl`, to connect Flok with your REPLs.
|
||||
|
||||
Just click on the *REPLs* button at the top-right corner of the screen, and
|
||||
Just click on the _REPLs_ button at the top-right corner of the screen, and
|
||||
copy the command shown there. It will look something like this:
|
||||
|
||||
```sh
|
||||
|
|
@ -84,7 +84,7 @@ npx flok-repl@latest -H wss://next.flok.cc \
|
|||
```
|
||||
|
||||
This command will automatically try to download and install `flok-repl` and
|
||||
start it, connecting it to your session. If you have multiple different targets
|
||||
start it, connecting it to your session. If you have multiple different targets
|
||||
with REPLs, the command will start one process for each target from the same
|
||||
command.
|
||||
|
||||
|
|
@ -109,16 +109,16 @@ npm install -g flok-web@latest flok-repl@latest
|
|||
This will download and install the latest Flok web version and start a server.
|
||||
|
||||
Your local server will be available on
|
||||
[http://localhost:3000](http://localhost:3000) from your computer. To share the
|
||||
URL with your friends, change `localhost` with your local LAN IP. `flok-web`
|
||||
[http://localhost:3000](http://localhost:3000) from your computer. To share the
|
||||
URL with your friends, change `localhost` with your local LAN IP. `flok-web`
|
||||
will try to guess your local IP in your LAN, and show it on the console, but it
|
||||
might not always work.
|
||||
|
||||
#### Secure mode (https)
|
||||
|
||||
In some cases, it's needed to run Flok in secure mode, using https. This is
|
||||
In some cases, it's needed to run Flok in secure mode, using https. This is
|
||||
needed for some browsers, like Chrome, to allow access to the microphone and
|
||||
camera (which might be needed for some targets, like Hydra). You can easily
|
||||
camera (which might be needed for some targets, like Hydra). You can easily
|
||||
run Flok in secure mode by passing the `--secure` parameter:
|
||||
|
||||
```sh
|
||||
|
|
@ -128,12 +128,12 @@ npx flok-web@latest --secure
|
|||
#### Note about remote users (not LAN)
|
||||
|
||||
Sharing your local server to other users in the Internet is a bit more
|
||||
complicated, and it depends on your router and network configuration. You will
|
||||
complicated, and it depends on your router and network configuration. You will
|
||||
need to configure your router to forward the port 3000 to your computer, and
|
||||
then share your public IP with your friends. You can find your public IP by
|
||||
visiting [https://whatismyipaddress.com/](https://whatismyipaddress.com/). Also
|
||||
then share your public IP with your friends. You can find your public IP by
|
||||
visiting [https://whatismyipaddress.com/](https://whatismyipaddress.com/). Also
|
||||
make sure to check your firewall settings, to allow incoming connections to
|
||||
port 3000. It's possible that some of your remote friends won't be able to
|
||||
port 3000. It's possible that some of your remote friends won't be able to
|
||||
connect to your local server, because of their own network configuration.
|
||||
|
||||
### Supported REPL targets
|
||||
|
|
@ -149,12 +149,12 @@ object, like this:
|
|||
|
||||
##### Extra options
|
||||
|
||||
* `bootScript`: Path to a custom initialization script.
|
||||
- `bootScript`: Path to a custom initialization script.
|
||||
|
||||
* `useStack`: Uses `stack exec -- ghci` instead of plain `ghci`. Use this if
|
||||
- `useStack`: Uses `stack exec -- ghci` instead of plain `ghci`. Use this if
|
||||
you installed Tidal using Stack.
|
||||
|
||||
* `ghci`: Use a specific Ghci command instead of plain `ghci`.
|
||||
- `ghci`: Use a specific Ghci command instead of plain `ghci`.
|
||||
This overrides `useStack` option, if used too.
|
||||
|
||||
#### Sardine
|
||||
|
|
@ -165,7 +165,7 @@ case if you followed a regular install.
|
|||
|
||||
##### Extra options
|
||||
|
||||
* `python`: Path to your custom `sardine` Python REPL. Use this if you need
|
||||
- `python`: Path to your custom `sardine` Python REPL. Use this if you need
|
||||
to target a specific install of Sardine (Python version, different path, etc).
|
||||
|
||||
#### FoxDot
|
||||
|
|
@ -174,7 +174,7 @@ Use `flok-repl` with the `-t foxdot` parameter.
|
|||
|
||||
##### Extra options
|
||||
|
||||
* `python`: Path to Python binary. Use this if you need to use a custom Python
|
||||
- `python`: Path to Python binary. Use this if you need to use a custom Python
|
||||
version.
|
||||
|
||||
#### Renardo
|
||||
|
|
@ -185,7 +185,7 @@ Use `flok-repl` with the `-t renardo` parameter.
|
|||
|
||||
##### Extra options
|
||||
|
||||
* `python`: Path to Python binary. Use this if you need to use a custom Python
|
||||
- `python`: Path to Python binary. Use this if you need to use a custom Python
|
||||
version.
|
||||
|
||||
#### SuperCollider
|
||||
|
|
@ -193,39 +193,38 @@ Use `flok-repl` with the `-t renardo` parameter.
|
|||
In the case of SuperCollider, there are two types of REPLs: `sclang` and
|
||||
`remote_sclang`. The first one tries to run a `sclang` process and interact
|
||||
with it, while the second one uses
|
||||
[FlokQuark](https://github.com/munshkr/FlokQuark) to communicate with SC. Read
|
||||
[FlokQuark](https://github.com/munshkr/FlokQuark) to communicate with SC. Read
|
||||
[more](https://github.com/munshkr/FlokQuark/blob/master/README.md) for
|
||||
installing and using it.
|
||||
|
||||
|
||||
##### `sclang` vs. `remote_sclang`
|
||||
|
||||
* As of today `sclang` does not currently work on Windows, you will have to use
|
||||
`remote_sclang`.
|
||||
- As of today `sclang` does not currently work on Windows, you will have to use
|
||||
`remote_sclang`.
|
||||
|
||||
* `remote_sclang` needs SC IDE to be running, and you need FlokQuark installed
|
||||
- `remote_sclang` needs SC IDE to be running, and you need FlokQuark installed
|
||||
and running there. Be sure to start your flok-repl with both `-t remote_sclang`
|
||||
and `-n sclang` flags.
|
||||
|
||||
* If you use `remote_sclang`, you won't see Post messages from Flok, because
|
||||
FlokQuark does not currently capture Post messages and errors. It is
|
||||
- If you use `remote_sclang`, you won't see Post messages from Flok, because
|
||||
FlokQuark does not currently capture Post messages and errors. It is
|
||||
recommended to deattach the Post window and have it visible while using Flok.
|
||||
|
||||
* `sclang` can't use any GUI object (like Scopes, Proxy mixers, etc.). You will
|
||||
- `sclang` can't use any GUI object (like Scopes, Proxy mixers, etc.). You will
|
||||
need to use `remote_sclang` + SC IDE for this.
|
||||
|
||||
|
||||
#### Hydra
|
||||
|
||||
[Hydra](https://hydra.ojack.xyz/) is a video synth and coding environment, inspired in
|
||||
analog video synthesis, that runs directly in the browser and is already included in
|
||||
the web App. You don't need to install anything as it runs on the browser. Just use
|
||||
the web App. You don't need to install anything as it runs on the browser. Just use
|
||||
the `hydra` target to execute Hydra code.
|
||||
|
||||
You can also use [p5.js](https://p5js.org/) within a `hydra` target, like you would in
|
||||
the official Hydra editor.
|
||||
|
||||
##### `P()` function
|
||||
|
||||
The `P()` function allows you to use strudel mini-patterns in Hydra.
|
||||
It uses the same timing information as Strudel itself, so it will be synchronized with the audio.
|
||||
|
||||
|
|
@ -256,26 +255,28 @@ fft(index: number,
|
|||
```
|
||||
|
||||
Parameters:
|
||||
|
||||
- `index: number` : The index of the bucket to return the value from.
|
||||
- `buckets: number`: The number of buckets to combine the underlying FFT data
|
||||
too. Defaults to 8.
|
||||
- `options?: { min?: number; max?: number, scale?: number }`:
|
||||
- `min?: number`: Minimum clamp value of the underlying data. Defaults to
|
||||
-150.
|
||||
- `max?: number`: Maximum clamp value of the underlying data. Defaults to 0.
|
||||
- `scale?: number`: Scale of the output. Defaults to 1 (so the output is
|
||||
from 0 to 1)
|
||||
- `analyzerId?: string`: Which Strudel analyser to listen to. Defaults to
|
||||
`flok-master`, which is also automatically added to all strudel patterns.
|
||||
Can be used to route different patterns to different parts of the hydra
|
||||
visualiser
|
||||
- `min?: number`: Minimum clamp value of the underlying data. Defaults to
|
||||
-150.
|
||||
- `max?: number`: Maximum clamp value of the underlying data. Defaults to 0.
|
||||
- `scale?: number`: Scale of the output. Defaults to 1 (so the output is
|
||||
from 0 to 1)
|
||||
- `analyzerId?: string`: Which Strudel analyser to listen to. Defaults to
|
||||
`flok-master`, which is also automatically added to all strudel patterns.
|
||||
Can be used to route different patterns to different parts of the hydra
|
||||
visualiser
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
solid(() => fft(0,1), 0)
|
||||
.mask(shape(5,.05))
|
||||
.rotate(() => 50 * fft(0, 40)) // we need to supply a function
|
||||
// for the parameter, for it to update automaticaly.
|
||||
solid(() => fft(0, 1), 0)
|
||||
.mask(shape(5, 0.05))
|
||||
.rotate(() => 50 * fft(0, 40)); // we need to supply a function
|
||||
// for the parameter, for it to update automaticaly.
|
||||
```
|
||||
|
||||
**Caveat**: Because of how we setup the analyze node on Strudel, every Strudel pane
|
||||
|
|
@ -320,79 +321,79 @@ npm start
|
|||
|
||||
### Packages overview
|
||||
|
||||
This repository is a monorepo, with multiple modular packages. Each package
|
||||
has its own README with more information. Here is a brief overview of the
|
||||
This repository is a monorepo, with multiple modular packages. Each package
|
||||
has its own README with more information. Here is a brief overview of the
|
||||
packages:
|
||||
|
||||
#### App packages
|
||||
|
||||
* [`flok-web`](packages/web): Web Server for Flok
|
||||
* [`flok-repl`](packages/repl): REPL Client for Flok
|
||||
* [`flok-server`](packages/server): Flok server, handles sessions and
|
||||
- [`flok-web`](packages/web): Web Server for Flok
|
||||
- [`flok-repl`](packages/repl): REPL Client for Flok
|
||||
- [`flok-server`](packages/server): Flok server, handles sessions and
|
||||
communication between clients.
|
||||
|
||||
#### Lib packages
|
||||
|
||||
* [`@flok-editor/pubsub`](packages/pubsub): Pub/Sub client-server, used for
|
||||
- [`@flok-editor/pubsub`](packages/pubsub): Pub/Sub client-server, used for
|
||||
remote code execution and message passing on Flok
|
||||
* [`@flok-editor/session`](packages/session): Flok session package
|
||||
* [`@flok-editor/server-middleware`](packages/server-middleware): Server
|
||||
- [`@flok-editor/session`](packages/session): Flok session package
|
||||
- [`@flok-editor/server-middleware`](packages/server-middleware): Server
|
||||
middleware for Flok, handles WebSocket connections and WebRTC signaling
|
||||
* [`@flok-editor/cm-eval`](packages/cm-eval): CodeMirror 6 extension for code
|
||||
- [`@flok-editor/cm-eval`](packages/cm-eval): CodeMirror 6 extension for code
|
||||
evaluation
|
||||
* [`@flok-editor/lang-tidal`](packages/lang-tidal): TidalCycles language support
|
||||
- [`@flok-editor/lang-tidal`](packages/lang-tidal): TidalCycles language support
|
||||
for CodeMirror 6
|
||||
|
||||
#### Examples
|
||||
|
||||
* [`example-vanilla-js`](packages/example-vanilla-js): Example of a Flok-based
|
||||
- [`example-vanilla-js`](packages/example-vanilla-js): Example of a Flok-based
|
||||
collaborative editor written in pure JS and Vite
|
||||
|
||||
### Design constraints (v1.0)
|
||||
|
||||
* Include a simplified vanilla JS example
|
||||
* Use [CodeMirror 6](https://codemirror.net/)
|
||||
* Best code editor library for the Web
|
||||
* Latest version (v6) comes with better extensibility and accesability
|
||||
* Use [Yjs](https://yjs.dev/) for collaborative editor
|
||||
* Battle-tested and updated
|
||||
* Now supports CodeMirror 6:
|
||||
[y-codemirror.next](https://github.com/yjs/y-codemirror.next)
|
||||
* More modular and extensible, similar to CodeMirror extensions, e.g.:
|
||||
* Line/block-based evaluation: `@flok-editor/cm-eval`
|
||||
* TidalCycles pattern and RMS decorators: `@flok-editor/cm-tidalcycles-decorators`
|
||||
* TidalCycles autocompletion: `@flok-editor/cm-tidalcycles-autocompletion`
|
||||
* Hydra synth autocompletion: `@flok-editor/cm-hydra-autocompletion`
|
||||
* Better UI for customizing editor and session configuration
|
||||
* Menu, toast, dialogs
|
||||
* *nice to have* Import external JS libraries dynamically, instead of bundling
|
||||
- Include a simplified vanilla JS example
|
||||
- Use [CodeMirror 6](https://codemirror.net/)
|
||||
- Best code editor library for the Web
|
||||
- Latest version (v6) comes with better extensibility and accesability
|
||||
- Use [Yjs](https://yjs.dev/) for collaborative editor
|
||||
- Battle-tested and updated
|
||||
- Now supports CodeMirror 6:
|
||||
[y-codemirror.next](https://github.com/yjs/y-codemirror.next)
|
||||
- More modular and extensible, similar to CodeMirror extensions, e.g.:
|
||||
- Line/block-based evaluation: `@flok-editor/cm-eval`
|
||||
- TidalCycles pattern and RMS decorators: `@flok-editor/cm-tidalcycles-decorators`
|
||||
- TidalCycles autocompletion: `@flok-editor/cm-tidalcycles-autocompletion`
|
||||
- Hydra synth autocompletion: `@flok-editor/cm-hydra-autocompletion`
|
||||
- Better UI for customizing editor and session configuration
|
||||
- Menu, toast, dialogs
|
||||
- _nice to have_ Import external JS libraries dynamically, instead of bundling
|
||||
them with Flok
|
||||
* Similar to JS playgrounds, like [codesandbox.io](https://codesandbox.io/)
|
||||
* User can have their own set of libraries to be loaded automatically or
|
||||
easily on new sketches
|
||||
* Connect to local filesystem for files and libraries
|
||||
- Similar to JS playgrounds, like [codesandbox.io](https://codesandbox.io/)
|
||||
- User can have their own set of libraries to be loaded automatically or
|
||||
easily on new sketches
|
||||
- Connect to local filesystem for files and libraries
|
||||
|
||||
### Hash parameters
|
||||
|
||||
* `username` (string): Default user name. Eg: `#username=arbor`
|
||||
* `targets` (list of strings): If session is empty, configure it with the
|
||||
- `username` (string): Default user name. Eg: `#username=arbor`
|
||||
- `targets` (list of strings): If session is empty, configure it with the
|
||||
specified targets by default. Eg: `#targets=hydra,strudel`
|
||||
* `c0`, `c1`, ..., `c7` (string): Default code to load on each document/pane
|
||||
- `c0`, `c1`, ..., `c7` (string): Default code to load on each document/pane
|
||||
(if available). **Code must be encoded in Base64**. Eg:
|
||||
`#c0=bm9pc2UoKS5vdXQoKQ%253D%253D` (decodes to `noise().out()`).
|
||||
* `code` (string): An alias of `c0` (see above)
|
||||
- `code` (string): An alias of `c0` (see above)
|
||||
|
||||
### Query parameters
|
||||
|
||||
* `readOnly` (boolean): Disable editing. If true, it won't ask for a user name
|
||||
- `readOnly` (boolean): Disable editing. If true, it won't ask for a user name
|
||||
when loading.
|
||||
* `bgOpacity` (number): Background opacity. Valid range: [0, 1]
|
||||
* `noWebEval` (list of strings): Disable evaluation of the specified web
|
||||
- `bgOpacity` (number): Background opacity. Valid range: [0, 1]
|
||||
- `noWebEval` (list of strings): Disable evaluation of the specified web
|
||||
targets. Useful for embedding Flok in a website, where the website already has
|
||||
its own evaluation mechanism. This still sends messages to parent window.
|
||||
Options: `*`, `[webTarget]`. Eg: `?noWebEval=hydra` disables only Hydra.
|
||||
`?noWebEval=*` disables all web targets.
|
||||
* `hideErrors` (boolean): Do not show errors for web targets (hydra, strudel, etc)
|
||||
- `hideErrors` (boolean): Do not show errors for web targets (hydra, strudel, etc)
|
||||
|
||||
### Window messages
|
||||
|
||||
|
|
@ -402,7 +403,7 @@ the code.
|
|||
|
||||
#### Events
|
||||
|
||||
* `change`: When the session changes. This usually happens at the beginning,
|
||||
- `change`: When the session changes. This usually happens at the beginning,
|
||||
when the session is empty, and when the user changes the targets.
|
||||
|
||||
```json
|
||||
|
|
@ -423,9 +424,9 @@ the code.
|
|||
}
|
||||
```
|
||||
|
||||
* `eval`: On evaluation. This happens when the user presses the "Run" button or
|
||||
- `eval`: On evaluation. This happens when the user presses the "Run" button or
|
||||
when the user presses one of the shortcuts for evaluating (e.g. `Ctrl+Enter`)
|
||||
on the editor. Only the content of the document that was evaluated is sent.
|
||||
on the editor. Only the content of the document that was evaluated is sent.
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -438,10 +439,9 @@ the code.
|
|||
|
||||
## Acknowledgments
|
||||
|
||||
* [Etherpad](https://github.com/ether/etherpad-lite)
|
||||
* [Troop](https://github.com/Qirky/Troop)
|
||||
* [TidalBridge](https://gitlab.com/colectivo-de-livecoders/tidal-bridge)
|
||||
|
||||
- [Etherpad](https://github.com/ether/etherpad-lite)
|
||||
- [Troop](https://github.com/Qirky/Troop)
|
||||
- [TidalBridge](https://gitlab.com/colectivo-de-livecoders/tidal-bridge)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
@ -450,7 +450,6 @@ page](https://github.com/munshkr/flok). This project is intended to be a safe,
|
|||
welcoming space for collaboration, and contributors are expected to adhere to
|
||||
the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under GPL 3+. Refer to [LICENSE.txt](LICENSE.txt)
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export function getBlock(state: EditorState): EvalBlock {
|
|||
export const evaluateBlockOrSelection = (
|
||||
view: EditorView,
|
||||
doc: Document,
|
||||
web: boolean = false
|
||||
web: boolean = false,
|
||||
) => {
|
||||
const { state } = view;
|
||||
const selection = getSelection(state);
|
||||
|
|
@ -71,7 +71,7 @@ export const evaluateBlockOrSelection = (
|
|||
export const evaluateLine = (
|
||||
view: EditorView,
|
||||
doc: Document,
|
||||
web: boolean = false
|
||||
web: boolean = false,
|
||||
) => {
|
||||
const { state } = view;
|
||||
const { text, from, to } = getLine(state);
|
||||
|
|
@ -82,7 +82,7 @@ export const evaluateLine = (
|
|||
export const evaluateDocument = (
|
||||
view: EditorView,
|
||||
doc: Document,
|
||||
web: boolean = false
|
||||
web: boolean = false,
|
||||
) => {
|
||||
const { state } = view;
|
||||
const { from } = state.doc.line(1);
|
||||
|
|
@ -106,7 +106,7 @@ export function evalKeymap(
|
|||
documentEvalKeys?: string[];
|
||||
defaultMode?: "block" | "document";
|
||||
web?: boolean;
|
||||
} = {}
|
||||
} = {},
|
||||
) {
|
||||
return keymap.of([
|
||||
...defaultEvalKeys.map((key) => ({
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const flash = (
|
|||
view: EditorView,
|
||||
from: number | null,
|
||||
to: number | null,
|
||||
timeout: number = 150
|
||||
timeout: number = 150,
|
||||
) => {
|
||||
if (from === null || to === null) return;
|
||||
view.dispatch({ effects: setFlash.of([from, to]) });
|
||||
|
|
|
|||
|
|
@ -21,5 +21,5 @@ export const remoteEvalFlash = (document: Document) =>
|
|||
destroy() {
|
||||
document.session.off("eval", this._handleEval);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,37 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@flok-editor/codemirror example</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@flok-editor/codemirror example</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="slots">
|
||||
<div class="slot" id="slot1">
|
||||
<select class="target">
|
||||
<option value="tidal">tidal</option>
|
||||
<option value="hydra">hydra</option>
|
||||
<option value="foxdot">foxdot</option>
|
||||
<option value="renardo">renardo</option>
|
||||
</select>
|
||||
<div class="editor"></div>
|
||||
</div>
|
||||
|
||||
<body>
|
||||
<div class="slots">
|
||||
<div class="slot" id="slot1">
|
||||
<select class="target">
|
||||
<option value="tidal">tidal</option>
|
||||
<option value="hydra">hydra</option>
|
||||
<option value="foxdot">foxdot</option>
|
||||
<option value="renardo">renardo</option>
|
||||
</select>
|
||||
<div class="editor"></div>
|
||||
<div class="slot" id="slot2">
|
||||
<select class="target">
|
||||
<option value="tidal">tidal</option>
|
||||
<option value="hydra">hydra</option>
|
||||
<option value="foxdot">foxdot</option>
|
||||
<option value="renardo">renardo</option>
|
||||
</select>
|
||||
<div class="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="slot" id="slot2">
|
||||
<select class="target">
|
||||
<option value="tidal">tidal</option>
|
||||
<option value="hydra">hydra</option>
|
||||
<option value="foxdot">foxdot</option>
|
||||
<option value="renardo">renardo</option>
|
||||
</select>
|
||||
<div class="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const flokBasicSetup = (doc) => {
|
|||
const text = doc.getText();
|
||||
const undoManager = new UndoManager(text);
|
||||
// if target is hydra, use "web" mode to evaluate on browser only, not REPLs
|
||||
const web = doc.target === "hydra"
|
||||
const web = doc.target === "hydra";
|
||||
|
||||
return [
|
||||
flashField(),
|
||||
|
|
@ -23,7 +23,7 @@ const flokBasicSetup = (doc) => {
|
|||
];
|
||||
};
|
||||
|
||||
const createEditor = doc => {
|
||||
const createEditor = (doc) => {
|
||||
const state = EditorState.create({
|
||||
doc: doc.content,
|
||||
extensions: [
|
||||
|
|
@ -46,10 +46,10 @@ const createEditor = doc => {
|
|||
|
||||
targetEl.addEventListener("change", (e) => {
|
||||
doc.target = e.target.value;
|
||||
})
|
||||
});
|
||||
doc.session.on(`change-target:${doc.id}`, () => {
|
||||
targetEl.value = doc.target;
|
||||
})
|
||||
});
|
||||
|
||||
return [state, view];
|
||||
};
|
||||
|
|
@ -64,7 +64,7 @@ const handleEvalHydra = (msg) => {
|
|||
};
|
||||
|
||||
const session = new Session("default", { port: 3000 });
|
||||
window.session = session
|
||||
window.session = session;
|
||||
|
||||
session.on("change", (...args) => console.log("change", ...args));
|
||||
session.on("message", handleMessage);
|
||||
|
|
@ -76,11 +76,11 @@ session.on("sync", () => {
|
|||
session.setActiveDocuments([
|
||||
{ id: "slot1", target: "tidal" },
|
||||
{ id: "slot2", target: "hydra" },
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
// Create editors for each document
|
||||
session.getDocuments().map(doc => createEditor(doc))
|
||||
})
|
||||
session.getDocuments().map((doc) => createEditor(doc));
|
||||
});
|
||||
|
||||
session.initialize();
|
||||
|
|
|
|||
|
|
@ -4,23 +4,23 @@ This is an example repository containing a minimal
|
|||
[CodeMirror](https://codemirror.net/6/) language support package. The idea is to
|
||||
clone it, rename it, and edit it to create support for a new language.
|
||||
|
||||
Things you'll need to do (see the [language support example](https://codemirror.net/6/examples/lang-package/)
|
||||
Things you'll need to do (see the [language support example](https://codemirror.net/6/examples/lang-package/)
|
||||
for a more detailed tutorial):
|
||||
|
||||
* `git grep EXAMPLE` and replace all instances with your language name.
|
||||
- `git grep EXAMPLE` and replace all instances with your language name.
|
||||
|
||||
* Rewrite the grammar in `src/syntax.grammar` to cover your language. See the
|
||||
[Lezer system guide](https://lezer.codemirror.net/docs/guide/#writing-a-grammar)
|
||||
for information on this file format.
|
||||
- Rewrite the grammar in `src/syntax.grammar` to cover your language. See the
|
||||
[Lezer system guide](https://lezer.codemirror.net/docs/guide/#writing-a-grammar)
|
||||
for information on this file format.
|
||||
|
||||
* Adjust the metadata in `src/index.ts` to work with your new grammar.
|
||||
- Adjust the metadata in `src/index.ts` to work with your new grammar.
|
||||
|
||||
* Adjust the grammar tests in `test/cases.txt`.
|
||||
- Adjust the grammar tests in `test/cases.txt`.
|
||||
|
||||
* Build (`npm run prepare`) and test (`npm test`).
|
||||
- Build (`npm run prepare`) and test (`npm test`).
|
||||
|
||||
* Rewrite this readme file.
|
||||
- Rewrite this readme file.
|
||||
|
||||
* Optionally add a license.
|
||||
- Optionally add a license.
|
||||
|
||||
* Publish. Put your package on npm under a name like `codemirror-lang-EXAMPLE`.
|
||||
- Publish. Put your package on npm under a name like `codemirror-lang-EXAMPLE`.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import typescript from "rollup-plugin-ts"
|
||||
import { lezer } from "@lezer/generator/rollup"
|
||||
import typescript from "rollup-plugin-ts";
|
||||
import { lezer } from "@lezer/generator/rollup";
|
||||
|
||||
export default {
|
||||
input: "src/index.ts",
|
||||
external: id => id != "tslib" && !/^(\.?\/|\w:)/.test(id),
|
||||
external: (id) => id != "tslib" && !/^(\.?\/|\w:)/.test(id),
|
||||
output: [
|
||||
{ file: "dist/index.cjs", format: "cjs" },
|
||||
{ dir: "./dist", format: "es" }
|
||||
{ dir: "./dist", format: "es" },
|
||||
],
|
||||
plugins: [lezer(), typescript()]
|
||||
}
|
||||
plugins: [lezer(), typescript()],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { haskell } from "@codemirror/legacy-modes/mode/haskell";
|
||||
|
||||
export const tidalLanguage = {
|
||||
...haskell,
|
||||
name: "tidal",
|
||||
languageData: {
|
||||
...haskell.languageData,
|
||||
closeBrackets: {brackets: ["(", "[", "{", "<", '"'], before: ')]}>"'}
|
||||
}
|
||||
}
|
||||
...haskell,
|
||||
name: "tidal",
|
||||
languageData: {
|
||||
...haskell.languageData,
|
||||
closeBrackets: { brackets: ["(", "[", "{", "<", '"'], before: ')]}>"' },
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ message passing in Flok.
|
|||
|
||||
## Features
|
||||
|
||||
* Basic Publish/Subscribe functionality: `subscribe`, `unsubscribe`, `publish`,
|
||||
- Basic Publish/Subscribe functionality: `subscribe`, `unsubscribe`, `publish`,
|
||||
`unsubscribeAll`.
|
||||
* Payload is JSON serialized, topics are any string.
|
||||
* Allows subscribing or unsubscribing without being connected by storing state
|
||||
- Payload is JSON serialized, topics are any string.
|
||||
- Allows subscribing or unsubscribing without being connected by storing state
|
||||
on the client.
|
||||
* Automatically reconnects if connection is lost, recovering client's state.
|
||||
* Ping/pong mechanism for detecting and closing broken connections both on
|
||||
- Automatically reconnects if connection is lost, recovering client's state.
|
||||
- Ping/pong mechanism for detecting and closing broken connections both on
|
||||
client and server.
|
||||
|
||||
## Usage
|
||||
|
|
@ -19,21 +19,21 @@ message passing in Flok.
|
|||
### Server
|
||||
|
||||
```js
|
||||
import { WebSocketServer } from "ws"
|
||||
import { PubSubServer } from "@flok-editor/pubsub"
|
||||
import { WebSocketServer } from "ws";
|
||||
import { PubSubServer } from "@flok-editor/pubsub";
|
||||
|
||||
// To use the server, you need to create a `WebSocketServer` and pass it to
|
||||
// `PubSubServer`.
|
||||
const wss = new WebSocketServer({ port: 4000 });
|
||||
const server = new PubSubServer({ wss });
|
||||
|
||||
console.log(`PubSub server listening on`, wss.address())
|
||||
console.log(`PubSub server listening on`, wss.address());
|
||||
```
|
||||
|
||||
### Client
|
||||
|
||||
```js
|
||||
import { PubSubClient } from "@flok-editor/pubsub"
|
||||
import { PubSubClient } from "@flok-editor/pubsub";
|
||||
|
||||
const client = new PubSubClient({ url: "ws://localhost:4000" });
|
||||
|
||||
|
|
@ -48,31 +48,31 @@ let internalId;
|
|||
client.on("open", () => {
|
||||
// Publish a message (any JSON serializable object) to a topic
|
||||
internalId = setInterval(() => {
|
||||
client.publish("a", { salutation: "hello!" })
|
||||
client.publish("a", { salutation: "hello!" });
|
||||
}, 2000);
|
||||
})
|
||||
});
|
||||
|
||||
// Add an error event handler to ignore connection errors
|
||||
client.on("error", () => { });
|
||||
client.on("error", () => {});
|
||||
|
||||
client.on("close", () => clearInterval(internalId))
|
||||
client.on("close", () => clearInterval(internalId));
|
||||
|
||||
setTimeout(() => {
|
||||
// Unsubscribe from a topic
|
||||
client.unsubscribe("b");
|
||||
// ... or from all topics with a single call
|
||||
client.unsubscribeAll();
|
||||
}, 5000)
|
||||
}, 5000);
|
||||
|
||||
// you can add a listener for all message events
|
||||
client.on("message", (topic, data) => {
|
||||
console.log("message", topic, data)
|
||||
})
|
||||
console.log("message", topic, data);
|
||||
});
|
||||
|
||||
// ...or only from a specific topic
|
||||
client.on("message:a", (data) => {
|
||||
console.log("message from topic 'a'", data)
|
||||
})
|
||||
console.log("message from topic 'a'", data);
|
||||
});
|
||||
|
||||
// Finally, you can subscribe and listen to messages in a single call
|
||||
client.subscribe("c", (data) => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { PubSubClient } from "../dist/index.js"
|
||||
import { PubSubClient } from "../dist/index.js";
|
||||
|
||||
const client = new PubSubClient({ url: "ws://localhost:4000" });
|
||||
|
||||
|
|
@ -13,28 +13,28 @@ let internalId;
|
|||
client.on("open", () => {
|
||||
// Publish a message (any JSON serializable object) to a topic
|
||||
internalId = setInterval(() => {
|
||||
client.publish("a", { salutation: "hello!" })
|
||||
client.publish("a", { salutation: "hello!" });
|
||||
}, 2000);
|
||||
})
|
||||
});
|
||||
|
||||
// Add an error event handler to ignore connection errors
|
||||
client.on("error", () => { });
|
||||
client.on("error", () => {});
|
||||
|
||||
client.on("close", () => clearInterval(internalId))
|
||||
client.on("close", () => clearInterval(internalId));
|
||||
|
||||
setTimeout(() => {
|
||||
// Unsubscribe from a topic
|
||||
client.unsubscribe("b");
|
||||
// ... or from all topics with a single call
|
||||
client.unsubscribeAll();
|
||||
}, 5000)
|
||||
}, 5000);
|
||||
|
||||
// you can add a listener for all message events
|
||||
client.on("message", (topic, data) => {
|
||||
console.log("message", topic, data)
|
||||
})
|
||||
console.log("message", topic, data);
|
||||
});
|
||||
|
||||
// ...or only from a specific topic
|
||||
client.on("message:a", (data) => {
|
||||
console.log("message from topic 'a'", data)
|
||||
})
|
||||
console.log("message from topic 'a'", data);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { WebSocketServer } from "ws"
|
||||
import { PubSubServer } from "../dist/server.js"
|
||||
import { WebSocketServer } from "ws";
|
||||
import { PubSubServer } from "../dist/server.js";
|
||||
|
||||
const wss = new WebSocketServer({ port: 4000 });
|
||||
const server = new PubSubServer({ wss });
|
||||
|
||||
console.log(`PubSub server listening on`, wss.address())
|
||||
console.log(`PubSub server listening on`, wss.address());
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ export class PubSubClient {
|
|||
protected _send(
|
||||
type: ClientMessageType,
|
||||
payload?: any,
|
||||
cb?: (err?: Error) => void
|
||||
cb?: (err?: Error) => void,
|
||||
) {
|
||||
const data = JSON.stringify({ type, payload });
|
||||
this._ws.send(data, (err?: Error) => {
|
||||
|
|
|
|||
|
|
@ -21,15 +21,16 @@ const readConfig = (path) => {
|
|||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const packageInfo = readConfig(path.resolve(__dirname, "../package.json"));
|
||||
const knownTypes = ["command", ...Object.keys(replClasses).filter(
|
||||
(repl) => repl !== "default"
|
||||
)];
|
||||
const knownTypes = [
|
||||
"command",
|
||||
...Object.keys(replClasses).filter((repl) => repl !== "default"),
|
||||
];
|
||||
const program = new Command();
|
||||
|
||||
program.version(packageInfo.version);
|
||||
program
|
||||
.option("-t, --types <types...>", "Type/s of REPL", ["command"])
|
||||
.option("-H, --hub <url>", "Server (or \"hub\") address", "ws://localhost:3000")
|
||||
.option("-H, --hub <url>", 'Server (or "hub") address', "ws://localhost:3000")
|
||||
.option("-s, --session-name <name>", "Session name", "default")
|
||||
.option("-n, --target-name <name>", "Use the specified target name")
|
||||
.option("-T, --tags <tags...>", "Tags for REPL messages")
|
||||
|
|
@ -46,25 +47,12 @@ const configPath = opts.config || process.env.FLOK_CONFIG;
|
|||
const config = configPath ? readConfig(configPath) : {};
|
||||
|
||||
// Override config with command line options
|
||||
const options = [
|
||||
"types",
|
||||
"hub",
|
||||
"sessionName",
|
||||
"targetName",
|
||||
"tags",
|
||||
"path",
|
||||
];
|
||||
options.forEach(opt => {
|
||||
const options = ["types", "hub", "sessionName", "targetName", "tags", "path"];
|
||||
options.forEach((opt) => {
|
||||
config[opt] = config[opt] || opts[opt];
|
||||
});
|
||||
|
||||
const {
|
||||
hub,
|
||||
sessionName,
|
||||
targetName,
|
||||
tags,
|
||||
path: pubSubPath,
|
||||
} = config;
|
||||
const { hub, sessionName, targetName, tags, path: pubSubPath } = config;
|
||||
|
||||
// Remove duplicates
|
||||
const types = [...new Set(config.types)];
|
||||
|
|
@ -79,20 +67,27 @@ if (opts.listTypes) {
|
|||
process.exit(0);
|
||||
}
|
||||
|
||||
const useDefaultREPL = types.some(type => type === "command");
|
||||
const useDefaultREPL = types.some((type) => type === "command");
|
||||
|
||||
// If using default REPL and no command was specified, throw error
|
||||
if (useDefaultREPL && !cmd) {
|
||||
console.error("You specified a 'command' type, but forgot to specify a REPL command (e.g.: flok-repl -- cat)");
|
||||
console.error(
|
||||
"You specified a 'command' type, but forgot to specify a REPL command (e.g.: flok-repl -- cat)",
|
||||
);
|
||||
program.outputHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check if all types are known
|
||||
if (!useDefaultREPL) {
|
||||
const unknownTypes = [...new Set(types.filter(type => !knownTypes.includes(type)))];
|
||||
const unknownTypes = [
|
||||
...new Set(types.filter((type) => !knownTypes.includes(type))),
|
||||
];
|
||||
if (unknownTypes.length > 0) {
|
||||
console.error(`Unknown types: ${unknownTypes.join(', ')}. Must be one of:`, knownTypes);
|
||||
console.error(
|
||||
`Unknown types: ${unknownTypes.join(", ")}. Must be one of:`,
|
||||
knownTypes,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -114,9 +109,10 @@ console.log("Hub address:", hub);
|
|||
console.log("Session name:", sessionName);
|
||||
if (targetName) console.log("Target name:", targetName);
|
||||
console.log("Types:", types);
|
||||
if (Object.keys(extraOptions).length > 0) console.log("Extra options:", extraOptions);
|
||||
if (Object.keys(extraOptions).length > 0)
|
||||
console.log("Extra options:", extraOptions);
|
||||
|
||||
types.forEach(type => {
|
||||
types.forEach((type) => {
|
||||
const useDefaultREPL = type === "command";
|
||||
|
||||
// Set target based on name or type
|
||||
|
|
@ -164,4 +160,4 @@ types.forEach(type => {
|
|||
replClient.emitter.on("close", ({ code }) => {
|
||||
process.exit(code);
|
||||
});
|
||||
})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ function createREPLFor(repl: string, ctx: CommandREPLContext) {
|
|||
function readPackageMetadata() {
|
||||
const packageJsonPath = path.resolve(
|
||||
__dirname,
|
||||
path.join("..", "package.json")
|
||||
path.join("..", "package.json"),
|
||||
);
|
||||
const rawBody = fs.readFileSync(packageJsonPath);
|
||||
const body = JSON.parse(rawBody.toString());
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ abstract class BaseREPL {
|
|||
({ message }: { message: Message }) => {
|
||||
const { body } = message;
|
||||
this.write(body);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class TidalREPL extends CommandREPL {
|
|||
debug(`Failed to get tidal data dir`);
|
||||
debug(
|
||||
`You will need to specify the location of your TidalCycles bootloading script.\n` +
|
||||
`Read more: https://github.com/munshkr/flok/wiki/Failed-to-get-tidal-data-dir`
|
||||
`Read more: https://github.com/munshkr/flok/wiki/Failed-to-get-tidal-data-dir`,
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,13 +57,13 @@ export default (conn: any, topics: Map<string, Set<any>>) => {
|
|||
const topic = map.setIfUndefined(
|
||||
topics,
|
||||
topicName,
|
||||
() => new Set()
|
||||
() => new Set(),
|
||||
);
|
||||
topic.add(conn);
|
||||
// add topic to conn
|
||||
subscribedTopics.add(topicName);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
break;
|
||||
case "unsubscribe":
|
||||
|
|
@ -73,7 +73,7 @@ export default (conn: any, topics: Map<string, Set<any>>) => {
|
|||
if (subs) {
|
||||
subs.delete(conn);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
break;
|
||||
case "publish":
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const setPersistence = (
|
|||
persistence_: {
|
||||
bindState: (arg0: string, arg1: WSSharedDoc) => void;
|
||||
writeState: (arg0: string, arg1: WSSharedDoc) => Promise<any>;
|
||||
} | null
|
||||
} | null,
|
||||
) => {
|
||||
persistence = persistence_;
|
||||
};
|
||||
|
|
@ -75,7 +75,7 @@ export class WSSharedDoc extends Doc {
|
|||
updated,
|
||||
removed,
|
||||
}: { added: number[]; updated: number[]; removed: number[] },
|
||||
conn: any
|
||||
conn: any,
|
||||
) => {
|
||||
const changedClients = added.concat(updated, removed);
|
||||
if (conn !== null) {
|
||||
|
|
@ -95,7 +95,7 @@ export class WSSharedDoc extends Doc {
|
|||
encoding.writeVarUint(encoder, messageAwareness);
|
||||
encoding.writeVarUint8Array(
|
||||
encoder,
|
||||
awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients)
|
||||
awarenessProtocol.encodeAwarenessUpdate(this.awareness, changedClients),
|
||||
);
|
||||
const buff = encoding.toUint8Array(encoder);
|
||||
this.conns.forEach((_, c) => {
|
||||
|
|
@ -123,7 +123,7 @@ const messageListener = (conn: any, doc: WSSharedDoc, message: Uint8Array) => {
|
|||
awarenessProtocol.applyAwarenessUpdate(
|
||||
doc.awareness,
|
||||
decoding.readVarUint8Array(decoder),
|
||||
conn
|
||||
conn,
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
|
@ -137,7 +137,7 @@ const closeConn = (doc: WSSharedDoc, conn: any) => {
|
|||
awarenessProtocol.removeAwarenessStates(
|
||||
doc.awareness,
|
||||
Array.from(controlledIds),
|
||||
null
|
||||
null,
|
||||
);
|
||||
if (doc.conns.size === 0 && persistence !== null) {
|
||||
// if persisted, we store state and destroy ydocument
|
||||
|
|
@ -162,7 +162,7 @@ const send = (doc: WSSharedDoc, conn: any, m: Uint8Array) => {
|
|||
m,
|
||||
/** @param {any} err */ (err) => {
|
||||
err != null && closeConn(doc, conn);
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
closeConn(doc, conn);
|
||||
|
|
@ -174,7 +174,7 @@ const pingTimeout = 30000;
|
|||
export const setupWSConnection = (
|
||||
conn: WebSocket,
|
||||
req: http.IncomingMessage,
|
||||
{ docName = req.url.slice(1).split("?")[0], gc = true }: any = {}
|
||||
{ docName = req.url.slice(1).split("?")[0], gc = true }: any = {},
|
||||
) => {
|
||||
conn.binaryType = "arraybuffer";
|
||||
// get doc, create if it does not exist yet
|
||||
|
|
@ -190,7 +190,7 @@ export const setupWSConnection = (
|
|||
doc.conns.set(conn, new Set());
|
||||
// listen and reply to events
|
||||
conn.on("message", (message: ArrayBuffer) =>
|
||||
messageListener(conn, doc, new Uint8Array(message))
|
||||
messageListener(conn, doc, new Uint8Array(message)),
|
||||
);
|
||||
conn.on("close", () => {
|
||||
closeConn(doc, conn);
|
||||
|
|
@ -228,8 +228,8 @@ export const setupWSConnection = (
|
|||
encoder,
|
||||
awarenessProtocol.encodeAwarenessUpdate(
|
||||
doc.awareness,
|
||||
Array.from(awarenessStates.keys())
|
||||
)
|
||||
Array.from(awarenessStates.keys()),
|
||||
),
|
||||
);
|
||||
send(doc, conn, encoding.toUint8Array(encoder));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ export class Session {
|
|||
|
||||
// Remove duplicates on items (duplicate ids) by creating an object/map
|
||||
const newTargets = Object.fromEntries(
|
||||
items.map(({ id, target }) => [id, target])
|
||||
items.map(({ id, target }) => [id, target]),
|
||||
);
|
||||
|
||||
// Calculate ids to delete and ids to create
|
||||
|
|
@ -151,7 +151,7 @@ export class Session {
|
|||
const oldIds = Array.from(targets.keys());
|
||||
const toDelete = oldIds.filter((id) => !newIds.includes(id));
|
||||
const toAddOrUpdate = newIds.filter(
|
||||
(id) => !oldIds.includes(id) || oldTargets[id] !== newTargets[id]
|
||||
(id) => !oldIds.includes(id) || oldTargets[id] !== newTargets[id],
|
||||
);
|
||||
debug("toDelete", toDelete);
|
||||
debug("toAddOrUpdate", toAddOrUpdate);
|
||||
|
|
@ -164,7 +164,7 @@ export class Session {
|
|||
|
||||
getDocuments(): Document[] {
|
||||
return Array.from(this._yTargets().keys()).map(
|
||||
(id) => new Document(this, id)
|
||||
(id) => new Document(this, id),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +203,7 @@ export class Session {
|
|||
target: string,
|
||||
body: string,
|
||||
context: EvalContext,
|
||||
mode: EvalMode = "default"
|
||||
mode: EvalMode = "default",
|
||||
) {
|
||||
const msg: EvalMessage = {
|
||||
docId,
|
||||
|
|
@ -223,7 +223,7 @@ export class Session {
|
|||
if (mode !== "webLocal") {
|
||||
this._pubSubClient.publish(
|
||||
`session:${this.name}:target:${target}:eval`,
|
||||
msg
|
||||
msg,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -247,7 +247,7 @@ export class Session {
|
|||
destroy() {
|
||||
this.removeAllListeners();
|
||||
["error", "open", "close"].forEach((e) =>
|
||||
this._pubSubClient.removeAllListeners(e)
|
||||
this._pubSubClient.removeAllListeners(e),
|
||||
);
|
||||
this._synced = false;
|
||||
this._initialized = false;
|
||||
|
|
@ -314,7 +314,7 @@ export class Session {
|
|||
`${this.wsUrl}/doc`,
|
||||
this.name,
|
||||
this.yDoc,
|
||||
{ awareness: this.awareness }
|
||||
{ awareness: this.awareness },
|
||||
);
|
||||
this._wsProvider.on("synced", () => {
|
||||
if (!this._synced) {
|
||||
|
|
@ -381,9 +381,9 @@ export class Session {
|
|||
// Notify to flok-repls
|
||||
this._pubSubClient.publish(
|
||||
`session:${this.name}:target:${target}:in`,
|
||||
message
|
||||
message,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this._pubSubClient.subscribe(
|
||||
|
|
@ -392,7 +392,7 @@ export class Session {
|
|||
debug(`session:${this.name}:target:${target}:out`, args);
|
||||
this._emitter.emit(`message`, args);
|
||||
this._emitter.emit(`message:${target}`, args);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// Subscribes to messages directed to ourselves
|
||||
|
|
@ -401,11 +401,11 @@ export class Session {
|
|||
(args) => {
|
||||
debug(
|
||||
`session:${this.name}:target:${target}:user:${this.user}:out`,
|
||||
args
|
||||
args,
|
||||
);
|
||||
this._emitter.emit(`message`, args);
|
||||
this._emitter.emit(`message:${target}`, args);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +438,7 @@ export class Session {
|
|||
const newValue = ymap.get(key);
|
||||
debug(
|
||||
`Document "${key}" was added or updated. New target: "${newValue}". ` +
|
||||
`Previous target: "${change.oldValue}".`
|
||||
`Previous target: "${change.oldValue}".`,
|
||||
);
|
||||
debug(`Subscribe to ${newValue}`);
|
||||
this._subscribeToTarget(newValue);
|
||||
|
|
|
|||
|
|
@ -43,5 +43,5 @@ startServer({
|
|||
secure: opts.secure,
|
||||
sslCert: opts.sslCert,
|
||||
sslKey: opts.sslKey,
|
||||
staticDir: opts.staticDir
|
||||
})
|
||||
staticDir: opts.staticDir,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/flok.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web-based P2P collaborative editor for live coding sounds and images"
|
||||
/>
|
||||
<title>Flok</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/flok.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="Web-based P2P collaborative editor for live coding sounds and images" />
|
||||
<title>Flok</title>
|
||||
</head>
|
||||
|
||||
<body class="min-h-screen font-sans antialiased overscroll-none overflow-hidden text-slate-50">
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
|
||||
<body
|
||||
class="min-h-screen font-sans antialiased overscroll-none overflow-hidden text-slate-50"
|
||||
>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ module.exports = {
|
|||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
// do some pre-build tasks like copying files, etc. that are required for the
|
||||
// build process.
|
||||
|
||||
import { existsSync, mkdirSync, readdirSync, copyFileSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { resolve, dirname } from 'path';
|
||||
import { existsSync, mkdirSync, readdirSync, copyFileSync } from "fs";
|
||||
import { fileURLToPath } from "url";
|
||||
import { resolve, dirname } from "path";
|
||||
|
||||
// Strudel
|
||||
// * mkdir -p public/assets
|
||||
|
|
@ -12,15 +12,20 @@ import { resolve, dirname } from 'path';
|
|||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
const publicAssetsDir = resolve(__dirname, '../public/assets');
|
||||
const strudelAssetsDir = resolve(__dirname, '../../../node_modules/@strudel/core/dist/assets');
|
||||
const publicAssetsDir = resolve(__dirname, "../public/assets");
|
||||
const strudelAssetsDir = resolve(
|
||||
__dirname,
|
||||
"../../../node_modules/@strudel/core/dist/assets",
|
||||
);
|
||||
|
||||
if (!existsSync(publicAssetsDir)) {
|
||||
mkdirSync(publicAssetsDir, { recursive: true });
|
||||
}
|
||||
|
||||
const files = readdirSync(strudelAssetsDir).filter(file => file.startsWith('clockworker--'));
|
||||
files.forEach(file => {
|
||||
const files = readdirSync(strudelAssetsDir).filter((file) =>
|
||||
file.startsWith("clockworker--"),
|
||||
);
|
||||
files.forEach((file) => {
|
||||
const src = resolve(strudelAssetsDir, file);
|
||||
const dest = resolve(publicAssetsDir, file);
|
||||
copyFileSync(src, dest);
|
||||
|
|
|
|||
|
|
@ -17,9 +17,7 @@ const __dirname = path.dirname(__filename);
|
|||
function info(msg) {
|
||||
const timestamp = new Date().toLocaleString("en-US").split(",")[1].trim();
|
||||
console.log(
|
||||
`${pc.dim(timestamp)} ${pc.bold(pc.cyan("[flok-web]"))} ${pc.green(
|
||||
msg,
|
||||
)}`,
|
||||
`${pc.dim(timestamp)} ${pc.bold(pc.cyan("[flok-web]"))} ${pc.green(msg)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -30,13 +28,15 @@ export async function startServer({ onReady, staticDir, ...opts }) {
|
|||
app.use(compression());
|
||||
|
||||
if (staticDir) {
|
||||
info(`Serving extra static files at ${pc.gray(staticDir)}`)
|
||||
app.use(express.static(staticDir))
|
||||
info(`Serving extra static files at ${pc.gray(staticDir)}`);
|
||||
app.use(express.static(staticDir));
|
||||
}
|
||||
|
||||
let viteServer;
|
||||
if (opts.secure) {
|
||||
info(`Using SSL certificate at ${pc.gray(opts.sslCert)} (key at ${pc.gray(opts.sslKey)})`)
|
||||
info(
|
||||
`Using SSL certificate at ${pc.gray(opts.sslCert)} (key at ${pc.gray(opts.sslKey)})`,
|
||||
);
|
||||
const key = fs.readFileSync(opts.sslKey);
|
||||
const cert = fs.readFileSync(opts.sslCert);
|
||||
viteServer = https.createServer({ key, cert }, app);
|
||||
|
|
@ -56,20 +56,25 @@ export async function startServer({ onReady, staticDir, ...opts }) {
|
|||
|
||||
const server = withFlokServer(viteServer);
|
||||
|
||||
server.listen(opts.port, onReady || (() => {
|
||||
const netResults = getPossibleIpAddresses();
|
||||
const schema = opts.secure ? "https" : "http";
|
||||
info(`Listening on ${schema}://localhost:${opts.port}`);
|
||||
if (netResults.length > 1) {
|
||||
info("If on LAN, try sharing with your friends one of these URLs:");
|
||||
Object.entries(netResults).map(([k, v]) => {
|
||||
info(`\t${k}: ${schema}://${v}:${opts.port}`);
|
||||
});
|
||||
} else {
|
||||
info(
|
||||
`If on LAN, try sharing with your friends ${schema}://${Object.values(netResults)[0]}:${opts.port}`);
|
||||
}
|
||||
}))
|
||||
server.listen(
|
||||
opts.port,
|
||||
onReady ||
|
||||
(() => {
|
||||
const netResults = getPossibleIpAddresses();
|
||||
const schema = opts.secure ? "https" : "http";
|
||||
info(`Listening on ${schema}://localhost:${opts.port}`);
|
||||
if (netResults.length > 1) {
|
||||
info("If on LAN, try sharing with your friends one of these URLs:");
|
||||
Object.entries(netResults).map(([k, v]) => {
|
||||
info(`\t${k}: ${schema}://${v}:${opts.port}`);
|
||||
});
|
||||
} else {
|
||||
info(
|
||||
`If on LAN, try sharing with your friends ${schema}://${Object.values(netResults)[0]}:${opts.port}`,
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
@font-face {
|
||||
font-family: 'BigBlue TerminalPlus';
|
||||
src: url('BigBlue_TerminalPlus.woff2') format('woff2'),
|
||||
url('BigBlue_TerminalPlus.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 80%;
|
||||
font-family: "BigBlue TerminalPlus";
|
||||
src:
|
||||
url("BigBlue_TerminalPlus.woff2") format("woff2"),
|
||||
url("BigBlue_TerminalPlus.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 80%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'BigBlue Terminal 437TT';
|
||||
src: url('BigBlue_Terminal_437TT.woff2') format('woff2'),
|
||||
url('BigBlue_Terminal_437TT.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 80%;
|
||||
font-family: "BigBlue Terminal 437TT";
|
||||
src:
|
||||
url("BigBlue_Terminal_437TT.woff2") format("woff2"),
|
||||
url("BigBlue_Terminal_437TT.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 80%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Fira Code VF';
|
||||
src: url('FiraCode-VF.woff2') format('woff2-variations'),
|
||||
url('woff/FiraCode-VF.woff') format('woff-variations');
|
||||
font-family: "Fira Code VF";
|
||||
src:
|
||||
url("FiraCode-VF.woff2") format("woff2-variations"),
|
||||
url("woff/FiraCode-VF.woff") format("woff-variations");
|
||||
/* font-weight requires a range: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide#Using_a_variable_font_font-face_changes */
|
||||
font-weight: 300 700;
|
||||
font-style: normal;
|
||||
size-adjust: 87%;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,140 +1,153 @@
|
|||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-Thin.woff2') format('woff2'),
|
||||
url('IBMPlexMono-Thin.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-Thin.woff2") format("woff2"),
|
||||
url("IBMPlexMono-Thin.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-Regular.woff2') format('woff2'),
|
||||
url('IBMPlexMono-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-Regular.woff2") format("woff2"),
|
||||
url("IBMPlexMono-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-Bold.woff2') format('woff2'),
|
||||
url('IBMPlexMono-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-Bold.woff2") format("woff2"),
|
||||
url("IBMPlexMono-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-LightItalic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-LightItalic.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-LightItalic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-LightItalic.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-ExtraLightItalic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-ExtraLightItalic.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-ExtraLightItalic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-ExtraLightItalic.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-SemiBold.woff2') format('woff2'),
|
||||
url('IBMPlexMono-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-SemiBold.woff2") format("woff2"),
|
||||
url("IBMPlexMono-SemiBold.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-Italic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-Italic.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-Italic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-ThinItalic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-ThinItalic.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-ThinItalic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-ThinItalic.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-SemiBoldItalic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-SemiBoldItalic.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-SemiBoldItalic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-SemiBoldItalic.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-Light.woff2') format('woff2'),
|
||||
url('IBMPlexMono-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-Light.woff2") format("woff2"),
|
||||
url("IBMPlexMono-Light.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-MediumItalic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-MediumItalic.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-MediumItalic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-MediumItalic.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-Medium.woff2') format('woff2'),
|
||||
url('IBMPlexMono-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-Medium.woff2") format("woff2"),
|
||||
url("IBMPlexMono-Medium.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-BoldItalic.woff2') format('woff2'),
|
||||
url('IBMPlexMono-BoldItalic.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-BoldItalic.woff2") format("woff2"),
|
||||
url("IBMPlexMono-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'IBM Plex Mono';
|
||||
src: url('IBMPlexMono-ExtraLight.woff2') format('woff2'),
|
||||
url('IBMPlexMono-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%
|
||||
font-family: "IBM Plex Mono";
|
||||
src:
|
||||
url("IBMPlexMono-ExtraLight.woff2") format("woff2"),
|
||||
url("IBMPlexMono-ExtraLight.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,40 +1,43 @@
|
|||
@font-face {
|
||||
font-family: 'jgs7';
|
||||
src: url('jgs7.woff2') format('woff2'),
|
||||
url('jgs7.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
font-family: "jgs7";
|
||||
src:
|
||||
url("jgs7.woff2") format("woff2"),
|
||||
url("jgs7.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'jgs';
|
||||
src: url('jgs.woff2') format('woff2'),
|
||||
url('jgs.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
font-family: "jgs";
|
||||
src:
|
||||
url("jgs.woff2") format("woff2"),
|
||||
url("jgs.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'jgs_Font';
|
||||
src: url('jgs_Font.woff2') format('woff2'),
|
||||
url('jgs_Font.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
font-family: "jgs_Font";
|
||||
src:
|
||||
url("jgs_Font.woff2") format("woff2"),
|
||||
url("jgs_Font.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'jgs5';
|
||||
src: url('jgs5.woff2') format('woff2'),
|
||||
url('jgs5.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
font-family: "jgs5";
|
||||
src:
|
||||
url("jgs5.woff2") format("woff2"),
|
||||
url("jgs5.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,300 +1,329 @@
|
|||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-SemiBoldItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-SemiBoldItalic.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-SemiBoldItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-SemiBoldItalic.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-ExtraBoldItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-ExtraBoldItalic.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-ExtraBoldItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-ExtraBoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-MediumItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-MediumItalic.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-MediumItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-MediumItalic.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-LightItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-LightItalic.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-LightItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-LightItalic.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-LightItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-LightItalic.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-LightItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-LightItalic.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-ExtraBold.woff2') format('woff2'),
|
||||
url('JetBrainsMono-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-ExtraBold.woff2") format("woff2"),
|
||||
url("JetBrainsMono-ExtraBold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-ThinItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-ThinItalic.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-ThinItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-ThinItalic.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-ExtraBold.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-ExtraBold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-ExtraBold.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-ExtraBold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-ExtraLight.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-ExtraLight.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-ExtraLight.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-MediumItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-MediumItalic.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-MediumItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-MediumItalic.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-Regular.woff2') format('woff2'),
|
||||
url('JetBrainsMono-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-Regular.woff2") format("woff2"),
|
||||
url("JetBrainsMono-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-ExtraBoldItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-ExtraBoldItalic.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-ExtraBoldItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-ExtraBoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-Italic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-Italic.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-Italic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-ExtraLightItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-ExtraLightItalic.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-ExtraLightItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-ExtraLightItalic.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-Medium.woff2') format('woff2'),
|
||||
url('JetBrainsMono-Medium.woff') format('woff');
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-Medium.woff2") format("woff2"),
|
||||
url("JetBrainsMono-Medium.woff") format("woff");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-Italic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-Italic.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-Italic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-BoldItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-BoldItalic.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-BoldItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-ExtraLight.woff2') format('woff2'),
|
||||
url('JetBrainsMono-ExtraLight.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-ExtraLight.woff2") format("woff2"),
|
||||
url("JetBrainsMono-ExtraLight.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-SemiBoldItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-SemiBoldItalic.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-SemiBoldItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-SemiBoldItalic.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-Thin.woff2') format('woff2'),
|
||||
url('JetBrainsMono-Thin.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-Thin.woff2") format("woff2"),
|
||||
url("JetBrainsMono-Thin.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-SemiBold.woff2') format('woff2'),
|
||||
url('JetBrainsMono-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-SemiBold.woff2") format("woff2"),
|
||||
url("JetBrainsMono-SemiBold.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-SemiBold.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-SemiBold.woff') format('woff');
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-SemiBold.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-SemiBold.woff") format("woff");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-Thin.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-Thin.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-Thin.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-Thin.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-Regular.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-Regular.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-ExtraLightItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-ExtraLightItalic.woff') format('woff');
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-ExtraLightItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-ExtraLightItalic.woff") format("woff");
|
||||
font-weight: 200;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-BoldItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMono-BoldItalic.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-BoldItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMono-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-ThinItalic.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-ThinItalic.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-ThinItalic.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-ThinItalic.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-Light.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-Light.woff') format('woff');
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-Light.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-Light.woff") format("woff");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono NL';
|
||||
src: url('JetBrainsMonoNL-Bold.woff2') format('woff2'),
|
||||
url('JetBrainsMonoNL-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono NL";
|
||||
src:
|
||||
url("JetBrainsMonoNL-Bold.woff2") format("woff2"),
|
||||
url("JetBrainsMonoNL-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'JetBrains Mono';
|
||||
src: url('JetBrainsMono-Bold.woff2') format('woff2'),
|
||||
url('JetBrainsMono-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
font-family: "JetBrains Mono";
|
||||
src:
|
||||
url("JetBrainsMono-Bold.woff2") format("woff2"),
|
||||
url("JetBrainsMono-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 85%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
@font-face {
|
||||
font-family: 'Monocraft Nerd Font';
|
||||
src: url('MonocraftNerdFontComplete-.woff2') format('woff2'),
|
||||
url('MonocraftNerdFontComplete-.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 80%;
|
||||
font-family: "Monocraft Nerd Font";
|
||||
src:
|
||||
url("MonocraftNerdFontComplete-.woff2") format("woff2"),
|
||||
url("MonocraftNerdFontComplete-.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 80%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
@font-face {
|
||||
font-family: 'Roboto Mono';
|
||||
src: url('RobotoMono-Regular.woff2') format('woff2'),
|
||||
url('RobotoMono-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
font-family: "Roboto Mono";
|
||||
src:
|
||||
url("RobotoMono-Regular.woff2") format("woff2"),
|
||||
url("RobotoMono-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 90%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
@font-face {
|
||||
font-family: 'Steps Mono';
|
||||
src: url('Steps-Mono-Thin.woff2') format('woff2'),
|
||||
url('Steps-Mono-Thin.woff') format('woff');
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 100%;
|
||||
font-family: "Steps Mono";
|
||||
src:
|
||||
url("Steps-Mono-Thin.woff2") format("woff2"),
|
||||
url("Steps-Mono-Thin.woff") format("woff");
|
||||
font-weight: 100;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 100%;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Steps-Mono';
|
||||
src: url('Steps-Mono-Mono.woff2') format('woff2'),
|
||||
url('Steps-Mono-Mono.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 95%;
|
||||
font-family: "Steps-Mono";
|
||||
src:
|
||||
url("Steps-Mono-Mono.woff2") format("woff2"),
|
||||
url("Steps-Mono-Mono.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 95%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
@font-face {
|
||||
font-family: 'Syne Mono';
|
||||
src: url('SyneMono-Regular.woff2') format('woff2'),
|
||||
url('SyneMono-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 95%;
|
||||
font-family: "Syne Mono";
|
||||
src:
|
||||
url("SyneMono-Regular.woff2") format("woff2"),
|
||||
url("SyneMono-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 95%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
@font-face {
|
||||
font-family: 'Ubuntu Mono';
|
||||
src: url('UbuntuMono-Bold.woff2') format('woff2'),
|
||||
url('UbuntuMono-Bold.woff') format('woff');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
font-family: "Ubuntu Mono";
|
||||
src:
|
||||
url("UbuntuMono-Bold.woff2") format("woff2"),
|
||||
url("UbuntuMono-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 105%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,192 +1,320 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="robots" content="noindex, noarchive">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="robots" content="noindex, noarchive" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<title>Transfonter demo</title>
|
||||
<link href="stylesheet.css" rel="stylesheet">
|
||||
<link href="stylesheet.css" rel="stylesheet" />
|
||||
<style>
|
||||
/*
|
||||
/*
|
||||
http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
/* demo styles */
|
||||
body {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
html,
|
||||
body,
|
||||
div,
|
||||
span,
|
||||
applet,
|
||||
object,
|
||||
iframe,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
blockquote,
|
||||
pre,
|
||||
a,
|
||||
abbr,
|
||||
acronym,
|
||||
address,
|
||||
big,
|
||||
cite,
|
||||
code,
|
||||
del,
|
||||
dfn,
|
||||
em,
|
||||
img,
|
||||
ins,
|
||||
kbd,
|
||||
q,
|
||||
s,
|
||||
samp,
|
||||
small,
|
||||
strike,
|
||||
strong,
|
||||
sub,
|
||||
sup,
|
||||
tt,
|
||||
var,
|
||||
b,
|
||||
u,
|
||||
i,
|
||||
center,
|
||||
dl,
|
||||
dt,
|
||||
dd,
|
||||
ol,
|
||||
ul,
|
||||
li,
|
||||
fieldset,
|
||||
form,
|
||||
label,
|
||||
legend,
|
||||
table,
|
||||
caption,
|
||||
tbody,
|
||||
tfoot,
|
||||
thead,
|
||||
tr,
|
||||
th,
|
||||
td,
|
||||
article,
|
||||
aside,
|
||||
canvas,
|
||||
details,
|
||||
embed,
|
||||
figure,
|
||||
figcaption,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
output,
|
||||
ruby,
|
||||
section,
|
||||
summary,
|
||||
time,
|
||||
mark,
|
||||
audio,
|
||||
video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
menu,
|
||||
nav,
|
||||
section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol,
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote,
|
||||
q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before,
|
||||
blockquote:after,
|
||||
q:before,
|
||||
q:after {
|
||||
content: "";
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
/* demo styles */
|
||||
body {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
.page {
|
||||
background: #fff;
|
||||
width: 920px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 20px 0 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.font-container {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-bottom: 40px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
h1 {
|
||||
position: relative;
|
||||
background: #444;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
margin: 0 -20px 12px -20px;
|
||||
}
|
||||
.letters {
|
||||
font-size: 25px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.s10:before {
|
||||
content: "10px";
|
||||
}
|
||||
.s11:before {
|
||||
content: "11px";
|
||||
}
|
||||
.s12:before {
|
||||
content: "12px";
|
||||
}
|
||||
.s14:before {
|
||||
content: "14px";
|
||||
}
|
||||
.s18:before {
|
||||
content: "18px";
|
||||
}
|
||||
.s24:before {
|
||||
content: "24px";
|
||||
}
|
||||
.s30:before {
|
||||
content: "30px";
|
||||
}
|
||||
.s36:before {
|
||||
content: "36px";
|
||||
}
|
||||
.s48:before {
|
||||
content: "48px";
|
||||
}
|
||||
.s60:before {
|
||||
content: "60px";
|
||||
}
|
||||
.s72:before {
|
||||
content: "72px";
|
||||
}
|
||||
.s10:before,
|
||||
.s11:before,
|
||||
.s12:before,
|
||||
.s14:before,
|
||||
.s18:before,
|
||||
.s24:before,
|
||||
.s30:before,
|
||||
.s36:before,
|
||||
.s48:before,
|
||||
.s60:before,
|
||||
.s72:before {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
padding-right: 6px;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9px;
|
||||
margin: 0 0 12px;
|
||||
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.428571429;
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ccc;
|
||||
overflow-x: auto;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* responsive */
|
||||
@media (max-width: 959px) {
|
||||
.page {
|
||||
background: #fff;
|
||||
width: 920px;
|
||||
margin: 0 auto;
|
||||
padding: 20px 20px 0 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.font-container {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-bottom: 40px;
|
||||
line-height: 1.3;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
h1 {
|
||||
position: relative;
|
||||
background: #444;
|
||||
font-size: 32px;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
margin: 0 -20px 12px -20px;
|
||||
}
|
||||
.letters {
|
||||
font-size: 25px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.s10:before {
|
||||
content: '10px';
|
||||
}
|
||||
.s11:before {
|
||||
content: '11px';
|
||||
}
|
||||
.s12:before {
|
||||
content: '12px';
|
||||
}
|
||||
.s14:before {
|
||||
content: '14px';
|
||||
}
|
||||
.s18:before {
|
||||
content: '18px';
|
||||
}
|
||||
.s24:before {
|
||||
content: '24px';
|
||||
}
|
||||
.s30:before {
|
||||
content: '30px';
|
||||
}
|
||||
.s36:before {
|
||||
content: '36px';
|
||||
}
|
||||
.s48:before {
|
||||
content: '48px';
|
||||
}
|
||||
.s60:before {
|
||||
content: '60px';
|
||||
}
|
||||
.s72:before {
|
||||
content: '72px';
|
||||
}
|
||||
.s10:before, .s11:before, .s12:before, .s14:before,
|
||||
.s18:before, .s24:before, .s30:before, .s36:before,
|
||||
.s48:before, .s60:before, .s72:before {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
color: #999;
|
||||
padding-right: 6px;
|
||||
}
|
||||
pre {
|
||||
display: block;
|
||||
padding: 9px;
|
||||
margin: 0 0 12px;
|
||||
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.428571429;
|
||||
color: #333;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ccc;
|
||||
overflow-x: auto;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* responsive */
|
||||
@media (max-width: 959px) {
|
||||
.page {
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
width: auto;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="demo">
|
||||
<h1 style="font-family: 'VT323'; font-weight: normal; font-style: normal;">VT323 Regular</h1>
|
||||
<pre title="Usage">.your-style {
|
||||
</head>
|
||||
<body>
|
||||
<div class="page">
|
||||
<div class="demo">
|
||||
<h1
|
||||
style="
|
||||
font-family: "VT323";
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
"
|
||||
>
|
||||
VT323 Regular
|
||||
</h1>
|
||||
<pre title="Usage">
|
||||
.your-style {
|
||||
font-family: 'VT323';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}</pre>
|
||||
}</pre
|
||||
>
|
||||
<pre title="Preload (optional)">
|
||||
<link rel="preload" href="VT323-Regular.woff2" as="font" type="font/woff2" crossorigin></pre>
|
||||
<div class="font-container" style="font-family: 'VT323'; font-weight: normal; font-style: normal;">
|
||||
<p class="letters">
|
||||
abcdefghijklmnopqrstuvwxyz<br>
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
|
||||
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||
</p>
|
||||
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
|
||||
<link rel="preload" href="VT323-Regular.woff2" as="font" type="font/woff2" crossorigin></pre
|
||||
>
|
||||
<div
|
||||
class="font-container"
|
||||
style="
|
||||
font-family: "VT323";
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
"
|
||||
>
|
||||
<p class="letters">
|
||||
abcdefghijklmnopqrstuvwxyz<br />
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br />
|
||||
0123456789.:,;()*!?'@#<>$%&^+-=~
|
||||
</p>
|
||||
<p class="s10" style="font-size: 10px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s11" style="font-size: 11px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s12" style="font-size: 12px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s14" style="font-size: 14px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s18" style="font-size: 18px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s24" style="font-size: 24px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s30" style="font-size: 30px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s36" style="font-size: 36px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s48" style="font-size: 48px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s60" style="font-size: 60px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
<p class="s72" style="font-size: 72px">
|
||||
The quick brown fox jumps over the lazy dog.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
@font-face {
|
||||
font-family: 'VT323';
|
||||
src: url('VT323-Regular.woff2') format('woff2'),
|
||||
url('VT323-Regular.woff') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 120%;
|
||||
font-family: "VT323";
|
||||
src:
|
||||
url("VT323-Regular.woff2") format("woff2"),
|
||||
url("VT323-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
size-adjust: 120%;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export function ConfigureDialog({
|
|||
.split(",")
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => knownTargets.includes(t)),
|
||||
[targetsValue]
|
||||
[targetsValue],
|
||||
);
|
||||
|
||||
const newOrCurrentTargets = newTargets.length > 0 ? newTargets : targets;
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ const panicCodes = panicCodesUntyped as { [target: string]: string };
|
|||
|
||||
const panicKeymap = (
|
||||
doc: Document,
|
||||
keys: string[] = ["Cmd-.", "Ctrl-.", "Alt-."]
|
||||
keys: string[] = ["Cmd-.", "Ctrl-.", "Alt-."],
|
||||
) => {
|
||||
const panicCode = panicCodes[doc.target];
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ interface FlokSetupOptions {
|
|||
|
||||
const flokSetup = (
|
||||
doc: Document,
|
||||
{ readOnly = false }: FlokSetupOptions = {}
|
||||
{ readOnly = false }: FlokSetupOptions = {},
|
||||
) => {
|
||||
const text = doc.getText();
|
||||
const undoManager = new UndoManager(text);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const HydraCanvas = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"absolute top-0 left-0",
|
||||
fullscreen && "h-full w-full block overflow-hidden"
|
||||
fullscreen && "h-full w-full block overflow-hidden",
|
||||
)}
|
||||
style={{
|
||||
imageRendering: "pixelated",
|
||||
|
|
|
|||
|
|
@ -51,14 +51,14 @@ export function Mosaic({ className, items }: MosaicProps) {
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col items-stretch p-1 h-screen gap-1 overflow-hidden",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{rows.map((rowItems, i) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-row gap-1",
|
||||
halfHeight ? "h-[50vh]" : "h-screen"
|
||||
halfHeight ? "h-[50vh]" : "h-screen",
|
||||
)}
|
||||
key={i}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const Pane = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex overflow-auto relative",
|
||||
halfHeight ? "h-[50vh]" : "h-screen"
|
||||
halfHeight ? "h-[50vh]" : "h-screen",
|
||||
)}
|
||||
>
|
||||
<TargetSelect
|
||||
|
|
|
|||
|
|
@ -24,15 +24,15 @@ export function ReplsInfo({
|
|||
const replTargets = targets.filter((t) => !webTargets.includes(t));
|
||||
if (replTargets.length === 0) return null;
|
||||
|
||||
const terminalSpec = (OS === "windows" ? 'PowerShell ' : '');
|
||||
const lineSeparator = (OS === 'windows' ? `\`` : `\\`);
|
||||
const terminalSpec = OS === "windows" ? "PowerShell " : "";
|
||||
const lineSeparator = OS === "windows" ? `\`` : `\\`;
|
||||
|
||||
const replCommand =
|
||||
`npx flok-repl@latest -H ${sessionUrl} ${lineSeparator}\n` +
|
||||
` -s ${sessionName} ${lineSeparator}\n` +
|
||||
` -t ${replTargets.join(" ")} ${lineSeparator}\n` +
|
||||
` -T user:${userName}`;
|
||||
|
||||
|
||||
const copyToClipboard = () => {
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 1000);
|
||||
|
|
@ -44,7 +44,8 @@ export function ReplsInfo({
|
|||
<p className="text-sm text-slate-500 dark:text-slate-400">
|
||||
This session has one or more targets that need an external REPL process
|
||||
to run on your computer. To run code executed on these targets, you will
|
||||
need to run <code>flok-repl</code> on a {terminalSpec}terminal, like this:
|
||||
need to run <code>flok-repl</code> on a {terminalSpec}terminal, like
|
||||
this:
|
||||
</p>
|
||||
<div className="mt-4 mb-4 relative">
|
||||
<pre className="rounded bg-slate-800 mr-3 p-3 whitespace-pre-wrap w-full">
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export default function SessionCommandDialog({
|
|||
onEditorSettingsChange({
|
||||
...editorSettings,
|
||||
fontFamily: font,
|
||||
})
|
||||
}),
|
||||
)();
|
||||
};
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ export default function SessionCommandDialog({
|
|||
onEditorSettingsChange({
|
||||
...editorSettings,
|
||||
theme,
|
||||
})
|
||||
}),
|
||||
)();
|
||||
};
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ export default function SessionCommandDialog({
|
|||
onEditorSettingsChange({
|
||||
...editorSettings,
|
||||
lineNumbers: !lineNumbers,
|
||||
})
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<FileDigit className="mr-2 h-4 w-4" />
|
||||
|
|
@ -181,7 +181,7 @@ export default function SessionCommandDialog({
|
|||
onEditorSettingsChange({
|
||||
...editorSettings,
|
||||
wrapText: !wrapText,
|
||||
})
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<WrapText className="mr-2 h-4 w-4" />
|
||||
|
|
@ -192,7 +192,7 @@ export default function SessionCommandDialog({
|
|||
onEditorSettingsChange({
|
||||
...editorSettings,
|
||||
vimMode: !vimMode,
|
||||
})
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<TextCursorIcon className="mr-2 h-4 w-4" />
|
||||
|
|
@ -203,7 +203,9 @@ export default function SessionCommandDialog({
|
|||
<CommandSeparator />
|
||||
<CommandGroup heading="Display">
|
||||
<CommandList>
|
||||
<CommandItem onSelect={wrapHandler(props.onEditorChangeDisplaySettings)}>
|
||||
<CommandItem
|
||||
onSelect={wrapHandler(props.onEditorChangeDisplaySettings)}
|
||||
>
|
||||
<Monitor className="mr-2 h-4 w-4" />
|
||||
<span>Change display settings</span>
|
||||
</CommandItem>
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export function StatusBar({
|
|||
<div
|
||||
className={cn(
|
||||
"fixed bottom-0 left-0 z-10 h-8 w-screen p-1 pl-2 pr-2 text-xs flex flex-row shadow-lg shadow-black/50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{pubSubState && (
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ const buttonVariants = cva(
|
|||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const Command = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-full w-full flex-col overflow-hidden rounded-lg bg-white dark:bg-slate-800",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -44,13 +44,14 @@ const CommandInput = ({
|
|||
}: React.ComponentProps<typeof CommandPrimitive.Input>) => (
|
||||
<div
|
||||
className="flex items-center border-b border-b-slate-100 px-4 dark:border-b-slate-700"
|
||||
cmdk-input-wrapper="">
|
||||
cmdk-input-wrapper=""
|
||||
>
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-slate-400 disabled:cursor-not-allowed disabled:opacity-50 dark:text-slate-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -95,7 +96,7 @@ const CommandGroup = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"overflow-hidden py-3 px-2 text-slate-700 dark:text-slate-400 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pb-1.5 [&_[cmdk-group-heading]]:text-sm [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-slate-900 [&_[cmdk-group-heading]]:dark:text-slate-300",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -125,7 +126,7 @@ const CommandItem = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-md py-1.5 px-2 text-sm font-medium outline-none aria-selected:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:aria-selected:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -141,7 +142,7 @@ const CommandShortcut = ({
|
|||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-slate-500",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const DialogOverlay = ({
|
|||
<DialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out fixed inset-0 z-50 bg-black/50 transition-all duration-100",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
|
|
@ -49,9 +49,10 @@ const DialogContent = ({
|
|||
className={cn(
|
||||
"animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0 fixed z-50 grid w-full gap-4 rounded-b-lg bg-white p-6 sm:max-w-lg sm:rounded-lg",
|
||||
"dark:bg-slate-900",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-slate-100 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 dark:data-[state=open]:bg-slate-800">
|
||||
<X className="h-4 w-4" />
|
||||
|
|
@ -69,7 +70,7 @@ const DialogHeader = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-2 text-center sm:text-left overflow-auto",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -83,7 +84,7 @@ const DialogFooter = ({
|
|||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -100,7 +101,7 @@ const DialogTitle = ({
|
|||
className={cn(
|
||||
"text-lg font-semibold text-slate-900",
|
||||
"dark:text-slate-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -29,9 +29,10 @@ const DropdownMenuSubTrigger = ({
|
|||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 dark:focus:bg-slate-700 dark:data-[state=open]:bg-slate-700",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
|
|
@ -48,7 +49,7 @@ const DropdownMenuSubContent = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"animate-in slide-in-from-left-1 z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-100 bg-white p-1 text-slate-700 shadow-md dark:border-slate-800 dark:bg-slate-800 dark:text-slate-400",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -68,7 +69,7 @@ const DropdownMenuContent = ({
|
|||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"animate-in data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-100 bg-white p-1 text-slate-700 shadow-md dark:border-slate-800 dark:bg-slate-800 dark:text-slate-400",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -89,7 +90,7 @@ const DropdownMenuItem = ({
|
|||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -107,10 +108,11 @@ const DropdownMenuCheckboxItem = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
|
|
@ -132,9 +134,10 @@ const DropdownMenuRadioItem = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
|
|
@ -158,7 +161,7 @@ const DropdownMenuLabel = ({
|
|||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold text-slate-900 dark:text-slate-300",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -186,7 +189,7 @@ const DropdownMenuShortcut = ({
|
|||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-slate-500",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ export function FloatingPanel({
|
|||
// Size and position are relative to window.innerWidth and window.innerHeight
|
||||
const [size, setSize] = useState<Size>(store.get(sizeSettingId, defaultSize));
|
||||
const [position, setPosition] = useState<Position>(
|
||||
store.get(posSettingId, defaultPosition)
|
||||
store.get(posSettingId, defaultPosition),
|
||||
);
|
||||
|
||||
// Save position and size
|
||||
|
|
@ -151,7 +151,7 @@ export function FloatingPanel({
|
|||
width: clamp(size.width) * innerWidth,
|
||||
height: clamp(size.height) * innerHeight,
|
||||
}),
|
||||
[size, resizeTriggered]
|
||||
[size, resizeTriggered],
|
||||
);
|
||||
|
||||
const absPosition = useMemo(
|
||||
|
|
@ -159,14 +159,14 @@ export function FloatingPanel({
|
|||
x: clamp(position.x) * innerWidth,
|
||||
y: clamp(position.y) * innerHeight,
|
||||
}),
|
||||
[position, resizeTriggered]
|
||||
[position, resizeTriggered],
|
||||
);
|
||||
|
||||
return (
|
||||
<Rnd
|
||||
className={cn(
|
||||
"overflow-hidden rounded-md pl-1 pr-1 pb-2 border border-gray-800 shadow-lg shadow-black/50 text-slate-50 font-mono text-xs bg-black bg-opacity-70 z-10",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
size={absSize}
|
||||
position={absPosition}
|
||||
|
|
@ -195,7 +195,7 @@ export function FloatingPanel({
|
|||
<div
|
||||
className={cn(
|
||||
headerClassName,
|
||||
"font-bold sticky top-0 cursor-move pb-1"
|
||||
"font-bold sticky top-0 cursor-move pb-1",
|
||||
)}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const Input = ({ className, ref, ...props }: InputProps) => {
|
|||
<input
|
||||
className={cn(
|
||||
"flex h-10 w-full rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-50 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ const Label = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const Menubar = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-8 items-center space-x-1 border-slate-100 bg-white dark:border-slate-800 dark:bg-slate-900 bg-opacity-50 dark:bg-opacity-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -38,7 +38,7 @@ const MenubarTrigger = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-[0.2rem] py-1.5 px-3 text-sm font-medium outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 dark:focus:bg-slate-700 dark:data-[state=open]:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -59,9 +59,10 @@ const MenubarSubTrigger = ({
|
|||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-slate-100 data-[state=open]:bg-slate-100 dark:focus:bg-slate-700 dark:data-[state=open]:bg-slate-700",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto h-4 w-4" />
|
||||
</MenubarPrimitive.SubTrigger>
|
||||
|
|
@ -77,7 +78,7 @@ const MenubarSubContent = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"animate-in slide-in-from-left-1 z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-100 bg-white p-1 shadow-md dark:border-slate-700 dark:bg-slate-800",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -96,7 +97,7 @@ const MenubarContent = ({
|
|||
align={align}
|
||||
className={cn(
|
||||
"animate-in slide-in-from-top-1 z-50 min-w-[12rem] overflow-hidden rounded-md border border-slate-100 bg-white p-1 text-slate-700 shadow-md dark:border-slate-800 dark:bg-slate-800 dark:text-slate-400",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -117,7 +118,7 @@ const MenubarItem = ({
|
|||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1 px-1 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -135,10 +136,11 @@ const MenubarCheckboxItem = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<MenubarPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
|
|
@ -159,9 +161,10 @@ const MenubarRadioItem = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<MenubarPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
|
|
@ -185,7 +188,7 @@ const MenubarLabel = ({
|
|||
className={cn(
|
||||
"px-2 py-1.5 text-sm font-semibold text-slate-900 dark:text-slate-300",
|
||||
inset && "pl-8",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -214,7 +217,7 @@ const MenubarShortcut = ({
|
|||
<span
|
||||
className={cn(
|
||||
"ml-auto text-xs tracking-widest text-slate-500",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const PopoverContent = ({
|
|||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 z-50 w-72 rounded-md border border-slate-100 bg-white p-4 shadow-md outline-none dark:border-slate-800 dark:bg-slate-800",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ const SelectTrigger = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-slate-300 bg-transparent py-2 px-3 text-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-50 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronDown className="h-4 w-4 opacity-50" />
|
||||
</SelectPrimitive.Trigger>
|
||||
|
|
@ -42,9 +43,10 @@ const SelectContent = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"animate-in fade-in-80 relative z-50 min-w-[8rem] overflow-hidden rounded-md border border-slate-100 bg-white text-slate-700 shadow-md dark:border-slate-800 dark:bg-slate-800 dark:text-slate-400",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<SelectPrimitive.Viewport className="p-1">
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
|
|
@ -62,7 +64,7 @@ const SelectLabel = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"py-1.5 pr-2 pl-8 text-sm font-semibold text-slate-900 dark:text-slate-300",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -79,9 +81,10 @@ const SelectItem = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pr-2 pl-8 text-sm font-medium outline-none focus:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-slate-700",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const ToastViewport = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:top-auto sm:bottom-0 sm:right-0 sm:flex-col md:max-w-[420px]",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -38,7 +38,7 @@ const toastVariants = cva(
|
|||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const Toast = ({
|
||||
|
|
@ -67,7 +67,7 @@ const ToastAction = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-slate-200 bg-transparent px-3 text-sm font-medium transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-red-100 group-[.destructive]:hover:border-slate-50 group-[.destructive]:hover:bg-red-100 group-[.destructive]:hover:text-red-600 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-700 dark:hover:text-slate-100 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 dark:data-[state=open]:bg-slate-800",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
@ -83,10 +83,11 @@ const ToastClose = ({
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"absolute top-2 right-2 rounded-md p-1 text-slate-500 opacity-0 transition-opacity hover:text-slate-900 focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600 dark:hover:text-slate-50",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
toast-close=""
|
||||
{...props}>
|
||||
{...props}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</ToastPrimitives.Close>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const toggleVariants = cva(
|
|||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const Toggle = ({
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ const TooltipContent = ({
|
|||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"animate-in fade-in-50 data-[side=bottom]:slide-in-from-top-1 data-[side=top]:slide-in-from-bottom-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 z-50 overflow-hidden rounded-md border border-slate-100 bg-white px-3 py-1.5 text-sm text-slate-700 shadow-md dark:border-slate-800 dark:bg-slate-800 dark:text-slate-400",
|
||||
className
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@ export interface WebTargetIframeProps {
|
|||
displaySettings: DisplaySettings;
|
||||
}
|
||||
|
||||
export const WebTargetIframe = ({ target, session, displaySettings }: WebTargetIframeProps) => {
|
||||
export const WebTargetIframe = ({
|
||||
target,
|
||||
session,
|
||||
displaySettings,
|
||||
}: WebTargetIframeProps) => {
|
||||
const ref = useRef<HTMLIFrameElement | null>(null);
|
||||
|
||||
const query = useQuery();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export function useAnimationFrame(callback: (timestamp: number) => void) {
|
|||
callback(timestamp);
|
||||
requestId.current = requestAnimationFrame(animate);
|
||||
},
|
||||
[callback]
|
||||
[callback],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ const toObject = (hash: string) =>
|
|||
|
||||
export function useHash(): [
|
||||
HashRecord,
|
||||
(newHash: HashRecord | React.SetStateAction<HashRecord>) => void
|
||||
(newHash: HashRecord | React.SetStateAction<HashRecord>) => void,
|
||||
] {
|
||||
const [hash, setHash] = useState<HashRecord>(() =>
|
||||
toObject(window.location.hash)
|
||||
toObject(window.location.hash),
|
||||
);
|
||||
|
||||
const hashChangeHandler = useCallback(() => {
|
||||
|
|
@ -41,7 +41,7 @@ export function useHash(): [
|
|||
if (typeof newHash === "function") newHash = newHash(hash);
|
||||
window.location.hash = fromObject(newHash);
|
||||
},
|
||||
[hash]
|
||||
[hash],
|
||||
);
|
||||
|
||||
return [hash, updateHash];
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export function useShortcut(
|
|||
keyShortcuts: string[],
|
||||
handler: (e: KeyboardEvent) => void,
|
||||
deps: any[] = [],
|
||||
preventDefault: boolean = true
|
||||
preventDefault: boolean = true,
|
||||
) {
|
||||
keyShortcuts.forEach((keyShortcut) => {
|
||||
const parts = keyShortcut.toLowerCase().split("-");
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { forEachDocumentContext } from "@/lib/utils";
|
|||
|
||||
export function useStrudelCodemirrorExtensions(
|
||||
session: Session | null,
|
||||
editorRefs: React.RefObject<ReactCodeMirrorRef>[]
|
||||
editorRefs: React.RefObject<ReactCodeMirrorRef>[],
|
||||
) {
|
||||
useAnimationFrame(
|
||||
useCallback(() => {
|
||||
|
|
@ -24,8 +24,8 @@ export function useStrudelCodemirrorExtensions(
|
|||
highlightMiniLocations(view, ctx.phase || 0, ctx.haps || []);
|
||||
},
|
||||
session,
|
||||
editorRefs
|
||||
editorRefs,
|
||||
);
|
||||
}, [session, editorRefs])
|
||||
}, [session, editorRefs]),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ export const reducer = (state: State, action: Action): State => {
|
|||
return {
|
||||
...state,
|
||||
toasts: state.toasts.map((t) =>
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t
|
||||
t.id === action.toast.id ? { ...t, ...action.toast } : t,
|
||||
),
|
||||
};
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ export const reducer = (state: State, action: Action): State => {
|
|||
...t,
|
||||
open: false,
|
||||
}
|
||||
: t
|
||||
: t,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function useWebTarget<Controller>(
|
|||
loadIf?: (deps: any[]) => boolean;
|
||||
onEval?: (instance: Controller, evalMsg: EvalMessage) => void;
|
||||
onError?: (err: unknown) => void;
|
||||
}
|
||||
},
|
||||
) {
|
||||
const query = useQuery();
|
||||
const noWebEval = query.get("noWebEval")?.split(",") || [];
|
||||
|
|
|
|||
|
|
@ -29,8 +29,15 @@
|
|||
}
|
||||
|
||||
.text-stroke {
|
||||
text-shadow: -1px -1px 0 #000, 0 -1px 0 #000, 1px -1px 0 #000, 1px 0 0 #000,
|
||||
1px 1px 0 #000, 0 1px 0 #000, -1px 1px 0 #000, -1px 0 0 #000;
|
||||
text-shadow:
|
||||
-1px -1px 0 #000,
|
||||
0 -1px 0 #000,
|
||||
1px -1px 0 #000,
|
||||
1px 0 0 #000,
|
||||
1px 1px 0 #000,
|
||||
0 1px 0 #000,
|
||||
-1px 1px 0 #000,
|
||||
-1px 0 0 #000;
|
||||
}
|
||||
|
||||
:root {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ export const defaultDisplaySettings: DisplaySettings = {
|
|||
canvasPixelSize: 1,
|
||||
showCanvas: true,
|
||||
enableFft: true,
|
||||
}
|
||||
};
|
||||
|
||||
export function sanitizeDisplaySettings(settings: DisplaySettings): DisplaySettings {
|
||||
export function sanitizeDisplaySettings(
|
||||
settings: DisplaySettings,
|
||||
): DisplaySettings {
|
||||
// Pixel size should be at least 1 to prevent division-by-zero errors
|
||||
const minPixelSize = 1;
|
||||
|
||||
|
|
@ -18,13 +20,11 @@ export function sanitizeDisplaySettings(settings: DisplaySettings): DisplaySetti
|
|||
// canvas; should be low enough
|
||||
const maxPixelSize = 50;
|
||||
|
||||
|
||||
return {
|
||||
...settings,
|
||||
canvasPixelSize: Math.max(
|
||||
minPixelSize,
|
||||
Math.min(
|
||||
maxPixelSize,
|
||||
Math.round(settings.canvasPixelSize))),
|
||||
canvasPixelSize: Math.max(
|
||||
minPixelSize,
|
||||
Math.min(maxPixelSize, Math.round(settings.canvasPixelSize)),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
export const fonts = {
|
||||
"BigBlue Terminal": "BigBlue TerminalPlus",
|
||||
"Courier": "Courier",
|
||||
"Fira Code" : "Fira Code VF",
|
||||
Courier: "Courier",
|
||||
"Fira Code": "Fira Code VF",
|
||||
"IBM Plex Mono": "IBM Plex Mono",
|
||||
"Inconsolata": "Inconsolata",
|
||||
"JetBrains": "JetBrains Mono",
|
||||
"JGS": "jgs_Font",
|
||||
"Monaco": "Monaco",
|
||||
"MonoCraft": "Monocraft Nerd Font",
|
||||
"OpenDyslexic" : "OpenDyslexicMono",
|
||||
"Roboto Mono" : "Roboto Mono",
|
||||
Inconsolata: "Inconsolata",
|
||||
JetBrains: "JetBrains Mono",
|
||||
JGS: "jgs_Font",
|
||||
Monaco: "Monaco",
|
||||
MonoCraft: "Monocraft Nerd Font",
|
||||
OpenDyslexic: "OpenDyslexicMono",
|
||||
"Roboto Mono": "Roboto Mono",
|
||||
"Steps Mono": "Steps Mono",
|
||||
"Syne Mono" : "Syne Mono",
|
||||
"Ubuntu Mono" : "Ubuntu Mono",
|
||||
"VT323" : "VT323",
|
||||
"Syne Mono": "Syne Mono",
|
||||
"Ubuntu Mono": "Ubuntu Mono",
|
||||
VT323: "VT323",
|
||||
};
|
||||
export default fonts;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Hydra from "hydra-synth";
|
||||
import { isWebglSupported } from "@/lib/webgl-detector.js";
|
||||
import {DisplaySettings} from "@/lib/display-settings.ts";
|
||||
import { DisplaySettings } from "@/lib/display-settings.ts";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
|
@ -57,7 +57,7 @@ export class HydraWrapper {
|
|||
// For some reason on Android mobile, Chrome has this object undefined:
|
||||
if (!window.navigator.mediaDevices) {
|
||||
this._onWarning(
|
||||
"navigator.mediaDevices is not defined. You won't be able to use the Webcam or screen capturing."
|
||||
"navigator.mediaDevices is not defined. You won't be able to use the Webcam or screen capturing.",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -85,62 +85,77 @@ export class HydraWrapper {
|
|||
window.P = (pattern: any) => {
|
||||
return () => {
|
||||
// parse using the strudel mini parser
|
||||
const reified = window.strudel.mini.minify(pattern)
|
||||
const reified = window.strudel.mini.minify(pattern);
|
||||
|
||||
const now = window.strudel.core.getTime()
|
||||
const now = window.strudel.core.getTime();
|
||||
|
||||
// query the current value
|
||||
const arc = reified.queryArc(now, now)
|
||||
const arc = reified.queryArc(now, now);
|
||||
return arc[0].value;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// initialized a streaming canvas with the strudel draw context canvas
|
||||
// this allows us to use the strudel output
|
||||
window.useStrudelCanvas = (s: any) => {
|
||||
const canvas = window.strudel.draw.getDrawContext().canvas
|
||||
canvas.style.display = "none"
|
||||
s.init({src: canvas})
|
||||
}
|
||||
|
||||
const clamp = (num: number, min: number, max: number) => Math.min(Math.max(num, min), max);
|
||||
const canvas = window.strudel.draw.getDrawContext().canvas;
|
||||
canvas.style.display = "none";
|
||||
s.init({ src: canvas });
|
||||
};
|
||||
|
||||
const clamp = (num: number, min: number, max: number) =>
|
||||
Math.min(Math.max(num, min), max);
|
||||
|
||||
// Enables Hydra to use Strudel frequency data
|
||||
// with `.scrollX(() => fft(1,0)` it will influence the x-axis, according to the fft data
|
||||
// first number is the index of the bucket, second is the number of buckets to aggregate the number too
|
||||
window.fft = (index: number, buckets: number = 8, options?: { min?: number; max?: number, scale?: number, analyzerId?: string }) => {
|
||||
const analyzerId = options?.analyzerId ?? "flok-master"
|
||||
window.fft = (
|
||||
index: number,
|
||||
buckets: number = 8,
|
||||
options?: {
|
||||
min?: number;
|
||||
max?: number;
|
||||
scale?: number;
|
||||
analyzerId?: string;
|
||||
},
|
||||
) => {
|
||||
const analyzerId = options?.analyzerId ?? "flok-master";
|
||||
const min = options?.min ?? -150;
|
||||
const scale = options?.scale ?? 1
|
||||
const max = options?.max ?? 0
|
||||
const scale = options?.scale ?? 1;
|
||||
const max = options?.max ?? 0;
|
||||
|
||||
// Strudel is not initialized yet, so we just return a default value
|
||||
if(window.strudel == undefined) return .5;
|
||||
if (window.strudel == undefined) return 0.5;
|
||||
|
||||
// If display settings are not enabled, we just return a default value
|
||||
if(!(this._displaySettings.enableFft ?? true)) return .5;
|
||||
if (!(this._displaySettings.enableFft ?? true)) return 0.5;
|
||||
|
||||
// Enable auto-analyze
|
||||
window.strudel.enableAutoAnalyze = true;
|
||||
|
||||
// If the analyzerId is not defined, we just return a default value
|
||||
if(window.strudel.webaudio.analysers[analyzerId] == undefined) {
|
||||
return .5
|
||||
if (window.strudel.webaudio.analysers[analyzerId] == undefined) {
|
||||
return 0.5;
|
||||
}
|
||||
|
||||
const freq = window.strudel.webaudio.getAnalyzerData("frequency", analyzerId) as Array<number>;
|
||||
const bucketSize = (freq.length) / buckets
|
||||
const freq = window.strudel.webaudio.getAnalyzerData(
|
||||
"frequency",
|
||||
analyzerId,
|
||||
) as Array<number>;
|
||||
const bucketSize = freq.length / buckets;
|
||||
|
||||
// inspired from https://github.com/tidalcycles/strudel/blob/a7728e3d81fb7a0a2dff9f2f4bd9e313ddf138cd/packages/webaudio/scope.mjs#L53
|
||||
const normalized = freq.map((it: number) => {
|
||||
const norm = clamp((it - min) / (max - min), 0, 1);
|
||||
return norm * scale;
|
||||
})
|
||||
});
|
||||
|
||||
return normalized.slice(bucketSize * index, bucketSize * (index + 1))
|
||||
.reduce((a, b) => a + b, 0) / bucketSize
|
||||
}
|
||||
return (
|
||||
normalized
|
||||
.slice(bucketSize * index, bucketSize * (index + 1))
|
||||
.reduce((a, b) => a + b, 0) / bucketSize
|
||||
);
|
||||
};
|
||||
|
||||
this.initialized = true;
|
||||
console.log("Hydra initialized");
|
||||
|
|
|
|||
2
packages/web/src/lib/mercury.d.ts
vendored
2
packages/web/src/lib/mercury.d.ts
vendored
|
|
@ -1 +1 @@
|
|||
declare module 'mercury-engine';
|
||||
declare module "mercury-engine";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DisplaySettings } from "@/lib/display-settings";
|
||||
|
||||
export interface SettingsMessage {
|
||||
displaySettings?: DisplaySettings
|
||||
displaySettings?: DisplaySettings;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export class StrudelWrapper {
|
|||
import("@strudel/serial"),
|
||||
import("@strudel/soundfonts"),
|
||||
this.webaudio,
|
||||
controls
|
||||
controls,
|
||||
);
|
||||
try {
|
||||
await Promise.all([
|
||||
|
|
@ -118,11 +118,11 @@ export class StrudelWrapper {
|
|||
// queries the stack of strudel patterns for the current time
|
||||
const allHaps = this._repl.scheduler.pattern.queryArc(
|
||||
Math.max(lastFrame!, phase - 1 / 10), // make sure query is not larger than 1/10 s
|
||||
phase
|
||||
phase,
|
||||
);
|
||||
// filter out haps that are not active right now
|
||||
const currentFrame = allHaps.filter(
|
||||
(hap: any) => phase >= hap.whole.begin && phase <= hap.endClipped
|
||||
(hap: any) => phase >= hap.whole.begin && phase <= hap.endClipped,
|
||||
);
|
||||
// iterate over each strudel doc
|
||||
Object.keys(this._docPatterns).forEach((docId: any) => {
|
||||
|
|
@ -134,7 +134,7 @@ export class StrudelWrapper {
|
|||
},
|
||||
(err: any) => {
|
||||
console.error("[strudel] draw error", err);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this._repl = repl({
|
||||
|
|
@ -169,14 +169,15 @@ export class StrudelWrapper {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
async tryEval(msg: EvalMessage) {
|
||||
if (!this.initialized) await this.initialize();
|
||||
try {
|
||||
const {body: code, docId} = msg;
|
||||
const { body: code, docId } = msg;
|
||||
// little hack that injects the docId at the end of the code to make it available in afterEval
|
||||
// also add ann analyser node to all patterns, for fft data in hydra
|
||||
const pattern = await this._repl.evaluate(`${code}\n${this.enableAutoAnalyze ? this.hapAnalyzeSnippet : ""}\n//${docId}`);
|
||||
const pattern = await this._repl.evaluate(
|
||||
`${code}\n${this.enableAutoAnalyze ? this.hapAnalyzeSnippet : ""}\n//${docId}`,
|
||||
);
|
||||
if (pattern) {
|
||||
this._docPatterns[docId] = pattern.docId(docId); // docId is needed for highlighting
|
||||
const allPatterns = stack(...Object.values(this._docPatterns));
|
||||
|
|
|
|||
|
|
@ -1,31 +1,31 @@
|
|||
import { createTheme } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme } from "@uiw/codemirror-themes";
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
|
||||
export const ayuDark = createTheme({
|
||||
theme: 'dark',
|
||||
theme: "dark",
|
||||
settings: {
|
||||
background: 'transparent',
|
||||
backgroundImage: '',
|
||||
foreground: '#B3B1AD',
|
||||
caret: '#FFCC66',
|
||||
selection: '#253340',
|
||||
selectionMatch: '#253340',
|
||||
lineHighlight: 'rgba(37, 52, 64, 0.7)',
|
||||
gutterBorder: '1px solid #0A0E14',
|
||||
gutterBackground: '#0A0E14',
|
||||
gutterForeground: '#4E5561',
|
||||
background: "transparent",
|
||||
backgroundImage: "",
|
||||
foreground: "#B3B1AD",
|
||||
caret: "#FFCC66",
|
||||
selection: "#253340",
|
||||
selectionMatch: "#253340",
|
||||
lineHighlight: "rgba(37, 52, 64, 0.7)",
|
||||
gutterBorder: "1px solid #0A0E14",
|
||||
gutterBackground: "#0A0E14",
|
||||
gutterForeground: "#4E5561",
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.comment, color: '#4E5561' },
|
||||
{ tag: t.variableName, color: '#FFCC66' },
|
||||
{ tag: [t.string, t.special(t.brace)], color: '#BAE67E' },
|
||||
{ tag: t.number, color: '#D4BFFF' },
|
||||
{ tag: t.bool, color: '#FF8F40' },
|
||||
{ tag: t.null, color: '#FF8F40' },
|
||||
{ tag: t.keyword, color: '#FF8F40' },
|
||||
{ tag: t.operator, color: '#FF8F40' },
|
||||
{ tag: t.className, color: '#5CCFE6' },
|
||||
{ tag: t.definition(t.typeName), color: '#5CCFE6' },
|
||||
{ tag: t.typeName, color: '#5CCFE6' },
|
||||
{ tag: t.comment, color: "#4E5561" },
|
||||
{ tag: t.variableName, color: "#FFCC66" },
|
||||
{ tag: [t.string, t.special(t.brace)], color: "#BAE67E" },
|
||||
{ tag: t.number, color: "#D4BFFF" },
|
||||
{ tag: t.bool, color: "#FF8F40" },
|
||||
{ tag: t.null, color: "#FF8F40" },
|
||||
{ tag: t.keyword, color: "#FF8F40" },
|
||||
{ tag: t.operator, color: "#FF8F40" },
|
||||
{ tag: t.className, color: "#5CCFE6" },
|
||||
{ tag: t.definition(t.typeName), color: "#5CCFE6" },
|
||||
{ tag: t.typeName, color: "#5CCFE6" },
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,30 +1,35 @@
|
|||
import { createTheme } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme } from "@uiw/codemirror-themes";
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
|
||||
export const dracula = createTheme({
|
||||
theme: 'dark',
|
||||
theme: "dark",
|
||||
settings: {
|
||||
background: 'transparent',
|
||||
foreground: '#f8f8f2',
|
||||
caret: '#f8f8f0',
|
||||
selection: 'rgba(255, 255, 255, 0.1)',
|
||||
selectionMatch: 'rgba(255, 255, 255, 0.2)',
|
||||
gutterBackground: '#282a36',
|
||||
gutterForeground: '#6D8A88',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: 'rgba(255, 255, 255, 0.1)',
|
||||
background: "transparent",
|
||||
foreground: "#f8f8f2",
|
||||
caret: "#f8f8f0",
|
||||
selection: "rgba(255, 255, 255, 0.1)",
|
||||
selectionMatch: "rgba(255, 255, 255, 0.2)",
|
||||
gutterBackground: "#282a36",
|
||||
gutterForeground: "#6D8A88",
|
||||
gutterBorder: "transparent",
|
||||
lineHighlight: "rgba(255, 255, 255, 0.1)",
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.comment, color: '#6272a4' },
|
||||
{ tag: t.string, color: '#f1fa8c' },
|
||||
{ tag: t.atom, color: '#bd93f9' },
|
||||
{ tag: t.meta, color: '#f8f8f2' },
|
||||
{ tag: [t.keyword, t.operator, t.tagName], color: '#ff79c6' },
|
||||
{ tag: [t.function(t.propertyName), t.propertyName], color: '#66d9ef' },
|
||||
{ tag: t.comment, color: "#6272a4" },
|
||||
{ tag: t.string, color: "#f1fa8c" },
|
||||
{ tag: t.atom, color: "#bd93f9" },
|
||||
{ tag: t.meta, color: "#f8f8f2" },
|
||||
{ tag: [t.keyword, t.operator, t.tagName], color: "#ff79c6" },
|
||||
{ tag: [t.function(t.propertyName), t.propertyName], color: "#66d9ef" },
|
||||
{
|
||||
tag: [t.definition(t.variableName), t.function(t.variableName), t.className, t.attributeName],
|
||||
color: '#50fa7b',
|
||||
tag: [
|
||||
t.definition(t.variableName),
|
||||
t.function(t.variableName),
|
||||
t.className,
|
||||
t.attributeName,
|
||||
],
|
||||
color: "#50fa7b",
|
||||
},
|
||||
{ tag: t.atom, color: '#bd93f9' },
|
||||
{ tag: t.atom, color: "#bd93f9" },
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,110 +1,110 @@
|
|||
import { createTheme } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme } from "@uiw/codemirror-themes";
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
|
||||
export const gruvboxDark = createTheme({
|
||||
theme: 'dark',
|
||||
theme: "dark",
|
||||
settings: {
|
||||
background: 'transparent',
|
||||
foreground: '#ebdbb2',
|
||||
caret: '#ebdbb2',
|
||||
selection: '#b99d555c',
|
||||
selectionMatch: '#b99d555c',
|
||||
lineHighlight: '#baa1602b',
|
||||
gutterBackground: '#282828',
|
||||
gutterForeground: '#7c6f64',
|
||||
background: "transparent",
|
||||
foreground: "#ebdbb2",
|
||||
caret: "#ebdbb2",
|
||||
selection: "#b99d555c",
|
||||
selectionMatch: "#b99d555c",
|
||||
lineHighlight: "#baa1602b",
|
||||
gutterBackground: "#282828",
|
||||
gutterForeground: "#7c6f64",
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.keyword, color: '#fb4934' },
|
||||
{ tag: t.keyword, color: "#fb4934" },
|
||||
{
|
||||
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
||||
color: '#8ec07c',
|
||||
color: "#8ec07c",
|
||||
},
|
||||
{ tag: [t.variableName], color: '#83a598' },
|
||||
{ tag: [t.function(t.variableName)], color: '#b8bb26', fontStyle: 'bold' },
|
||||
{ tag: [t.labelName], color: '#ebdbb2' },
|
||||
{ tag: [t.variableName], color: "#83a598" },
|
||||
{ tag: [t.function(t.variableName)], color: "#b8bb26", fontStyle: "bold" },
|
||||
{ tag: [t.labelName], color: "#ebdbb2" },
|
||||
{
|
||||
tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
||||
color: '#d3869b',
|
||||
color: "#d3869b",
|
||||
},
|
||||
{ tag: [t.definition(t.name), t.separator], color: '#ebdbb2' },
|
||||
{ tag: [t.brace], color: '#ebdbb2' },
|
||||
{ tag: [t.definition(t.name), t.separator], color: "#ebdbb2" },
|
||||
{ tag: [t.brace], color: "#ebdbb2" },
|
||||
{
|
||||
tag: [t.annotation],
|
||||
color: '#fb4934d',
|
||||
color: "#fb4934d",
|
||||
},
|
||||
{
|
||||
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
||||
color: '#d3869b',
|
||||
color: "#d3869b",
|
||||
},
|
||||
{
|
||||
tag: [t.typeName, t.className],
|
||||
color: '#fabd2f',
|
||||
color: "#fabd2f",
|
||||
},
|
||||
{
|
||||
tag: [t.operator, t.operatorKeyword],
|
||||
color: '#fb4934',
|
||||
color: "#fb4934",
|
||||
},
|
||||
{
|
||||
tag: [t.tagName],
|
||||
color: '#8ec07c',
|
||||
fontStyle: 'bold',
|
||||
color: "#8ec07c",
|
||||
fontStyle: "bold",
|
||||
},
|
||||
{
|
||||
tag: [t.squareBracket],
|
||||
color: '#fe8019',
|
||||
color: "#fe8019",
|
||||
},
|
||||
{
|
||||
tag: [t.angleBracket],
|
||||
color: '#83a598',
|
||||
color: "#83a598",
|
||||
},
|
||||
{
|
||||
tag: [t.attributeName],
|
||||
color: '#8ec07c',
|
||||
color: "#8ec07c",
|
||||
},
|
||||
{
|
||||
tag: [t.regexp],
|
||||
color: '#8ec07c',
|
||||
color: "#8ec07c",
|
||||
},
|
||||
{
|
||||
tag: [t.quote],
|
||||
color: '#928374',
|
||||
color: "#928374",
|
||||
},
|
||||
{ tag: [t.string], color: '#ebdbb2' },
|
||||
{ tag: [t.string], color: "#ebdbb2" },
|
||||
{
|
||||
tag: t.link,
|
||||
color: '#a89984',
|
||||
textDecoration: 'underline',
|
||||
textUnderlinePosition: 'under',
|
||||
color: "#a89984",
|
||||
textDecoration: "underline",
|
||||
textUnderlinePosition: "under",
|
||||
},
|
||||
{
|
||||
tag: [t.url, t.escape, t.special(t.string)],
|
||||
color: '#d3869b',
|
||||
color: "#d3869b",
|
||||
},
|
||||
{ tag: [t.meta], color: '#fabd2f' },
|
||||
{ tag: [t.comment], color: '#928374', fontStyle: 'italic' },
|
||||
{ tag: t.strong, fontWeight: 'bold', color: '#fe8019' },
|
||||
{ tag: t.emphasis, fontStyle: 'italic', color: '#b8bb26' },
|
||||
{ tag: t.strikethrough, textDecoration: 'line-through' },
|
||||
{ tag: t.heading, fontWeight: 'bold', color: '#b8bb26' },
|
||||
{ tag: [t.heading1, t.heading2], fontWeight: 'bold', color: '#b8bb26' },
|
||||
{ tag: [t.meta], color: "#fabd2f" },
|
||||
{ tag: [t.comment], color: "#928374", fontStyle: "italic" },
|
||||
{ tag: t.strong, fontWeight: "bold", color: "#fe8019" },
|
||||
{ tag: t.emphasis, fontStyle: "italic", color: "#b8bb26" },
|
||||
{ tag: t.strikethrough, textDecoration: "line-through" },
|
||||
{ tag: t.heading, fontWeight: "bold", color: "#b8bb26" },
|
||||
{ tag: [t.heading1, t.heading2], fontWeight: "bold", color: "#b8bb26" },
|
||||
{
|
||||
tag: [t.heading3, t.heading4],
|
||||
fontWeight: 'bold',
|
||||
color: '#fabd2f',
|
||||
fontWeight: "bold",
|
||||
color: "#fabd2f",
|
||||
},
|
||||
{
|
||||
tag: [t.heading5, t.heading6],
|
||||
color: '#fabd2f',
|
||||
color: "#fabd2f",
|
||||
},
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#d3869b' },
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: "#d3869b" },
|
||||
{
|
||||
tag: [t.processingInstruction, t.inserted],
|
||||
color: '#83a598',
|
||||
color: "#83a598",
|
||||
},
|
||||
{
|
||||
tag: [t.contentSeparator],
|
||||
color: '#fb4934',
|
||||
color: "#fb4934",
|
||||
},
|
||||
{ tag: t.invalid, color: '#fe8019', borderBottom: `1px dotted #fb4934d` },
|
||||
{ tag: t.invalid, color: "#fe8019", borderBottom: `1px dotted #fb4934d` },
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,23 +23,26 @@ interface Theme {
|
|||
ext: Extension;
|
||||
}
|
||||
|
||||
const noBackground = { "settings" : { "background" : "none" }};
|
||||
const noBackground = { settings: { background: "none" } };
|
||||
|
||||
export const themes: { [key: string]: Theme } = {
|
||||
ayuDark: { name: "Ayu Dark", ext: ayuDark },
|
||||
andromeda: { name: "Andromeda", ext: andromedaInit(noBackground) },
|
||||
bespin : { name: "Bespin", ext: bespinInit(noBackground) },
|
||||
consoleDark : { name: "Console Dark", ext: consoleDarkInit(noBackground) },
|
||||
andromeda: { name: "Andromeda", ext: andromedaInit(noBackground) },
|
||||
bespin: { name: "Bespin", ext: bespinInit(noBackground) },
|
||||
consoleDark: { name: "Console Dark", ext: consoleDarkInit(noBackground) },
|
||||
dracula: { name: "Dracula", ext: dracula },
|
||||
githubDark : { name: "Github Dark", ext: githubDarkInit(noBackground) },
|
||||
githubDark: { name: "Github Dark", ext: githubDarkInit(noBackground) },
|
||||
gruvboxDark: { name: "Gruvbox Dark", ext: gruvboxDark },
|
||||
monokai : { name: "Monokai", ext: monokaiInit(noBackground) },
|
||||
monokai: { name: "Monokai", ext: monokaiInit(noBackground) },
|
||||
monokaiDimmed: { name: "Monokai Dimmed", ext: monokai },
|
||||
nord: { name: "Nord", ext: nord },
|
||||
oneDark: { name: "One Dark", ext: oneDark },
|
||||
solarizedDark : { name: "Solarized Dark", ext: solarizedDarkInit(noBackground) },
|
||||
solarizedDark: {
|
||||
name: "Solarized Dark",
|
||||
ext: solarizedDarkInit(noBackground),
|
||||
},
|
||||
tokyoNight: { name: "Tokyo Night", ext: tokyoNight },
|
||||
xcodeDark : { name: "XCode Dark", ext: xcodeDarkInit(noBackground) },
|
||||
xcodeDark: { name: "XCode Dark", ext: xcodeDarkInit(noBackground) },
|
||||
};
|
||||
|
||||
export default themes;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,34 @@
|
|||
import { createTheme } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme } from "@uiw/codemirror-themes";
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
|
||||
const monokaiColors = {
|
||||
background: 'transparent',
|
||||
foreground: '#c5c8c6',
|
||||
selection: '#4747a1',
|
||||
selectionMatch: '#4747a1',
|
||||
cursor: '#c07020',
|
||||
dropdownBackground: '#525252',
|
||||
activeLine: '#30303078',
|
||||
matchingBracket: '#303030',
|
||||
keyword: '#676867',
|
||||
storage: '#676867',
|
||||
variable: '#c7444a',
|
||||
parameter: '#6089B4',
|
||||
function: '#9872A2',
|
||||
string: '#D08442',
|
||||
constant: '#8080FF',
|
||||
type: '#9B0000',
|
||||
class: '#CE6700',
|
||||
number: '#6089B4',
|
||||
comment: '#9A9B99',
|
||||
heading: '#D0B344',
|
||||
invalid: '#FF0B00',
|
||||
regexp: '#D08442',
|
||||
tag: '#6089B4',
|
||||
background: "transparent",
|
||||
foreground: "#c5c8c6",
|
||||
selection: "#4747a1",
|
||||
selectionMatch: "#4747a1",
|
||||
cursor: "#c07020",
|
||||
dropdownBackground: "#525252",
|
||||
activeLine: "#30303078",
|
||||
matchingBracket: "#303030",
|
||||
keyword: "#676867",
|
||||
storage: "#676867",
|
||||
variable: "#c7444a",
|
||||
parameter: "#6089B4",
|
||||
function: "#9872A2",
|
||||
string: "#D08442",
|
||||
constant: "#8080FF",
|
||||
type: "#9B0000",
|
||||
class: "#CE6700",
|
||||
number: "#6089B4",
|
||||
comment: "#9A9B99",
|
||||
heading: "#D0B344",
|
||||
invalid: "#FF0B00",
|
||||
regexp: "#D08442",
|
||||
tag: "#6089B4",
|
||||
};
|
||||
|
||||
export const monokai = createTheme({
|
||||
theme: 'dark',
|
||||
theme: "dark",
|
||||
settings: {
|
||||
background: monokaiColors.background,
|
||||
foreground: monokaiColors.foreground,
|
||||
|
|
@ -41,25 +41,47 @@ export const monokai = createTheme({
|
|||
},
|
||||
styles: [
|
||||
{ tag: t.keyword, color: monokaiColors.keyword },
|
||||
{ tag: [t.name, t.deleted, t.character, t.macroName], color: monokaiColors.variable },
|
||||
{
|
||||
tag: [t.name, t.deleted, t.character, t.macroName],
|
||||
color: monokaiColors.variable,
|
||||
},
|
||||
{ tag: [t.propertyName], color: monokaiColors.function },
|
||||
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: monokaiColors.string },
|
||||
{ tag: [t.function(t.variableName), t.labelName], color: monokaiColors.function },
|
||||
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: monokaiColors.constant },
|
||||
{
|
||||
tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)],
|
||||
color: monokaiColors.string,
|
||||
},
|
||||
{
|
||||
tag: [t.function(t.variableName), t.labelName],
|
||||
color: monokaiColors.function,
|
||||
},
|
||||
{
|
||||
tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
||||
color: monokaiColors.constant,
|
||||
},
|
||||
{ tag: [t.definition(t.name), t.separator], color: monokaiColors.variable },
|
||||
{ tag: [t.className], color: monokaiColors.class },
|
||||
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: monokaiColors.number },
|
||||
{ tag: [t.typeName], color: monokaiColors.type, fontStyle: monokaiColors.type },
|
||||
{
|
||||
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
||||
color: monokaiColors.number,
|
||||
},
|
||||
{
|
||||
tag: [t.typeName],
|
||||
color: monokaiColors.type,
|
||||
fontStyle: monokaiColors.type,
|
||||
},
|
||||
{ tag: [t.operator, t.operatorKeyword], color: monokaiColors.keyword },
|
||||
{ tag: [t.url, t.escape, t.regexp, t.link], color: monokaiColors.regexp },
|
||||
{ tag: [t.meta, t.comment], color: monokaiColors.comment },
|
||||
{ tag: t.tagName, color: monokaiColors.tag },
|
||||
{ tag: t.strong, fontWeight: 'bold' },
|
||||
{ tag: t.emphasis, fontStyle: 'italic' },
|
||||
{ tag: t.link, textDecoration: 'underline' },
|
||||
{ tag: t.heading, fontWeight: 'bold', color: monokaiColors.heading },
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: monokaiColors.variable },
|
||||
{ tag: t.strong, fontWeight: "bold" },
|
||||
{ tag: t.emphasis, fontStyle: "italic" },
|
||||
{ tag: t.link, textDecoration: "underline" },
|
||||
{ tag: t.heading, fontWeight: "bold", color: monokaiColors.heading },
|
||||
{
|
||||
tag: [t.atom, t.bool, t.special(t.variableName)],
|
||||
color: monokaiColors.variable,
|
||||
},
|
||||
{ tag: t.invalid, color: monokaiColors.invalid },
|
||||
{ tag: t.strikethrough, textDecoration: 'line-through' },
|
||||
{ tag: t.strikethrough, textDecoration: "line-through" },
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,116 +1,116 @@
|
|||
import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme, CreateThemeOptions } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
import { createTheme, CreateThemeOptions } from "@uiw/codemirror-themes";
|
||||
|
||||
export const defaultSettingsNord: CreateThemeOptions['settings'] = {
|
||||
background: 'transparent',
|
||||
foreground: '#FFFFFF',
|
||||
caret: '#FFFFFF',
|
||||
selection: '#00000073',
|
||||
selectionMatch: '#00000073',
|
||||
gutterBackground: '#2e3440',
|
||||
gutterForeground: '#4c566a',
|
||||
gutterActiveForeground: '#d8dee9',
|
||||
lineHighlight: '#4c566a29',
|
||||
export const defaultSettingsNord: CreateThemeOptions["settings"] = {
|
||||
background: "transparent",
|
||||
foreground: "#FFFFFF",
|
||||
caret: "#FFFFFF",
|
||||
selection: "#00000073",
|
||||
selectionMatch: "#00000073",
|
||||
gutterBackground: "#2e3440",
|
||||
gutterForeground: "#4c566a",
|
||||
gutterActiveForeground: "#d8dee9",
|
||||
lineHighlight: "#4c566a29",
|
||||
};
|
||||
|
||||
export const nord = createTheme({
|
||||
theme: 'dark',
|
||||
settings: {
|
||||
...defaultSettingsNord,
|
||||
theme: "dark",
|
||||
settings: {
|
||||
...defaultSettingsNord,
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.keyword, color: "#5e81ac" },
|
||||
{
|
||||
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
||||
color: "#88c0d0",
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.keyword, color: '#5e81ac' },
|
||||
{
|
||||
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
||||
color: '#88c0d0',
|
||||
},
|
||||
{ tag: [t.variableName], color: '#8fbcbb' },
|
||||
{ tag: [t.function(t.variableName)], color: '#8fbcbb' },
|
||||
{ tag: [t.labelName], color: '#81a1c1' },
|
||||
{
|
||||
tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
||||
color: '#5e81ac',
|
||||
},
|
||||
{ tag: [t.definition(t.name), t.separator], color: '#a3be8c' },
|
||||
{ tag: [t.brace], color: '#8fbcbb' },
|
||||
{
|
||||
tag: [t.annotation],
|
||||
color: '#d30102',
|
||||
},
|
||||
{
|
||||
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
||||
color: '#b48ead',
|
||||
},
|
||||
{
|
||||
tag: [t.typeName, t.className],
|
||||
color: '#ebcb8b',
|
||||
},
|
||||
{
|
||||
tag: [t.operator, t.operatorKeyword],
|
||||
color: '#a3be8c',
|
||||
},
|
||||
{
|
||||
tag: [t.tagName],
|
||||
color: '#b48ead',
|
||||
},
|
||||
{
|
||||
tag: [t.squareBracket],
|
||||
color: '#bf616a',
|
||||
},
|
||||
{
|
||||
tag: [t.angleBracket],
|
||||
color: '#d08770',
|
||||
},
|
||||
{
|
||||
tag: [t.attributeName],
|
||||
color: '#ebcb8b',
|
||||
},
|
||||
{
|
||||
tag: [t.regexp],
|
||||
color: '#5e81ac',
|
||||
},
|
||||
{
|
||||
tag: [t.quote],
|
||||
color: '#b48ead',
|
||||
},
|
||||
{ tag: [t.string], color: '#a3be8c' },
|
||||
{
|
||||
tag: t.link,
|
||||
color: '#a3be8c',
|
||||
textDecoration: 'underline',
|
||||
textUnderlinePosition: 'under',
|
||||
},
|
||||
{
|
||||
tag: [t.url, t.escape, t.special(t.string)],
|
||||
color: '#8fbcbb',
|
||||
},
|
||||
{ tag: [t.meta], color: '#88c0d0' },
|
||||
{ tag: [t.monospace], color: '#d8dee9', fontStyle: 'italic' },
|
||||
{ tag: [t.comment], color: '#4c566a', fontStyle: 'italic' },
|
||||
{ tag: t.strong, fontWeight: 'bold', color: '#5e81ac' },
|
||||
{ tag: t.emphasis, fontStyle: 'italic', color: '#5e81ac' },
|
||||
{ tag: t.strikethrough, textDecoration: 'line-through' },
|
||||
{ tag: t.heading, fontWeight: 'bold', color: '#5e81ac' },
|
||||
{ tag: t.special(t.heading1), fontWeight: 'bold', color: '#5e81ac' },
|
||||
{ tag: t.heading1, fontWeight: 'bold', color: '#5e81ac' },
|
||||
{
|
||||
tag: [t.heading2, t.heading3, t.heading4],
|
||||
fontWeight: 'bold',
|
||||
color: '#5e81ac',
|
||||
},
|
||||
{
|
||||
tag: [t.heading5, t.heading6],
|
||||
color: '#5e81ac',
|
||||
},
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#d08770' },
|
||||
{
|
||||
tag: [t.processingInstruction, t.inserted],
|
||||
color: '#8fbcbb',
|
||||
},
|
||||
{
|
||||
tag: [t.contentSeparator],
|
||||
color: '#ebcb8b',
|
||||
},
|
||||
{ tag: t.invalid, color: '#434c5e', borderBottom: `1px dotted #d30102` },
|
||||
],
|
||||
});
|
||||
{ tag: [t.variableName], color: "#8fbcbb" },
|
||||
{ tag: [t.function(t.variableName)], color: "#8fbcbb" },
|
||||
{ tag: [t.labelName], color: "#81a1c1" },
|
||||
{
|
||||
tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
||||
color: "#5e81ac",
|
||||
},
|
||||
{ tag: [t.definition(t.name), t.separator], color: "#a3be8c" },
|
||||
{ tag: [t.brace], color: "#8fbcbb" },
|
||||
{
|
||||
tag: [t.annotation],
|
||||
color: "#d30102",
|
||||
},
|
||||
{
|
||||
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
||||
color: "#b48ead",
|
||||
},
|
||||
{
|
||||
tag: [t.typeName, t.className],
|
||||
color: "#ebcb8b",
|
||||
},
|
||||
{
|
||||
tag: [t.operator, t.operatorKeyword],
|
||||
color: "#a3be8c",
|
||||
},
|
||||
{
|
||||
tag: [t.tagName],
|
||||
color: "#b48ead",
|
||||
},
|
||||
{
|
||||
tag: [t.squareBracket],
|
||||
color: "#bf616a",
|
||||
},
|
||||
{
|
||||
tag: [t.angleBracket],
|
||||
color: "#d08770",
|
||||
},
|
||||
{
|
||||
tag: [t.attributeName],
|
||||
color: "#ebcb8b",
|
||||
},
|
||||
{
|
||||
tag: [t.regexp],
|
||||
color: "#5e81ac",
|
||||
},
|
||||
{
|
||||
tag: [t.quote],
|
||||
color: "#b48ead",
|
||||
},
|
||||
{ tag: [t.string], color: "#a3be8c" },
|
||||
{
|
||||
tag: t.link,
|
||||
color: "#a3be8c",
|
||||
textDecoration: "underline",
|
||||
textUnderlinePosition: "under",
|
||||
},
|
||||
{
|
||||
tag: [t.url, t.escape, t.special(t.string)],
|
||||
color: "#8fbcbb",
|
||||
},
|
||||
{ tag: [t.meta], color: "#88c0d0" },
|
||||
{ tag: [t.monospace], color: "#d8dee9", fontStyle: "italic" },
|
||||
{ tag: [t.comment], color: "#4c566a", fontStyle: "italic" },
|
||||
{ tag: t.strong, fontWeight: "bold", color: "#5e81ac" },
|
||||
{ tag: t.emphasis, fontStyle: "italic", color: "#5e81ac" },
|
||||
{ tag: t.strikethrough, textDecoration: "line-through" },
|
||||
{ tag: t.heading, fontWeight: "bold", color: "#5e81ac" },
|
||||
{ tag: t.special(t.heading1), fontWeight: "bold", color: "#5e81ac" },
|
||||
{ tag: t.heading1, fontWeight: "bold", color: "#5e81ac" },
|
||||
{
|
||||
tag: [t.heading2, t.heading3, t.heading4],
|
||||
fontWeight: "bold",
|
||||
color: "#5e81ac",
|
||||
},
|
||||
{
|
||||
tag: [t.heading5, t.heading6],
|
||||
color: "#5e81ac",
|
||||
},
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: "#d08770" },
|
||||
{
|
||||
tag: [t.processingInstruction, t.inserted],
|
||||
color: "#8fbcbb",
|
||||
},
|
||||
{
|
||||
tag: [t.contentSeparator],
|
||||
color: "#ebcb8b",
|
||||
},
|
||||
{ tag: t.invalid, color: "#434c5e", borderBottom: `1px dotted #d30102` },
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {EditorView} from "@codemirror/view"
|
||||
import {Extension} from "@codemirror/state"
|
||||
import {HighlightStyle, syntaxHighlighting} from "@codemirror/language"
|
||||
import {tags as t} from "@lezer/highlight"
|
||||
import { EditorView } from "@codemirror/view";
|
||||
import { Extension } from "@codemirror/state";
|
||||
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
|
||||
// Using https://github.com/one-dark/vscode-one-dark-theme/ as reference for the colors
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ const chalky = "#e5c07b",
|
|||
background = "#282c34",
|
||||
tooltipBackground = "#353a42",
|
||||
selection = "#3E4451",
|
||||
cursor = "#528bff"
|
||||
cursor = "#528bff";
|
||||
|
||||
/// The colors used in the theme, as CSS color strings.
|
||||
export const color = {
|
||||
|
|
@ -39,117 +39,132 @@ export const color = {
|
|||
background,
|
||||
tooltipBackground,
|
||||
selection,
|
||||
cursor
|
||||
}
|
||||
cursor,
|
||||
};
|
||||
|
||||
/// The editor theme styles for One Dark.
|
||||
export const oneDarkTheme = EditorView.theme({
|
||||
"&": {
|
||||
color: ivory,
|
||||
// backgroundColor: "background"
|
||||
backgroundColor: "none"
|
||||
},
|
||||
export const oneDarkTheme = EditorView.theme(
|
||||
{
|
||||
"&": {
|
||||
color: ivory,
|
||||
// backgroundColor: "background"
|
||||
backgroundColor: "none",
|
||||
},
|
||||
|
||||
".cm-content": {
|
||||
caretColor: cursor
|
||||
},
|
||||
".cm-content": {
|
||||
caretColor: cursor,
|
||||
},
|
||||
|
||||
".cm-cursor, .cm-dropCursor": {borderLeftColor: cursor},
|
||||
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {backgroundColor: selection},
|
||||
".cm-cursor, .cm-dropCursor": { borderLeftColor: cursor },
|
||||
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":
|
||||
{ backgroundColor: selection },
|
||||
|
||||
".cm-panels": {backgroundColor: darkBackground, color: ivory},
|
||||
".cm-panels.cm-panels-top": {borderBottom: "2px solid black"},
|
||||
".cm-panels.cm-panels-bottom": {borderTop: "2px solid black"},
|
||||
".cm-panels": { backgroundColor: darkBackground, color: ivory },
|
||||
".cm-panels.cm-panels-top": { borderBottom: "2px solid black" },
|
||||
".cm-panels.cm-panels-bottom": { borderTop: "2px solid black" },
|
||||
|
||||
".cm-searchMatch": {
|
||||
backgroundColor: "#72a1ff59",
|
||||
outline: "1px solid #457dff"
|
||||
},
|
||||
".cm-searchMatch.cm-searchMatch-selected": {
|
||||
backgroundColor: "#6199ff2f"
|
||||
},
|
||||
".cm-searchMatch": {
|
||||
backgroundColor: "#72a1ff59",
|
||||
outline: "1px solid #457dff",
|
||||
},
|
||||
".cm-searchMatch.cm-searchMatch-selected": {
|
||||
backgroundColor: "#6199ff2f",
|
||||
},
|
||||
|
||||
".cm-activeLine": {backgroundColor: "#6699ff0b"},
|
||||
".cm-selectionMatch": {backgroundColor: "#aafe661a"},
|
||||
".cm-activeLine": { backgroundColor: "#6699ff0b" },
|
||||
".cm-selectionMatch": { backgroundColor: "#aafe661a" },
|
||||
|
||||
"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
|
||||
backgroundColor: "#bad0f847"
|
||||
},
|
||||
"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
|
||||
backgroundColor: "#bad0f847",
|
||||
},
|
||||
|
||||
".cm-gutters": {
|
||||
backgroundColor: background,
|
||||
color: stone,
|
||||
border: "none"
|
||||
},
|
||||
".cm-gutters": {
|
||||
backgroundColor: background,
|
||||
color: stone,
|
||||
border: "none",
|
||||
},
|
||||
|
||||
".cm-activeLineGutter": {
|
||||
backgroundColor: highlightBackground
|
||||
},
|
||||
|
||||
".cm-foldPlaceholder": {
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
color: "#ddd"
|
||||
},
|
||||
|
||||
".cm-tooltip": {
|
||||
border: "none",
|
||||
backgroundColor: tooltipBackground
|
||||
},
|
||||
".cm-tooltip .cm-tooltip-arrow:before": {
|
||||
borderTopColor: "transparent",
|
||||
borderBottomColor: "transparent"
|
||||
},
|
||||
".cm-tooltip .cm-tooltip-arrow:after": {
|
||||
borderTopColor: tooltipBackground,
|
||||
borderBottomColor: tooltipBackground
|
||||
},
|
||||
".cm-tooltip-autocomplete": {
|
||||
"& > ul > li[aria-selected]": {
|
||||
".cm-activeLineGutter": {
|
||||
backgroundColor: highlightBackground,
|
||||
color: ivory
|
||||
}
|
||||
}
|
||||
}, {dark: true})
|
||||
},
|
||||
|
||||
".cm-foldPlaceholder": {
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
color: "#ddd",
|
||||
},
|
||||
|
||||
".cm-tooltip": {
|
||||
border: "none",
|
||||
backgroundColor: tooltipBackground,
|
||||
},
|
||||
".cm-tooltip .cm-tooltip-arrow:before": {
|
||||
borderTopColor: "transparent",
|
||||
borderBottomColor: "transparent",
|
||||
},
|
||||
".cm-tooltip .cm-tooltip-arrow:after": {
|
||||
borderTopColor: tooltipBackground,
|
||||
borderBottomColor: tooltipBackground,
|
||||
},
|
||||
".cm-tooltip-autocomplete": {
|
||||
"& > ul > li[aria-selected]": {
|
||||
backgroundColor: highlightBackground,
|
||||
color: ivory,
|
||||
},
|
||||
},
|
||||
},
|
||||
{ dark: true },
|
||||
);
|
||||
|
||||
/// The highlighting style for code in the One Dark theme.
|
||||
export const oneDarkHighlightStyle = HighlightStyle.define([
|
||||
{tag: t.keyword,
|
||||
color: violet},
|
||||
{tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
||||
color: coral},
|
||||
{tag: [t.function(t.variableName), t.labelName],
|
||||
color: malibu},
|
||||
{tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
||||
color: whiskey},
|
||||
{tag: [t.definition(t.name), t.separator],
|
||||
color: ivory},
|
||||
{tag: [t.typeName, t.className, t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
||||
color: chalky},
|
||||
{tag: [t.operator, t.operatorKeyword, t.url, t.escape, t.regexp, t.link, t.special(t.string)],
|
||||
color: cyan},
|
||||
{tag: [t.meta, t.comment],
|
||||
color: stone},
|
||||
{tag: t.strong,
|
||||
fontWeight: "bold"},
|
||||
{tag: t.emphasis,
|
||||
fontStyle: "italic"},
|
||||
{tag: t.strikethrough,
|
||||
textDecoration: "line-through"},
|
||||
{tag: t.link,
|
||||
color: stone,
|
||||
textDecoration: "underline"},
|
||||
{tag: t.heading,
|
||||
fontWeight: "bold",
|
||||
color: coral},
|
||||
{tag: [t.atom, t.bool, t.special(t.variableName)],
|
||||
color: whiskey },
|
||||
{tag: [t.processingInstruction, t.string, t.inserted],
|
||||
color: sage},
|
||||
{tag: t.invalid,
|
||||
color: invalid},
|
||||
])
|
||||
{ tag: t.keyword, color: violet },
|
||||
{
|
||||
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
||||
color: coral,
|
||||
},
|
||||
{ tag: [t.function(t.variableName), t.labelName], color: malibu },
|
||||
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: whiskey },
|
||||
{ tag: [t.definition(t.name), t.separator], color: ivory },
|
||||
{
|
||||
tag: [
|
||||
t.typeName,
|
||||
t.className,
|
||||
t.number,
|
||||
t.changed,
|
||||
t.annotation,
|
||||
t.modifier,
|
||||
t.self,
|
||||
t.namespace,
|
||||
],
|
||||
color: chalky,
|
||||
},
|
||||
{
|
||||
tag: [
|
||||
t.operator,
|
||||
t.operatorKeyword,
|
||||
t.url,
|
||||
t.escape,
|
||||
t.regexp,
|
||||
t.link,
|
||||
t.special(t.string),
|
||||
],
|
||||
color: cyan,
|
||||
},
|
||||
{ tag: [t.meta, t.comment], color: stone },
|
||||
{ tag: t.strong, fontWeight: "bold" },
|
||||
{ tag: t.emphasis, fontStyle: "italic" },
|
||||
{ tag: t.strikethrough, textDecoration: "line-through" },
|
||||
{ tag: t.link, color: stone, textDecoration: "underline" },
|
||||
{ tag: t.heading, fontWeight: "bold", color: coral },
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: whiskey },
|
||||
{ tag: [t.processingInstruction, t.string, t.inserted], color: sage },
|
||||
{ tag: t.invalid, color: invalid },
|
||||
]);
|
||||
|
||||
/// Extension to enable the One Dark theme (both the editor theme and
|
||||
/// the highlight style).
|
||||
export const oneDark: Extension = [oneDarkTheme, syntaxHighlighting(oneDarkHighlightStyle)]
|
||||
export const oneDark: Extension = [
|
||||
oneDarkTheme,
|
||||
syntaxHighlighting(oneDarkHighlightStyle),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,43 +1,52 @@
|
|||
import { tags as t } from '@lezer/highlight';
|
||||
import { createTheme, CreateThemeOptions } from '@uiw/codemirror-themes';
|
||||
import { tags as t } from "@lezer/highlight";
|
||||
import { createTheme, CreateThemeOptions } from "@uiw/codemirror-themes";
|
||||
|
||||
export const defaultSettingsTokyoNight: CreateThemeOptions['settings'] = {
|
||||
background: 'transparent',
|
||||
foreground: '#787c99',
|
||||
caret: '#c0caf5',
|
||||
selection: '#515c7e40',
|
||||
selectionMatch: '#16161e',
|
||||
gutterBackground: '#1a1b26',
|
||||
gutterForeground: '#787c99',
|
||||
gutterBorder: 'transparent',
|
||||
lineHighlight: '#474b6611',
|
||||
export const defaultSettingsTokyoNight: CreateThemeOptions["settings"] = {
|
||||
background: "transparent",
|
||||
foreground: "#787c99",
|
||||
caret: "#c0caf5",
|
||||
selection: "#515c7e40",
|
||||
selectionMatch: "#16161e",
|
||||
gutterBackground: "#1a1b26",
|
||||
gutterForeground: "#787c99",
|
||||
gutterBorder: "transparent",
|
||||
lineHighlight: "#474b6611",
|
||||
};
|
||||
|
||||
export const tokyoNight = createTheme({
|
||||
theme: 'dark',
|
||||
settings: {
|
||||
...defaultSettingsTokyoNight,
|
||||
theme: "dark",
|
||||
settings: {
|
||||
...defaultSettingsTokyoNight,
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.keyword, color: "#bb9af7" },
|
||||
{ tag: [t.name, t.deleted, t.character, t.macroName], color: "#c0caf5" },
|
||||
{ tag: [t.propertyName], color: "#7aa2f7" },
|
||||
{
|
||||
tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)],
|
||||
color: "#9ece6a",
|
||||
},
|
||||
styles: [
|
||||
{ tag: t.keyword, color: '#bb9af7' },
|
||||
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#c0caf5' },
|
||||
{ tag: [t.propertyName], color: '#7aa2f7' },
|
||||
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: '#9ece6a' },
|
||||
{ tag: [t.function(t.variableName), t.labelName], color: '#7aa2f7' },
|
||||
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#bb9af7' },
|
||||
{ tag: [t.definition(t.name), t.separator], color: '#c0caf5' },
|
||||
{ tag: [t.className], color: '#c0caf5' },
|
||||
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#ff9e64' },
|
||||
{ tag: [t.typeName], color: '#0db9d7' },
|
||||
{ tag: [t.operator, t.operatorKeyword], color: '#bb9af7' },
|
||||
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#b4f9f8' },
|
||||
{ tag: [t.meta, t.comment], color: '#444b6a' },
|
||||
{ tag: t.strong, fontWeight: 'bold' },
|
||||
{ tag: t.emphasis, fontStyle: 'italic' },
|
||||
{ tag: t.link, textDecoration: 'underline' },
|
||||
{ tag: t.heading, fontWeight: 'bold', color: '#89ddff' },
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#c0caf5' },
|
||||
{ tag: t.invalid, color: '#ff5370' },
|
||||
{ tag: t.strikethrough, textDecoration: 'line-through' },
|
||||
],
|
||||
});
|
||||
{ tag: [t.function(t.variableName), t.labelName], color: "#7aa2f7" },
|
||||
{
|
||||
tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
||||
color: "#bb9af7",
|
||||
},
|
||||
{ tag: [t.definition(t.name), t.separator], color: "#c0caf5" },
|
||||
{ tag: [t.className], color: "#c0caf5" },
|
||||
{
|
||||
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
||||
color: "#ff9e64",
|
||||
},
|
||||
{ tag: [t.typeName], color: "#0db9d7" },
|
||||
{ tag: [t.operator, t.operatorKeyword], color: "#bb9af7" },
|
||||
{ tag: [t.url, t.escape, t.regexp, t.link], color: "#b4f9f8" },
|
||||
{ tag: [t.meta, t.comment], color: "#444b6a" },
|
||||
{ tag: t.strong, fontWeight: "bold" },
|
||||
{ tag: t.emphasis, fontStyle: "italic" },
|
||||
{ tag: t.link, textDecoration: "underline" },
|
||||
{ tag: t.heading, fontWeight: "bold", color: "#89ddff" },
|
||||
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: "#c0caf5" },
|
||||
{ tag: t.invalid, color: "#ff5370" },
|
||||
{ tag: t.strikethrough, textDecoration: "line-through" },
|
||||
],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export function base64ToUnicode(base64String: string) {
|
|||
const utf8Bytes = new Uint8Array(
|
||||
atob(base64String)
|
||||
.split("")
|
||||
.map((char) => char.charCodeAt(0))
|
||||
.map((char) => char.charCodeAt(0)),
|
||||
);
|
||||
const decoder = new TextDecoder("utf-8", { fatal: true });
|
||||
const decodedText = decoder.decode(utf8Bytes);
|
||||
|
|
@ -80,7 +80,7 @@ export function sendToast(
|
|||
variant: "warning" | "destructive",
|
||||
title: string,
|
||||
message: string,
|
||||
pre?: boolean
|
||||
pre?: boolean,
|
||||
) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
|
|
@ -92,7 +92,7 @@ export function sendToast(
|
|||
pre,
|
||||
},
|
||||
},
|
||||
"*"
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ export function updateDocumentsContext(docId: string, context: object) {
|
|||
export function forEachDocumentContext(
|
||||
callback: (context: any, editor: ReactCodeMirrorRef | null) => void,
|
||||
session: Session,
|
||||
editorRefs: React.RefObject<ReactCodeMirrorRef>[]
|
||||
editorRefs: React.RefObject<ReactCodeMirrorRef>[],
|
||||
) {
|
||||
const documentsContext = window.documentsContext || {};
|
||||
for (const docId in documentsContext) {
|
||||
|
|
|
|||
|
|
@ -28,5 +28,5 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
|||
<HelmetProvider>
|
||||
<RouterProvider router={router} />
|
||||
</HelmetProvider>
|
||||
</React.StrictMode>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -18,14 +18,16 @@ export function Component() {
|
|||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const hasWebGl = useMemo(() => isWebglSupported(), []);
|
||||
const [instance, setInstance] = useState<HydraWrapper | null>(null);
|
||||
const [displaySettings, setDisplaySettings] = useState(defaultDisplaySettings);
|
||||
const [displaySettings, setDisplaySettings] = useState(
|
||||
defaultDisplaySettings,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasWebGl) return;
|
||||
sendToast(
|
||||
"warning",
|
||||
"WebGL not available",
|
||||
"WebGL is disabled or not supported, so Hydra was not initialized"
|
||||
"WebGL is disabled or not supported, so Hydra was not initialized",
|
||||
);
|
||||
}, [hasWebGl]);
|
||||
|
||||
|
|
@ -58,7 +60,7 @@ export function Component() {
|
|||
useCallback(() => {
|
||||
window.m = window.parent?.mercury?.m;
|
||||
window.strudel = window.parent?.strudel?.strudel;
|
||||
}, [])
|
||||
}, []),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -71,8 +73,8 @@ export function Component() {
|
|||
if (!instance) return;
|
||||
instance.tryEval(msg.body);
|
||||
},
|
||||
[instance]
|
||||
)
|
||||
[instance],
|
||||
),
|
||||
);
|
||||
|
||||
useSettings(
|
||||
|
|
@ -83,9 +85,18 @@ export function Component() {
|
|||
setDisplaySettings(msg.displaySettings);
|
||||
}
|
||||
},
|
||||
[instance]
|
||||
)
|
||||
[instance],
|
||||
),
|
||||
);
|
||||
|
||||
return hasWebGl && canvasRef && <HydraCanvas ref={canvasRef} fullscreen displaySettings={displaySettings} />;
|
||||
return (
|
||||
hasWebGl &&
|
||||
canvasRef && (
|
||||
<HydraCanvas
|
||||
ref={canvasRef}
|
||||
fullscreen
|
||||
displaySettings={displaySettings}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ export function Component() {
|
|||
if (!instance) return;
|
||||
instance.tryEval(msg.body);
|
||||
},
|
||||
[instance]
|
||||
)
|
||||
[instance],
|
||||
),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ export function Component() {
|
|||
if (!instance) return;
|
||||
instance.tryEval(msg);
|
||||
},
|
||||
[instance]
|
||||
)
|
||||
[instance],
|
||||
),
|
||||
);
|
||||
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,10 @@ import { useQuery } from "@/hooks/use-query";
|
|||
import { useShortcut } from "@/hooks/use-shortcut";
|
||||
import { useStrudelCodemirrorExtensions } from "@/hooks/use-strudel-codemirror-extensions";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { DisplaySettings, defaultDisplaySettings } from "@/lib/display-settings";
|
||||
import {
|
||||
DisplaySettings,
|
||||
defaultDisplaySettings,
|
||||
} from "@/lib/display-settings";
|
||||
import {
|
||||
cn,
|
||||
code2hash,
|
||||
|
|
@ -95,7 +98,8 @@ export function Component() {
|
|||
const [welcomeDialogOpen, setWelcomeDialogOpen] = useState(false);
|
||||
const [shareUrlDialogOpen, setShareUrlDialogOpen] = useState(false);
|
||||
const [configureDialogOpen, setConfigureDialogOpen] = useState(false);
|
||||
const [displaySettingsDialogOpen, setDisplaySettingsDialogOpen] = useState(false);
|
||||
const [displaySettingsDialogOpen, setDisplaySettingsDialogOpen] =
|
||||
useState(false);
|
||||
const [documents, setDocuments] = useState<Document[]>([]);
|
||||
const [hidden, setHidden] = useState<boolean>(false);
|
||||
|
||||
|
|
@ -113,17 +117,19 @@ export function Component() {
|
|||
});
|
||||
|
||||
// Display settings: Try to restore from local storage or use default settings
|
||||
const [displaySettings, setDisplaySettings] = useState<DisplaySettings>(() => {
|
||||
const savedSettings = localStorage.getItem("display-settings");
|
||||
if (savedSettings) {
|
||||
try {
|
||||
return JSON.parse(savedSettings);
|
||||
} catch (error) {
|
||||
console.error("Error parsing saved display settings:", error);
|
||||
const [displaySettings, setDisplaySettings] = useState<DisplaySettings>(
|
||||
() => {
|
||||
const savedSettings = localStorage.getItem("display-settings");
|
||||
if (savedSettings) {
|
||||
try {
|
||||
return JSON.parse(savedSettings);
|
||||
} catch (error) {
|
||||
console.error("Error parsing saved display settings:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
return defaultDisplaySettings;
|
||||
});
|
||||
return defaultDisplaySettings;
|
||||
},
|
||||
);
|
||||
|
||||
// Save editor settings to local storage
|
||||
useEffect(() => {
|
||||
|
|
@ -140,15 +146,15 @@ export function Component() {
|
|||
const [messagesCount, setMessagesCount] = useState<number>(0);
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [autoShowMessages, setAutoShowMessages] = useState<boolean>(
|
||||
store.get("messages:autoshow", true)
|
||||
store.get("messages:autoshow", true),
|
||||
);
|
||||
const [hideMessagesOnEval, setHideMessagesOnEval] = useState<boolean>(
|
||||
store.get("messages:hide-on-eval", true)
|
||||
store.get("messages:hide-on-eval", true),
|
||||
);
|
||||
const [sessionUrl, setSessionUrl] = useState<string>("");
|
||||
|
||||
const editorRefs = Array.from({ length: 8 }).map(() =>
|
||||
useRef<ReactCodeMirrorRef>(null)
|
||||
useRef<ReactCodeMirrorRef>(null),
|
||||
);
|
||||
|
||||
useStrudelCodemirrorExtensions(session, editorRefs);
|
||||
|
|
@ -162,7 +168,7 @@ export function Component() {
|
|||
if (hideErrors) return;
|
||||
_toast(options);
|
||||
},
|
||||
[_toast, hideErrors]
|
||||
[_toast, hideErrors],
|
||||
);
|
||||
|
||||
const postMessageParentWindow = (message: any) => {
|
||||
|
|
@ -198,7 +204,7 @@ export function Component() {
|
|||
// Otherwise, use default target.
|
||||
if (newSession.getDocuments().length === 0) {
|
||||
console.log(
|
||||
"Session is empty, setting targets and code from hash params"
|
||||
"Session is empty, setting targets and code from hash params",
|
||||
);
|
||||
// If `targets` hash param is present and has valid targets, set them as
|
||||
// active documents.
|
||||
|
|
@ -302,7 +308,7 @@ export function Component() {
|
|||
console.log(
|
||||
`%c${target}` + `%c ${content}`,
|
||||
"font-weight: bold",
|
||||
type === "stderr" ? "color: #ff5f6b" : ""
|
||||
type === "stderr" ? "color: #ff5f6b" : "",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
@ -421,17 +427,17 @@ export function Component() {
|
|||
|
||||
const getFocusedEditorIndex = (): number => {
|
||||
const i = editorRefs.findIndex(
|
||||
(ref) => ref.current && ref.current.view?.hasFocus
|
||||
(ref) => ref.current && ref.current.view?.hasFocus,
|
||||
);
|
||||
return i;
|
||||
};
|
||||
|
||||
// Global shortcuts
|
||||
useShortcut(["Control-J", "Meta-J"], () =>
|
||||
setCommandsDialogOpen((open) => !open)
|
||||
setCommandsDialogOpen((open) => !open),
|
||||
);
|
||||
useShortcut(["Control-P", "Meta-P"], () =>
|
||||
setConfigureDialogOpen((open) => !open)
|
||||
setConfigureDialogOpen((open) => !open),
|
||||
);
|
||||
useShortcut(
|
||||
["Control-Shift-.", "Meta-Shift-."],
|
||||
|
|
@ -442,7 +448,7 @@ export function Component() {
|
|||
});
|
||||
toast({ title: "Panic!", duration: 1000 });
|
||||
},
|
||||
[documents]
|
||||
[documents],
|
||||
);
|
||||
Array.from({ length: 8 }).map((_, i) => {
|
||||
useShortcut([`Control-${i}`], () => focusEditor(i - 1), [...editorRefs]);
|
||||
|
|
@ -455,7 +461,7 @@ export function Component() {
|
|||
const newIndex = mod(curIndex - 1, documents.length);
|
||||
focusEditor(newIndex);
|
||||
},
|
||||
[documents, ...editorRefs]
|
||||
[documents, ...editorRefs],
|
||||
);
|
||||
useShortcut(
|
||||
["Control-]"],
|
||||
|
|
@ -465,7 +471,7 @@ export function Component() {
|
|||
const newIndex = mod(curIndex + 1, documents.length);
|
||||
focusEditor(newIndex);
|
||||
},
|
||||
[documents, ...editorRefs]
|
||||
[documents, ...editorRefs],
|
||||
);
|
||||
useShortcut(["Meta-Shift-H", "Control-Shift-H"], () => {
|
||||
setHidden((p) => !p);
|
||||
|
|
@ -477,14 +483,14 @@ export function Component() {
|
|||
const replTargets = useMemo(
|
||||
() =>
|
||||
[...new Set(documents.map((doc) => doc.target))].filter(
|
||||
(t) => !webTargets.includes(t)
|
||||
(t) => !webTargets.includes(t),
|
||||
),
|
||||
[documents]
|
||||
[documents],
|
||||
);
|
||||
|
||||
const targetsList = useMemo(
|
||||
() => documents.map((doc) => doc.target),
|
||||
[documents]
|
||||
[documents],
|
||||
);
|
||||
|
||||
const OS = navigator.userAgent.indexOf("Windows") != -1 ? "windows" : "unix";
|
||||
|
|
@ -524,7 +530,7 @@ export function Component() {
|
|||
session.setActiveDocuments(
|
||||
targets
|
||||
.filter((t) => t)
|
||||
.map((target, i) => ({ id: String(i + 1), target }))
|
||||
.map((target, i) => ({ id: String(i + 1), target })),
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -548,9 +554,9 @@ export function Component() {
|
|||
const activeWebTargets = useMemo(
|
||||
() =>
|
||||
webTargets.filter((target) =>
|
||||
documents.some((doc) => doc.target === target)
|
||||
documents.some((doc) => doc.target === target),
|
||||
),
|
||||
[documents]
|
||||
[documents],
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
@ -573,9 +579,7 @@ export function Component() {
|
|||
onLayoutAdd={handleViewLayoutAdd}
|
||||
onLayoutRemove={handleViewLayoutRemove}
|
||||
onLayoutConfigure={() => setConfigureDialogOpen(true)}
|
||||
onEditorChangeDisplaySettings={() =>
|
||||
setDisplaySettingsDialogOpen(true)
|
||||
}
|
||||
onEditorChangeDisplaySettings={() => setDisplaySettingsDialogOpen(true)}
|
||||
/>
|
||||
<UsernameDialog
|
||||
name={username}
|
||||
|
|
@ -624,7 +628,7 @@ export function Component() {
|
|||
<Mosaic
|
||||
className={cn(
|
||||
"transition-opacity",
|
||||
hidden ? "opacity-0" : "opacity-100"
|
||||
hidden ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
items={documents.map((doc, i) => (
|
||||
<Pane
|
||||
|
|
@ -644,13 +648,18 @@ export function Component() {
|
|||
))}
|
||||
/>
|
||||
{activeWebTargets.map((target) => (
|
||||
<WebTargetIframe key={target} session={session} target={target} displaySettings={displaySettings} />
|
||||
<WebTargetIframe
|
||||
key={target}
|
||||
session={session}
|
||||
target={target}
|
||||
displaySettings={displaySettings}
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className={cn(
|
||||
"fixed top-1 right-1 flex m-1",
|
||||
"transition-opacity",
|
||||
hidden ? "opacity-0" : "opacity-100"
|
||||
hidden ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
>
|
||||
{replTargets.length > 0 && (
|
||||
|
|
@ -662,7 +671,7 @@ export function Component() {
|
|||
<MessagesPanel
|
||||
className={cn(
|
||||
"transition-opacity",
|
||||
hidden ? "opacity-0" : "opacity-100"
|
||||
hidden ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
messages={messages}
|
||||
autoShowMessages={autoShowMessages}
|
||||
|
|
@ -675,7 +684,7 @@ export function Component() {
|
|||
<StatusBar
|
||||
className={cn(
|
||||
"transition-opacity",
|
||||
hidden ? "opacity-0" : "opacity-100"
|
||||
hidden ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
pubSubState={pubSubState}
|
||||
syncState={syncState}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
const { fontFamily } = require("tailwindcss/defaultTheme")
|
||||
const { fontFamily } = require("tailwindcss/defaultTheme");
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
|
|
@ -30,4 +27,4 @@ module.exports = {
|
|||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,11 +6,10 @@ import pc from "picocolors";
|
|||
let Vite;
|
||||
try {
|
||||
Vite = await import("vite");
|
||||
} catch (err) { }
|
||||
|
||||
} catch (err) {}
|
||||
|
||||
const _State = {
|
||||
viteConfig: undefined
|
||||
viteConfig: undefined,
|
||||
};
|
||||
|
||||
function clearState() {
|
||||
|
|
@ -18,9 +17,10 @@ function clearState() {
|
|||
}
|
||||
|
||||
const Config = {
|
||||
mode: (process.env.NODE_ENV === "production" || !Vite
|
||||
? "production"
|
||||
: "development"),
|
||||
mode:
|
||||
process.env.NODE_ENV === "production" || !Vite
|
||||
? "production"
|
||||
: "development",
|
||||
inlineViteConfig: undefined,
|
||||
viteConfigFile: undefined,
|
||||
ignorePaths: undefined,
|
||||
|
|
@ -30,7 +30,7 @@ const Config = {
|
|||
function info(msg) {
|
||||
const timestamp = new Date().toLocaleString("en-US").split(",")[1].trim();
|
||||
console.log(
|
||||
`${pc.dim(timestamp)} ${pc.bold(pc.cyan("[flok-web]"))} ${pc.green(msg)}`
|
||||
`${pc.dim(timestamp)} ${pc.bold(pc.cyan("[flok-web]"))} ${pc.green(msg)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -62,8 +62,8 @@ async function resolveConfig() {
|
|||
if (Config.inlineViteConfig) {
|
||||
info(
|
||||
`${pc.yellow("Inline config")} detected, ignoring ${pc.yellow(
|
||||
"Vite config file"
|
||||
)}`
|
||||
"Vite config file",
|
||||
)}`,
|
||||
);
|
||||
|
||||
return {
|
||||
|
|
@ -79,10 +79,10 @@ async function resolveConfig() {
|
|||
{
|
||||
configFile: Config.viteConfigFile,
|
||||
},
|
||||
"build"
|
||||
"build",
|
||||
);
|
||||
info(
|
||||
`Using ${pc.yellow("Vite")} to resolve the ${pc.yellow("config file")}`
|
||||
`Using ${pc.yellow("Vite")} to resolve the ${pc.yellow("config file")}`,
|
||||
);
|
||||
return config;
|
||||
} catch (e) {
|
||||
|
|
@ -90,9 +90,9 @@ async function resolveConfig() {
|
|||
info(
|
||||
pc.red(
|
||||
`Unable to use ${pc.yellow("Vite")}, running in ${pc.yellow(
|
||||
"viteless"
|
||||
)} mode`
|
||||
)
|
||||
"viteless",
|
||||
)} mode`,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -117,9 +117,9 @@ async function resolveConfig() {
|
|||
info(
|
||||
pc.red(
|
||||
`Unable to locate ${pc.yellow(
|
||||
"vite.config.*s file"
|
||||
)}, using default options`
|
||||
)
|
||||
"vite.config.*s file",
|
||||
)}, using default options`,
|
||||
),
|
||||
);
|
||||
|
||||
return getDefaultViteConfig();
|
||||
|
|
@ -146,8 +146,8 @@ async function serveStatic() {
|
|||
info(`${pc.red(`Static files at ${pc.gray(distPath)} not found!`)}`);
|
||||
info(
|
||||
`${pc.yellow(
|
||||
`Did you forget to run ${pc.bold(pc.green("vite build"))} command?`
|
||||
)}`
|
||||
`Did you forget to run ${pc.bold(pc.green("vite build"))} command?`,
|
||||
)}`,
|
||||
);
|
||||
} else {
|
||||
info(`${pc.green(`Serving static files from ${pc.gray(distPath)}`)}`);
|
||||
|
|
@ -163,7 +163,7 @@ async function injectStaticMiddleware(app, middleware) {
|
|||
app.use(config.base, middleware);
|
||||
|
||||
const stubMiddlewareLayer = app._router.stack.find(
|
||||
(layer) => layer.handle === stubMiddleware
|
||||
(layer) => layer.handle === stubMiddleware,
|
||||
);
|
||||
|
||||
if (stubMiddlewareLayer !== undefined) {
|
||||
|
|
@ -182,10 +182,7 @@ function isIgnoredPath(path, req) {
|
|||
: Config.ignorePaths(path, req);
|
||||
}
|
||||
|
||||
function findClosestIndexToRoot(
|
||||
reqPath,
|
||||
root
|
||||
) {
|
||||
function findClosestIndexToRoot(reqPath, root) {
|
||||
const basePath = reqPath.slice(0, reqPath.lastIndexOf("/"));
|
||||
const dirs = basePath.split("/");
|
||||
|
||||
|
|
@ -265,7 +262,7 @@ async function startServer(server) {
|
|||
middlewareMode: true,
|
||||
hmr: { server },
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
server.on("close", async () => {
|
||||
|
|
@ -284,11 +281,7 @@ function config(config) {
|
|||
Config.viteConfigFile = config.viteConfigFile;
|
||||
}
|
||||
|
||||
async function bind(
|
||||
app,
|
||||
server,
|
||||
callback
|
||||
) {
|
||||
async function bind(app, server, callback) {
|
||||
info(`Running in ${pc.yellow(Config.mode)} mode`);
|
||||
|
||||
clearState();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue