mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-28 06:22:45 -08:00
initial commit
This commit is contained in:
10
vendor/texthooker-ui/.editorconfig
vendored
Normal file
10
vendor/texthooker-ui/.editorconfig
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
max_line_length = 120
|
||||
trim_trailing_whitespace = true
|
||||
19
vendor/texthooker-ui/.eslintrc.cjs
vendored
Normal file
19
vendor/texthooker-ui/.eslintrc.cjs
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ['plugin:@typescript-eslint/recommended', 'eslint:recommended', 'prettier', 'prettier/@typescript-eslint'],
|
||||
plugins: ['svelte3', '@typescript-eslint'],
|
||||
overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }],
|
||||
parserOptions: {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 2020,
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true,
|
||||
},
|
||||
parser: '@typescript-eslint/parser',
|
||||
settings: {
|
||||
'svelte3/typescript': () => require('typescript'),
|
||||
},
|
||||
};
|
||||
27
vendor/texthooker-ui/.gitignore
vendored
Normal file
27
vendor/texthooker-ui/.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
# nix flake build output
|
||||
result
|
||||
1
vendor/texthooker-ui/.npmrc
vendored
Normal file
1
vendor/texthooker-ui/.npmrc
vendored
Normal file
@@ -0,0 +1 @@
|
||||
engine-strict=true
|
||||
6
vendor/texthooker-ui/.prettierrc
vendored
Normal file
6
vendor/texthooker-ui/.prettierrc
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"editorconfig": true,
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4
|
||||
}
|
||||
3
vendor/texthooker-ui/.vscode/extensions.json
vendored
Normal file
3
vendor/texthooker-ui/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["svelte.svelte-vscode"]
|
||||
}
|
||||
21
vendor/texthooker-ui/LICENSE
vendored
Normal file
21
vendor/texthooker-ui/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Renji-xD
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
206
vendor/texthooker-ui/README.md
vendored
Normal file
206
vendor/texthooker-ui/README.md
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
# Texthooker UI
|
||||
|
||||
A web interface for using websocket-based interfaces, such as:
|
||||
- [Textractor](https://github.com/Artikash/Textractor) with [textractor-websocket](https://github.com/kuroahna/textractor_websocket) or [TextractorSender](https://github.com/KamWithK/TextractorSender)
|
||||
- [mpv](https://mpv.io) with [mpv_websocket](https://github.com/kuroahna/mpv_websocket)
|
||||
|
||||
An online version of the page can be accessed [here](https://renji-xd.github.io/texthooker-ui/).
|
||||
|
||||
An offline version of the page can be downloaded from the [docs](https://github.com/Renji-XD/texthooker-ui/tree/main/docs) folder (make sure to also download the assets folder and content in case you want to use some of the custom online fonts) or build locally by your own.
|
||||
|
||||
When facing connection issues check the [FAQ](https://github.com/Renji-XD/texthooker-ui#faq) for common issues like ad blocker extensions (uBlock) or wrong websocket urls.
|
||||
|
||||
**Note:** If you are interested in persistent statistics, history and additional mining capabitilies / workflows you may want to checkout [GameSentenceMiner](https://github.com/bpwhelan/GameSentenceMiner) which runs a forked version of this web interface.
|
||||
|
||||
## Building
|
||||
|
||||
```
|
||||
# Install pnpm
|
||||
npm install --global pnpm
|
||||
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Build the Page
|
||||
pnpm run build
|
||||
|
||||
# Optional - serve the Page via local Server
|
||||
pnpm run preview
|
||||
```
|
||||
|
||||
The page can be opened via the index.html inside the "docs" folder and is usable without the need of hosting it via a server.
|
||||
|
||||
## FAQ
|
||||
|
||||
### I can't connect to the websocket with textractor-websocket.
|
||||
|
||||
- [Sadolit's textractor-websocket](https://github.com/sadolit/textractor-websocket) requires that textractor captures at least one line before starting the server - connect manually afterwards. Alternatively try [kuroahna's textractor_websocket](https://github.com/kuroahna/textractor_websocket) which does not have this issue.
|
||||
|
||||
### I can't connect to the websocket with TextractorSender.
|
||||
|
||||
- Make sure you are using the right port which is 9001
|
||||
|
||||
### I can't connect to the websocket with a different plugin/still can't connect to the websocket with one of the mentioned plugins.
|
||||
|
||||
- Make sure your firewall is not blocking the required ports. You can also check if another extension is interfering by trying out the page with a clean temporary profile and disabled extensions
|
||||
- Adblocker extensions like uBlock may block connections to localhost / websocket addresses. Try to disable them for this page / running a clean temporary profile to verify the functionality
|
||||
- **For Brave Users**: If you are using a hosted / online version of the page disable the brave shield for the domain to allow the usage of unsafe websocket connections. Alternatively try out the local / offline version which you can find in the [docs](https://raw.githubusercontent.com/Renji-XD/texthooker-ui/main/docs/index.html) folder
|
||||
|
||||
### Can I use this page with extensions like [Clipboard Inserter](https://github.com/kmltml/clipboard-inserter) or [lap-clipboard-inserter](https://github.com/laplus-sadness/lap-clipboard-inserter)?
|
||||
|
||||
- When "Enable external Clipboard Monitor" is checked text appended as paragraph to the page body will be taken over by the app. Make sure to enable this setting before the actual extension to avoid wrongly pasted elements
|
||||
|
||||
### How do I customize the page with CSS?
|
||||
|
||||
- You can use normal CSS syntax and rules via the "Custom CSS" Field. The content will be appended as style node to the page header
|
||||
|
||||
### How can I delete lines?
|
||||
|
||||
There are multiple ways of deleting a line:
|
||||
|
||||
- Click on the "Delete last Line" Icon in the header
|
||||
- Click on the "Reset Lines" / "Reset Data" / "Reset All" Icon in the settings menu
|
||||
- Highlight a line and press the "Delete" key on the keyboard
|
||||
- Have no text highlighted and press the "Alt" + "Delete" key on the keyboard
|
||||
- Select a Line for deletion by holding the "CTRL" key (or "command" key on macOS) on the keyboard and double click on it (you can press "Escape" to unselect lines again). Afterwards click on the "Remove selected Lines" icon in the header
|
||||
|
||||
### How can I edit a line?
|
||||
|
||||
- You can modify the content of a line by double clicking on it. Clicking somewhere outside will exit the edit mode. Changes to the text will automatically be reflected in the character counter
|
||||
|
||||
### What is covered by "Undo last Action"?
|
||||
|
||||
_Note_: By default, the undo history is stored in memory only. If you want to keep it across tab reloads, make sure to enable the respective setting.
|
||||
|
||||
- Deleting lines by clicking on the "Remove last line" icon
|
||||
- Deleting lines by highlighting them and pressing the "Delete" key on the keyboard
|
||||
- Deleting last line pressing the "Alt" + "Delete" key on the keyboard
|
||||
- Deleting lines by clicking on the "Remove selected lines" icon
|
||||
- Editing content of a line
|
||||
|
||||
### What is NOT covered by "Undo last Action"?
|
||||
|
||||
- Deleting data by clicking on the "Reset Lines" / "Reset Data" / "Reset All" icon
|
||||
- Overwritten data by an import
|
||||
- Skipping duplicates resulting out of setting changes / changed Data
|
||||
- Skipping duplicates resulting out of replacement pattern changes / changed Data
|
||||
- Removed lines by the "Max Lines" setting
|
||||
- Filtered lines by the "Filter lines without jp content" setting
|
||||
|
||||
### Can I move the data to another device / browser?
|
||||
|
||||
- You can export/import data by clicking on the respective Icon in the settings menu
|
||||
- Clicking on the icon will export the current time value, notes, displayed lines and action history (settings will not be exported)
|
||||
- Clicking on the icon while holding the "ALT" key on the keyboard lets you select a previously exported file for import. Note that all existing data will be overwritten
|
||||
- The same steps can be executed for exporting/importing all Settings/Presets or single Presets via respective Icons
|
||||
|
||||
|
||||
### What is the order of settings / transformations on new text lines?
|
||||
1. Replacements
|
||||
2. Remove all Whitespace
|
||||
3. Filter lines without jp content
|
||||
4. Global or last line Duplicate
|
||||
5. Max Lines
|
||||
6. Merge equal Line Starts
|
||||
|
||||
### Can I use the floating window in other browsers except chrome / edge?
|
||||
- No - (Desktop) Chromium Browser are currently the only browser having the required api implemented
|
||||
|
||||
### What options / actions are applied to the floating Window?
|
||||
- Applied: Font Size, Online Font, Max Lines (floating window),Reverse Line Order, Preserve Whitespace, Enable Line Animation, AFK Blur, Custom CSS
|
||||
- Implicit: All Line related text adjustments like replacement patterns, duplicate management, line start merges, jp content filter etc.
|
||||
- Not available: Vertical Display, Main window actions, timer / stats, keybinds, pasting and line actions like selecting or editing
|
||||
|
||||
### Can i let my dictionary extension exceed the floating Window?
|
||||
|
||||
- No - technically the floating window behaves exactly as any other browser window and therefore it is not possible that content exceeds it
|
||||
|
||||
### Will the floating Window remember the last Position?
|
||||
|
||||
- In Terms of height and width the page will attempt to restore the last used dimensions but the browser may clamp or ignore the values as appropriate to provide a reasonable user experience. The window position itself typically resets when closing the tab or floating window
|
||||
|
||||
### Can i further customize the floating Window?
|
||||
|
||||
- You can apply custom styles as per standard settings. In order to target the floating window content you can use the id selector "#pip-container" (e.g. `#pip-container p {color: red;}` will only apply to paragraphs in the floating window and not the main window). Further customizations like exeeding height, transparency etc. is not possible
|
||||
|
||||
|
||||
## Available Keybinds
|
||||
Note: The actions are only executed when settings/notes are closed, no (confirmation) dialog is displayed and no line is in edit mode.
|
||||
|
||||
| Keybind | Description |
|
||||
|-|-|
|
||||
| <kbd>Delete</kbd> | Deletes current highlighted lines on the page. |
|
||||
| <kbd>Esc</kbd> | Deselects Lines. |
|
||||
| <kbd>Alt</kbd> + <kbd>Delete</kbd> | Deletes last line if no lines are highlighted |
|
||||
| <kbd>Alt</kbd> + <kbd>a</kbd> | Deletes all Lines and resets the Timer to 00:00:00. |
|
||||
| <kbd>Alt</kbd> + <kbd>q</kbd> | Deletes all Lines. |
|
||||
| <kbd>Alt</kbd> + <kbd>g</kbd> | Toggles Websocket Icon. |
|
||||
| <kbd>Control</kbd> + <kbd>Space</kbd> | Toggles the Timer. |
|
||||
|
||||
|
||||
## Available Settings
|
||||
|
||||
The following section contains explanations and details on the settings you can configure. The settings can be accessed by clicking on the gear at the top right corner.
|
||||
|
||||
<details style="cursor: pointer;">
|
||||
<summary>Settings List</summary>
|
||||
|
||||
| Setting | Description |
|
||||
|-|-|
|
||||
| Presets | Allows you to save the current Settings as a Preset and to quickly switch between them.<br/>**Note:** Changes to Settings needs to be manually saved to a Preset by clicking on the Save button. The Dialog to apply Settings to current Lines or Storage like "Store X persistently", "Prevent Last Line Duplicate", "Remove all Whitespace" etc. will not be triggered by switching between Presets. You can still execute them by toggling respective Setting.|
|
||||
| Replacements | Allows you to configure (regex) patterns and replacements which are getting applied to new lines. See [this documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#description) for more Information. You can change the order of patterns by holding down your mouse on the box and moving it to the item you want to swap the position with
|
||||
| Window Title | Lets you set the current document title. This can be used with Yomichan to tag your created cards (with the `{document-title}` [marker](https://github.com/FooSoft/yomichan#markers-for-term-cards)). |
|
||||
| Primary WebSocket | URL of the primary WebSocket to which you want to connect. |
|
||||
| Secondary WebSocket | URL of the secondary WebSocket to which you want to connect. |
|
||||
| Font Size | The font size, in number of pixels. |
|
||||
| Character Milestone | Interval of Characters after which a milestone section will be inserted (< 2 = disabled) |
|
||||
| Online Font | Lets you select a font from a predefined selection. An internet connection is required in order for this work. |
|
||||
| Prevent Last Line Duplicate | This will prevent the insertion/pasting of a line if the text is equal to one of the last n configured lines. |
|
||||
| Max lines | Sets the maximum number of lines allowed. Once the limit is reached, the oldest line is automatically removed when a new one is added. The feature is active only when the limit is greater than 0. Undo Action will enforce this setting on execution. |
|
||||
| AFK Timer (s) | Number of seconds after which the timer will automatically pause without page interaction (no new line, text selection, or pointer move). |
|
||||
| Adjust Timer after AFK | If enabled, the timer will be subtracted by the configured `AFK Timer (s)` value whenever the timer was paused due to no page interaction. |
|
||||
| Enable external Clipboard Monitor | If enabled, this will allow the texthooker page to handle lines pasted by extensions like [Clipboard Inserter](https://github.com/kmltml/clipboard-inserter) or [lap-clipboard-inserter](https://github.com/laplus-sadness/lap-clipboard-inserter). |
|
||||
| Show Preset Quick Switch | If enabled and you have more than 2 preset stored, this will display a preset selector in the page header for quick access to your presets. |
|
||||
| Skip Reset Confirmations | If enabled, reset / delete actions like "Reset Lines" will be immediately executed without asking for confirmation. |
|
||||
| Store Stats persistently | If enabled, the stats (time, speed, etc.) will be stored in your local browser storage. This means the stats will be available after tab reloads, etc. |
|
||||
| Store Notes persistently | If enabled, the text within the notes section will be stored in your local browser storage. |
|
||||
| Store Lines persistently | If enabled, the inserted/pasted lines will be stored in your local browser storage. |
|
||||
| Store Action History persistently | If enabled, the [revertible actions](#what-is-covered-by-undo-last-action) will be stored in your local browser storage. |
|
||||
| Enable Paste | If enabled, this will allow the user to manually paste new lines to the texthooker page (i.e. with ctrl+v). |
|
||||
| Block Copy from Page | If enabled, this will block the next line insertion by an external clipboard monitor after copying text from the page |
|
||||
| Allow Paste during Pause | If enabled, this will allow the page to paste new lines even with a paused timer. |
|
||||
| Allow new Line during Pause | If enabled, this will allow the page to insert new lines from other sources than pasting even with a paused timer. |
|
||||
| Autostart Timer by Paste during Pause | If enabled, the time will automatically re-start if it was paused and new lines were pasted. |
|
||||
| Autostart Timer by Line during Pause | If enabled, the time will automatically re-start if it was paused and new lines were inserted by sources than pasting. |
|
||||
| Prevent Global Duplicate | This is the same as "Prevent Last Line Duplicate", except the line is checked against the entire document. The line will not be inserted/pasted if it is found anywhere within the document. |
|
||||
| Merge equal Line Start | If enabled, a new text line will be merged with the previous one in case it starts with the exact same content |
|
||||
| Filter lines without jp content | If enabled, lines without any Japanese character or punctuation will be ignored and not added to the list of lines. |
|
||||
| Flash on missed Line | If enabled, the page will flash every time a line is inserted/pasted *if your timer is paused*. These lines will be ignored from stats collection. |
|
||||
| Display Text vertically | If enabled, the lines will be displayed vertically instead horizontally. |
|
||||
| Reverse Line Order | If enabled, the new lines will be appended on top (horizontal mode) / left (vertical mode) instead of bottom / right respectively. |
|
||||
| Preserve Whitespace | If enabled, all existing whitespace (such as spaces, new line characters, etc.) within the line will be fully displayed. If left disabled, newlines and multiple spaces in a row will be collapsed to a singular space. This has no effect if the whitespace is already removed (i.e. with the `Remove all Whitespace` option enabled). |
|
||||
| Remove all Whitespace | If enabled, all whitespace will be removed from the lines before they are inserted into the page. |
|
||||
| Show Timer | If enabled, the page will display the current passed (active) time in the header. |
|
||||
| Show Speed | If enabled, the page will display the current characters per hour in the header. |
|
||||
| Show Character Count | If enabled, the page will display the current number of displayed characters within the page. |
|
||||
| Show Line Count | If enabled, the page will display the current number of inserted lines within the page. |
|
||||
| Blur Stats | If enabled, the displayed stats will be blurred. These stats are unblurred on hover. |
|
||||
| Enable Line Animation | If enabled, adds Lines with a short animated Transition. |
|
||||
| Enable AFK Blur | If enabled the screen will be blurred when the afk timer gets activated. You can exit by double clicking/tapping on the page. |
|
||||
| Restart Timer after AFK Blur | If enabled the timer will automatically restart when you exit the afk blur mode. |
|
||||
| Continuous Reconnect | If enabled, supresses Connection Error Messages and retries to connect to the Websocket Url continuously. |
|
||||
| Custom CSS | Lets you insert custom CSS rules to customize the page further. |
|
||||
|
||||
</details>
|
||||
|
||||
## Known Issues
|
||||
|
||||
- High number of displayed characters may slow down the page performance due to the current greedy way of counting characters etc.
|
||||
- The horizontal reading mode performs overall better than the vertical one
|
||||
- Line breaks added manually during editing a line are sometimes removed
|
||||
- The page was build with desktop / maximized window usage in mind - following guides (e. g. like [this](https://rentry.co/android-texthook) one) to access the page via tablet or mobile devices / using smaller window / screen sizes may have a limited user experience or functionality
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
- [Anacreon Texthooker](https://anacreondjt.gitlab.io/texthooker.html)
|
||||
- [MarvNC texthooker-websocket User Script](https://github.com/MarvNC/texthooker-websocket)
|
||||
BIN
vendor/texthooker-ui/docs/assets/fonts/ackaisyo.ttf
vendored
Normal file
BIN
vendor/texthooker-ui/docs/assets/fonts/ackaisyo.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/texthooker-ui/docs/assets/fonts/cinecaption226.ttf
vendored
Normal file
BIN
vendor/texthooker-ui/docs/assets/fonts/cinecaption226.ttf
vendored
Normal file
Binary file not shown.
49
vendor/texthooker-ui/docs/index.html
vendored
Normal file
49
vendor/texthooker-ui/docs/index.html
vendored
Normal file
File diff suppressed because one or more lines are too long
60
vendor/texthooker-ui/flake.lock
generated
vendored
Normal file
60
vendor/texthooker-ui/flake.lock
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1738680400,
|
||||
"narHash": "sha256-ooLh+XW8jfa+91F1nhf9OF7qhuA/y1ChLx6lXDNeY5U=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "799ba5bffed04ced7067a91798353d360788b30d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-unstable",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
44
vendor/texthooker-ui/flake.nix
vendored
Normal file
44
vendor/texthooker-ui/flake.nix
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
description = "texthooker-ui";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
}:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system: let
|
||||
name = "texthooker-ui";
|
||||
src = ./.;
|
||||
pkgs = import nixpkgs {inherit system;};
|
||||
nativeBuildInputs = with pkgs; [nodejs pnpm.configHook];
|
||||
in {
|
||||
# index.html will be located in the nix store
|
||||
# build with "nix build . --print-out-paths" to get the path
|
||||
packages.default = pkgs.stdenv.mkDerivation (finalAttrs: {
|
||||
inherit name nativeBuildInputs src;
|
||||
pname = name;
|
||||
|
||||
pnpmDeps = pkgs.pnpm.fetchDeps {
|
||||
pname = name;
|
||||
inherit src;
|
||||
hash = "sha256-Wqs3aO4uq/5eqVmp9FFZNVEWo/TpwDib9PJFABmFrbk=";
|
||||
};
|
||||
|
||||
installPhase = ''
|
||||
pnpm run build
|
||||
cp -r ./docs $out
|
||||
'';
|
||||
});
|
||||
|
||||
devShell = pkgs.mkShell {
|
||||
inherit nativeBuildInputs;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
23
vendor/texthooker-ui/index.html
vendored
Normal file
23
vendor/texthooker-ui/index.html
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head data-version="1.0.0">
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/svg+xml"
|
||||
href="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojOGQ2ZGU4O30uY2xzLTJ7ZmlsbDojYTc4ZWVmO30uY2xzLTN7ZmlsbDojNmMyZTdjO308L3N0eWxlPjwvZGVmcz48ZyBpZD0iSWNvbnMiPjxyZWN0IGNsYXNzPSJjbHMtMSIgaGVpZ2h0PSIyMiIgcng9IjMiIHdpZHRoPSIyMiIgeD0iMSIgeT0iMSIvPjxyZWN0IGNsYXNzPSJjbHMtMiIgaGVpZ2h0PSIxNyIgcng9IjMiIHdpZHRoPSIyMiIgeD0iMSIgeT0iMSIvPjwvZz48ZyBkYXRhLW5hbWU9IkxheWVyIDQiIGlkPSJMYXllcl80Ij48cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik0yMCwwSDRBNCw0LDAsMCwwLDAsNFYyMGE0LDQsMCwwLDAsNCw0SDIwYTQsNCwwLDAsMCw0LTRWNEE0LDQsMCwwLDAsMjAsMFptMiwyMGEyLDIsMCwwLDEtMiwySDRhMiwyLDAsMCwxLTItMlY0QTIsMiwwLDAsMSw0LDJIMjBhMiwyLDAsMCwxLDIsMloiLz48cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik01LDE1YTEsMSwwLDAsMCwwLDIsMiwyLDAsMCwxLDIsMiwxLDEsMCwwLDAsMiwwQTQsNCwwLDAsMCw1LDE1WiIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTUsMTFhMSwxLDAsMCwwLDAsMiw2LjAwNiw2LjAwNiwwLDAsMSw2LDYsMSwxLDAsMCwwLDIsMEE4LjAwOSw4LjAwOSwwLDAsMCw1LDExWiIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTUsN0ExLDEsMCwwLDAsNSw5LDEwLjAxMSwxMC4wMTEsMCwwLDEsMTUsMTlhMSwxLDAsMCwwLDIsMEExMi4wMTMsMTIuMDEzLDAsMCwwLDUsN1oiLz48L2c+PC9zdmc+"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Klee+One&family=Noto+Serif+JP&family=Shippori+Mincho&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Texthooker UI</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script type="module" src="./src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
44
vendor/texthooker-ui/package.json
vendored
Normal file
44
vendor/texthooker-ui/package.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"author": "Renji-xD",
|
||||
"devDependencies": {
|
||||
"@mdi/js": "^7.1.96",
|
||||
"@sveltejs/vite-plugin-svelte": "^2.0.2",
|
||||
"@tsconfig/svelte": "^3.0.0",
|
||||
"@types/dom-screen-wake-lock": "^1.0.0",
|
||||
"@types/sortablejs": "^1.15.8",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"daisyui": "^2.45.0",
|
||||
"eslint": "^8.30.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"postcss": "^8.4.20",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.8.1",
|
||||
"rollup": "^3.14.0",
|
||||
"rxjs": "^7.8.0",
|
||||
"svelte": "^3.55.0",
|
||||
"svelte-check": "^2.10.2",
|
||||
"svelte-preprocess": "^5.0.0",
|
||||
"tailwindcss": "^3.2.4",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.4",
|
||||
"vite": "^4.0.1",
|
||||
"vite-plugin-singlefile": "^0.13.2"
|
||||
},
|
||||
"license": "MIT",
|
||||
"name": "texthooker-ui",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "vite -c vite.main.config.ts build",
|
||||
"build:lib": "vite -c vite.lib.config.ts build",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:types": "tsc --noEmit",
|
||||
"dev": "vite -c vite.main.config.ts",
|
||||
"preview": "vite -c vite.main.config.ts preview --host"
|
||||
},
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"sortablejs": "^1.15.2"
|
||||
}
|
||||
}
|
||||
2096
vendor/texthooker-ui/pnpm-lock.yaml
generated
vendored
Normal file
2096
vendor/texthooker-ui/pnpm-lock.yaml
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
8
vendor/texthooker-ui/postcss.config.cjs
vendored
Normal file
8
vendor/texthooker-ui/postcss.config.cjs
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
const tailwindcss = require('tailwindcss');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
|
||||
const config = {
|
||||
plugins: [tailwindcss(), autoprefixer],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
BIN
vendor/texthooker-ui/public/assets/fonts/ackaisyo.ttf
vendored
Normal file
BIN
vendor/texthooker-ui/public/assets/fonts/ackaisyo.ttf
vendored
Normal file
Binary file not shown.
BIN
vendor/texthooker-ui/public/assets/fonts/cinecaption226.ttf
vendored
Normal file
BIN
vendor/texthooker-ui/public/assets/fonts/cinecaption226.ttf
vendored
Normal file
Binary file not shown.
1
vendor/texthooker-ui/public/icon.svg
vendored
Normal file
1
vendor/texthooker-ui/public/icon.svg
vendored
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" ?><svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:#8d6de8;}.cls-2{fill:#a78eef;}.cls-3{fill:#6c2e7c;}</style></defs><g id="Icons"><rect class="cls-1" height="22" rx="3" width="22" x="1" y="1"/><rect class="cls-2" height="17" rx="3" width="22" x="1" y="1"/></g><g data-name="Layer 4" id="Layer_4"><path class="cls-3" d="M20,0H4A4,4,0,0,0,0,4V20a4,4,0,0,0,4,4H20a4,4,0,0,0,4-4V4A4,4,0,0,0,20,0Zm2,20a2,2,0,0,1-2,2H4a2,2,0,0,1-2-2V4A2,2,0,0,1,4,2H20a2,2,0,0,1,2,2Z"/><path class="cls-3" d="M5,15a1,1,0,0,0,0,2,2,2,0,0,1,2,2,1,1,0,0,0,2,0A4,4,0,0,0,5,15Z"/><path class="cls-3" d="M5,11a1,1,0,0,0,0,2,6.006,6.006,0,0,1,6,6,1,1,0,0,0,2,0A8.009,8.009,0,0,0,5,11Z"/><path class="cls-3" d="M5,7A1,1,0,0,0,5,9,10.011,10.011,0,0,1,15,19a1,1,0,0,0,2,0A12.013,12.013,0,0,0,5,7Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 835 B |
24
vendor/texthooker-ui/public/index.html
vendored
Normal file
24
vendor/texthooker-ui/public/index.html
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head data-version="1.0.0">
|
||||
<meta charset="UTF-8" />
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/svg+xml"
|
||||
href="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pjxzdmcgdmlld0JveD0iMCAwIDI0IDI0IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojOGQ2ZGU4O30uY2xzLTJ7ZmlsbDojYTc4ZWVmO30uY2xzLTN7ZmlsbDojNmMyZTdjO308L3N0eWxlPjwvZGVmcz48ZyBpZD0iSWNvbnMiPjxyZWN0IGNsYXNzPSJjbHMtMSIgaGVpZ2h0PSIyMiIgcng9IjMiIHdpZHRoPSIyMiIgeD0iMSIgeT0iMSIvPjxyZWN0IGNsYXNzPSJjbHMtMiIgaGVpZ2h0PSIxNyIgcng9IjMiIHdpZHRoPSIyMiIgeD0iMSIgeT0iMSIvPjwvZz48ZyBkYXRhLW5hbWU9IkxheWVyIDQiIGlkPSJMYXllcl80Ij48cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik0yMCwwSDRBNCw0LDAsMCwwLDAsNFYyMGE0LDQsMCwwLDAsNCw0SDIwYTQsNCwwLDAsMCw0LTRWNEE0LDQsMCwwLDAsMjAsMFptMiwyMGEyLDIsMCwwLDEtMiwySDRhMiwyLDAsMCwxLTItMlY0QTIsMiwwLDAsMSw0LDJIMjBhMiwyLDAsMCwxLDIsMloiLz48cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik01LDE1YTEsMSwwLDAsMCwwLDIsMiwyLDAsMCwxLDIsMiwxLDEsMCwwLDAsMiwwQTQsNCwwLDAsMCw1LDE1WiIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTUsMTFhMSwxLDAsMCwwLDAsMiw2LjAwNiw2LjAwNiwwLDAsMSw2LDYsMSwxLDAsMCwwLDIsMEE4LjAwOSw4LjAwOSwwLDAsMCw1LDExWiIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTUsN0ExLDEsMCwwLDAsNSw5LDEwLjAxMSwxMC4wMTEsMCwwLDEsMTUsMTlhMSwxLDAsMCwwLDIsMEExMi4wMTMsMTIuMDEzLDAsMCwwLDUsN1oiLz48L2c+PC9zdmc+"
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Klee+One&family=Noto+Serif+JP&family=Shippori+Mincho&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Texthooker UI</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="texthooker-ui.iife.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
131
vendor/texthooker-ui/src/app.css
vendored
Normal file
131
vendor/texthooker-ui/src/app.css
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@font-face {
|
||||
font-family: 'Ackaisyo';
|
||||
src: local(''), url('./assets/fonts/ackaisyo.ttf') format('truetype');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'CineCaption226';
|
||||
src: local(''), url('./assets/fonts/cinecaption226.ttf') format('truetype');
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/* SUBMINER_DEFAULT_STYLE_START */
|
||||
:root {
|
||||
--sm-bg: #1a1b2e;
|
||||
--sm-surface: #222436;
|
||||
--sm-border: rgba(255, 255, 255, 0.05);
|
||||
--sm-text: #c8d3f5;
|
||||
--sm-text-muted: #636da6;
|
||||
--sm-hover-bg: rgba(130, 170, 255, 0.06);
|
||||
--sm-scrollbar: rgba(255, 255, 255, 0.08);
|
||||
--sm-scrollbar-hover: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-height: 100%;
|
||||
overflow: auto;
|
||||
background: var(--sm-bg);
|
||||
color: var(--sm-text);
|
||||
}
|
||||
|
||||
body[data-theme] {
|
||||
background: var(--sm-bg);
|
||||
color: var(--sm-text);
|
||||
}
|
||||
|
||||
main,
|
||||
header,
|
||||
#pip-container {
|
||||
background: transparent;
|
||||
color: var(--sm-text);
|
||||
}
|
||||
|
||||
header.bg-base-100,
|
||||
header.bg-base-200 {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
main,
|
||||
main.flex {
|
||||
font-family: 'Noto Sans CJK JP', 'Hiragino Sans', system-ui, sans-serif;
|
||||
padding: 0.5rem min(4vw, 2rem);
|
||||
line-height: 1.7;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
p,
|
||||
p.cursor-pointer {
|
||||
font-family: 'Noto Sans CJK JP', 'Hiragino Sans', system-ui, sans-serif;
|
||||
font-size: clamp(18px, 2vw, 26px);
|
||||
letter-spacing: 0.04em;
|
||||
line-height: 1.65;
|
||||
white-space: normal;
|
||||
margin: 0;
|
||||
padding: 0.65rem 1rem;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--sm-border);
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
p:hover,
|
||||
p.cursor-pointer:hover {
|
||||
background: var(--sm-hover-bg);
|
||||
}
|
||||
|
||||
p:last-child,
|
||||
p.cursor-pointer:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
p.cursor-pointer.whitespace-pre-wrap {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
p.cursor-pointer.my-2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p.cursor-pointer.py-4,
|
||||
p.cursor-pointer.py-2,
|
||||
p.cursor-pointer.px-2,
|
||||
p.cursor-pointer.px-4 {
|
||||
padding: 0.65rem 1rem;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background: var(--sm-scrollbar);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--sm-scrollbar-hover);
|
||||
}
|
||||
/* SUBMINER_DEFAULT_STYLE_END */
|
||||
747
vendor/texthooker-ui/src/components/App.svelte
vendored
Normal file
747
vendor/texthooker-ui/src/components/App.svelte
vendored
Normal file
@@ -0,0 +1,747 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
mdiArrowULeftTop,
|
||||
mdiCancel,
|
||||
mdiCog,
|
||||
mdiDelete,
|
||||
mdiDeleteForever,
|
||||
mdiNoteEdit,
|
||||
mdiPause,
|
||||
mdiPlay,
|
||||
mdiWindowMaximize,
|
||||
mdiWindowRestore,
|
||||
} from '@mdi/js';
|
||||
import { debounceTime, filter, fromEvent, map, NEVER, switchMap, tap } from 'rxjs';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { quintInOut } from 'svelte/easing';
|
||||
import { fly } from 'svelte/transition';
|
||||
import {
|
||||
actionHistory$,
|
||||
allowNewLineDuringPause$,
|
||||
allowPasteDuringPause$,
|
||||
autoStartTimerDuringPause$,
|
||||
autoStartTimerDuringPausePaste$,
|
||||
blockCopyOnPage$,
|
||||
customCSS$,
|
||||
dialogOpen$,
|
||||
displayVertical$,
|
||||
enabledReplacements$,
|
||||
enablePaste$,
|
||||
filterNonCJKLines$,
|
||||
flashOnMissedLine$,
|
||||
flashOnPauseTimeout$,
|
||||
fontSize$,
|
||||
isPaused$,
|
||||
lastPipHeight$,
|
||||
lastPipWidth$,
|
||||
lineData$,
|
||||
maxLines$,
|
||||
maxPipLines$,
|
||||
mergeEqualLineStarts$,
|
||||
newLine$,
|
||||
notesOpen$,
|
||||
onlineFont$,
|
||||
openDialog$,
|
||||
preventGlobalDuplicate$,
|
||||
preventLastDuplicate$,
|
||||
removeAllWhitespace$,
|
||||
replacements$,
|
||||
reverseLineOrder$,
|
||||
secondaryWebsocketUrl$,
|
||||
showConnectionIcon$,
|
||||
showSpinner$,
|
||||
theme$,
|
||||
websocketUrl$,
|
||||
} from '../stores/stores';
|
||||
import { LineType, OnlineFont, Theme, type LineItem, type LineItemEditEvent } from '../types';
|
||||
import {
|
||||
applyAfkBlur,
|
||||
applyCustomCSS,
|
||||
applyReplacements,
|
||||
generateRandomUUID,
|
||||
newLineCharacter,
|
||||
reduceToEmptyString,
|
||||
updateScroll,
|
||||
} from '../util';
|
||||
import DialogManager from './DialogManager.svelte';
|
||||
import Icon from './Icon.svelte';
|
||||
import Line from './Line.svelte';
|
||||
import Notes from './Notes.svelte';
|
||||
import Presets from './Presets.svelte';
|
||||
import Settings from './Settings.svelte';
|
||||
import SocketConnector from './SocketConnector.svelte';
|
||||
import Spinner from './Spinner.svelte';
|
||||
import Stats from './Stats.svelte';
|
||||
|
||||
let isSmFactor = false;
|
||||
let settingsComponent: Settings;
|
||||
let selectedLineIds: string[] = [];
|
||||
let settingsContainer: HTMLElement;
|
||||
let settingsElement: SVGElement;
|
||||
let settingsOpen = false;
|
||||
let lineContainer: HTMLElement;
|
||||
let lineElements: Line[] = [];
|
||||
let lineInEdit = false;
|
||||
let blockNextExternalLine = false;
|
||||
let wakeLock = null;
|
||||
let pipContainer: HTMLElement;
|
||||
let pipWindow: Window | undefined;
|
||||
let pipResizeTimeout: number;
|
||||
let hasPipFocus = false;
|
||||
|
||||
const wakeLockAvailable = 'wakeLock' in navigator;
|
||||
|
||||
const cjkCharacters = /[\p{scx=Hira}\p{scx=Kana}\p{scx=Han}]/imu;
|
||||
|
||||
const uniqueLines$ = preventGlobalDuplicate$.pipe(
|
||||
map((preventGlobalDuplicate) =>
|
||||
preventGlobalDuplicate ? new Set<string>($lineData$.map((line) => line.text)) : new Set<string>(),
|
||||
),
|
||||
);
|
||||
|
||||
const handleLine$ = newLine$.pipe(
|
||||
filter(([_, lineType]) => {
|
||||
const isPaste = lineType === LineType.PASTE;
|
||||
const hasNoUserInteraction = !isPaste || (!$notesOpen$ && !$dialogOpen$ && !settingsOpen && !lineInEdit);
|
||||
const skipExternalLine = blockNextExternalLine && lineType === LineType.EXTERNAL;
|
||||
|
||||
if (skipExternalLine) {
|
||||
blockNextExternalLine = false;
|
||||
}
|
||||
|
||||
if (
|
||||
(!$isPaused$ ||
|
||||
(($allowPasteDuringPause$ || $autoStartTimerDuringPausePaste$) && isPaste) ||
|
||||
(($allowNewLineDuringPause$ || $autoStartTimerDuringPause$) && !isPaste)) &&
|
||||
hasNoUserInteraction &&
|
||||
!skipExternalLine
|
||||
) {
|
||||
if (
|
||||
$isPaused$ &&
|
||||
(($autoStartTimerDuringPausePaste$ && isPaste) || ($autoStartTimerDuringPause$ && !isPaste))
|
||||
) {
|
||||
$isPaused$ = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!skipExternalLine && hasNoUserInteraction && $flashOnMissedLine$) {
|
||||
handleMissedLine();
|
||||
}
|
||||
|
||||
return false;
|
||||
}),
|
||||
tap((newLine: [string, LineType]) => {
|
||||
const [lineContent] = newLine;
|
||||
const text = transformLine(lineContent);
|
||||
|
||||
if (text) {
|
||||
$lineData$ = applyEqualLineStartMerge([
|
||||
...applyMaxLinesAndGetRemainingLineData(1),
|
||||
{ id: generateRandomUUID(), text },
|
||||
]);
|
||||
}
|
||||
}),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
const pasteHandler$ = enablePaste$.pipe(
|
||||
switchMap((enablePaste) => (enablePaste ? fromEvent(document, 'paste') : NEVER)),
|
||||
tap((event: ClipboardEvent) => newLine$.next([event.clipboardData.getData('text/plain'), LineType.PASTE])),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
const visibilityHandler$ = fromEvent(document, 'visibilitychange').pipe(
|
||||
tap(() => {
|
||||
if (wakeLockAvailable && wakeLock !== null && document.visibilityState === 'visible') {
|
||||
wakeLock = navigator.wakeLock
|
||||
.request('screen')
|
||||
.then((lock) => {
|
||||
return lock;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`Unable to aquire screen lock: ${error.message}`);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
const copyBlocker$ = blockCopyOnPage$.pipe(
|
||||
switchMap((blockCopyOnPage) => {
|
||||
blockNextExternalLine = false;
|
||||
|
||||
return blockCopyOnPage ? fromEvent(document, 'copy') : NEVER;
|
||||
}),
|
||||
tap(() => (blockNextExternalLine = true)),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
const resizeHandler$ = fromEvent(window, 'resize').pipe(
|
||||
debounceTime(500),
|
||||
tap(mountFunction),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
$: iconSize = isSmFactor ? '1.5rem' : '1.25rem';
|
||||
|
||||
$: $enabledReplacements$ = $replacements$.filter((replacment) => replacment.enabled);
|
||||
|
||||
$: pipAvailable = 'documentPictureInPicture' in window && !!pipContainer;
|
||||
|
||||
$: pipLines = pipAvailable && $lineData$ ? $lineData$.slice(-$maxPipLines$) : [];
|
||||
|
||||
$: if (pipWindow) {
|
||||
pipWindow.document.body.dataset.theme = $theme$;
|
||||
|
||||
applyCustomCSS(pipWindow.document, $customCSS$);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
mountFunction();
|
||||
if (wakeLockAvailable) {
|
||||
wakeLock = navigator.wakeLock
|
||||
.request('screen')
|
||||
.then((lock) => {
|
||||
return lock;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(`Unable to aquire screen lock: ${error.message}`);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function mountFunction() {
|
||||
isSmFactor = window.matchMedia('(min-width: 640px)').matches;
|
||||
executeUpdateScroll();
|
||||
}
|
||||
|
||||
function handleKeyPress(event: KeyboardEvent) {
|
||||
if ($notesOpen$ || $dialogOpen$ || settingsOpen || lineInEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = (event.key || '')?.toLowerCase();
|
||||
|
||||
if (key === 'delete') {
|
||||
if (window.getSelection()?.toString().trim()) {
|
||||
const range = window.getSelection().getRangeAt(0);
|
||||
|
||||
for (let index = 0, { length } = lineElements; index < length; index += 1) {
|
||||
const lineElement = lineElements[index];
|
||||
const selectedId = lineElement?.getIdIfSelected(range);
|
||||
|
||||
if (selectedId) {
|
||||
selectedLineIds.push(selectedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedLineIds.length) {
|
||||
removeLines();
|
||||
} else if (event.altKey) {
|
||||
removeLastLine();
|
||||
}
|
||||
} else if (selectedLineIds.length && key === 'escape') {
|
||||
deselectLines();
|
||||
} else if (event.altKey && key === 'a') {
|
||||
settingsComponent.handleReset(false);
|
||||
} else if (event.altKey && key === 'q') {
|
||||
settingsComponent.handleReset(true);
|
||||
} else if ((event.ctrlKey || event.metaKey) && key === ' ') {
|
||||
$isPaused$ = !$isPaused$;
|
||||
} else if (event.altKey && key === 'g') {
|
||||
$showConnectionIcon$ = !$showConnectionIcon$;
|
||||
}
|
||||
}
|
||||
|
||||
async function undoLastAction() {
|
||||
if (!$actionHistory$.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const linesToRevert = $actionHistory$.pop();
|
||||
|
||||
let lineToRevert = linesToRevert.pop();
|
||||
|
||||
while (lineToRevert) {
|
||||
const text = transformLine(lineToRevert.text, false);
|
||||
|
||||
if (text) {
|
||||
const { id, index } = lineToRevert;
|
||||
|
||||
if (index > $lineData$.length - 1) {
|
||||
$lineData$.push({ id, text });
|
||||
} else if ($lineData$[index].id === id) {
|
||||
$lineData$[index] = { id, text };
|
||||
} else {
|
||||
$lineData$.splice(index, 0, { id, text });
|
||||
}
|
||||
}
|
||||
|
||||
lineToRevert = linesToRevert.pop();
|
||||
}
|
||||
|
||||
await tick();
|
||||
|
||||
$lineData$ = applyEqualLineStartMerge(applyMaxLinesAndGetRemainingLineData());
|
||||
$actionHistory$ = $actionHistory$;
|
||||
}
|
||||
|
||||
function removeLastLine() {
|
||||
if (!$lineData$.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [removedLine] = $lineData$.splice($lineData$.length - 1, 1);
|
||||
|
||||
selectedLineIds = selectedLineIds.filter((selectedLineId) => selectedLineId !== removedLine.id);
|
||||
$lineData$ = $lineData$;
|
||||
$actionHistory$ = [...$actionHistory$, [{ ...removedLine, index: $lineData$.length }]];
|
||||
|
||||
$uniqueLines$.delete(removedLine.text);
|
||||
}
|
||||
|
||||
function removeLines() {
|
||||
const linesToDelete = new Set(selectedLineIds);
|
||||
const newActionHistory: LineItem[] = [];
|
||||
|
||||
$lineData$ = $lineData$.filter((oldLine, index) => {
|
||||
const hasLine = linesToDelete.has(oldLine.id);
|
||||
|
||||
linesToDelete.delete(oldLine.id);
|
||||
|
||||
if (hasLine) {
|
||||
newActionHistory.push({ ...oldLine, index: index - newActionHistory.length });
|
||||
$uniqueLines$.delete(oldLine.text);
|
||||
}
|
||||
|
||||
return !hasLine;
|
||||
});
|
||||
|
||||
selectedLineIds = linesToDelete.size ? [...linesToDelete] : [];
|
||||
|
||||
if (newActionHistory.length) {
|
||||
$actionHistory$ = [...$actionHistory$, newActionHistory];
|
||||
}
|
||||
}
|
||||
|
||||
function deselectLines() {
|
||||
for (let index = 0, { length } = lineElements; index < length; index += 1) {
|
||||
lineElements[index]?.deselect();
|
||||
}
|
||||
|
||||
selectedLineIds = [];
|
||||
}
|
||||
|
||||
async function handlePipAction() {
|
||||
if (pipWindow) {
|
||||
return pipWindow.close();
|
||||
}
|
||||
|
||||
pipWindow = await window.documentPictureInPicture
|
||||
.requestWindow(
|
||||
$lastPipHeight$ > 0 && $lastPipWidth$ > 0
|
||||
? { height: $lastPipHeight$, width: $lastPipWidth$, preferInitialWindowPlacement: false }
|
||||
: { preferInitialWindowPlacement: false },
|
||||
)
|
||||
.catch(({ message }) => {
|
||||
$openDialog$ = {
|
||||
message: `Error opening floating window: ${message}`,
|
||||
showCancel: false,
|
||||
};
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
if (!pipWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
pipWindow.document.body.appendChild(pipContainer);
|
||||
|
||||
pipWindow.addEventListener('pagehide', onPipHide, { once: true });
|
||||
pipWindow.addEventListener('resize', onPipResize, false);
|
||||
pipWindow.addEventListener('blur', onPipFocusBlur, false);
|
||||
pipWindow.addEventListener('focus', onPipFocusBlur, false);
|
||||
|
||||
[...document.styleSheets].forEach((styleSheet) => {
|
||||
if (styleSheet.ownerNode instanceof Element && styleSheet.ownerNode.id === 'user-css') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const cssRules = [...styleSheet.cssRules].map((rule) => rule.cssText).join('');
|
||||
const style = document.createElement('style');
|
||||
|
||||
style.textContent = cssRules;
|
||||
pipWindow.document.head.appendChild(style);
|
||||
} catch (_error) {
|
||||
const link = document.createElement('link');
|
||||
|
||||
link.rel = 'stylesheet';
|
||||
link.type = styleSheet.type;
|
||||
link.media = styleSheet.media.toString();
|
||||
link.href = styleSheet.href;
|
||||
pipWindow.document.head.appendChild(link);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onPipHide() {
|
||||
updatePipDimensions();
|
||||
|
||||
pipWindow.removeEventListener('resize', onPipResize, false);
|
||||
pipWindow.removeEventListener('blur', onPipFocusBlur, false);
|
||||
pipWindow.removeEventListener('focus', onPipFocusBlur, false);
|
||||
|
||||
hasPipFocus = false;
|
||||
pipWindow = undefined;
|
||||
}
|
||||
|
||||
function onPipResize() {
|
||||
window.clearTimeout(pipResizeTimeout);
|
||||
|
||||
pipResizeTimeout = window.setTimeout(updatePipDimensions, 500);
|
||||
}
|
||||
|
||||
function updatePipDimensions() {
|
||||
if (!pipWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lastPipHeight$ = pipWindow.document.body.clientHeight;
|
||||
$lastPipWidth$ = pipWindow.document.body.clientWidth;
|
||||
}
|
||||
|
||||
function onPipFocusBlur(event: Event) {
|
||||
hasPipFocus = event.type === 'focus';
|
||||
}
|
||||
|
||||
function onAfkBlur({ detail: isAfk }: CustomEvent<boolean>) {
|
||||
applyAfkBlur(document, isAfk);
|
||||
|
||||
if (pipWindow) {
|
||||
applyAfkBlur(pipWindow.document, isAfk);
|
||||
}
|
||||
}
|
||||
|
||||
function executeUpdateScroll() {
|
||||
updateScroll(window, lineContainer, $reverseLineOrder$, $displayVertical$);
|
||||
|
||||
if (pipWindow) {
|
||||
updateScroll(pipWindow, pipContainer, $reverseLineOrder$, false);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMissedLine() {
|
||||
clearTimeout($flashOnPauseTimeout$);
|
||||
|
||||
if ($theme$ === Theme.GARDEN) {
|
||||
settingsContainer.classList.add('bg-base-200');
|
||||
settingsContainer.classList.remove('bg-base-100');
|
||||
document.body.classList.add('bg-base-200');
|
||||
}
|
||||
|
||||
document.body.classList.add('animate-[pulse_0.5s_cubic-bezier(0.4,0,0.6,1)_1]');
|
||||
|
||||
$flashOnPauseTimeout$ = window.setTimeout(() => {
|
||||
if ($theme$ === Theme.GARDEN) {
|
||||
settingsContainer.classList.add('bg-base-100');
|
||||
settingsContainer.classList.remove('bg-base-200');
|
||||
document.body.classList.remove('bg-base-200');
|
||||
}
|
||||
|
||||
document.body.classList.remove('animate-[pulse_0.5s_cubic-bezier(0.4,0,0.6,1)_1]');
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function transformLine(text: string, useReplacements = true) {
|
||||
const textToAppend = useReplacements ? applyReplacements(text, $enabledReplacements$) : text;
|
||||
|
||||
let canAppend = true;
|
||||
let lineToAppend = $removeAllWhitespace$ ? textToAppend.replace(/\s/gm, '').trim() : textToAppend;
|
||||
|
||||
if ($filterNonCJKLines$ && !lineToAppend.match(cjkCharacters)) {
|
||||
lineToAppend = '';
|
||||
}
|
||||
|
||||
if (!lineToAppend) {
|
||||
canAppend = false;
|
||||
} else if ($preventGlobalDuplicate$) {
|
||||
canAppend = !$uniqueLines$.has(lineToAppend);
|
||||
$uniqueLines$.add(lineToAppend);
|
||||
} else if ($preventLastDuplicate$ && $lineData$.length) {
|
||||
canAppend = $lineData$.slice(-$preventLastDuplicate$).every((line) => line.text !== lineToAppend);
|
||||
}
|
||||
|
||||
return canAppend ? lineToAppend : undefined;
|
||||
}
|
||||
|
||||
function handleLineEdit(event) {
|
||||
const { inEdit, data } = event.detail as LineItemEditEvent;
|
||||
|
||||
if (data && data.originalText !== data.newText) {
|
||||
const text = transformLine(data.newText);
|
||||
|
||||
$lineData$[data.lineIndex] = {
|
||||
id: data.line.id,
|
||||
text,
|
||||
};
|
||||
|
||||
if (text) {
|
||||
$actionHistory$ = [...$actionHistory$, [{ ...data.line, index: data.lineIndex }]];
|
||||
$uniqueLines$.delete(data.originalText);
|
||||
$uniqueLines$.add(text);
|
||||
} else {
|
||||
tick().then(
|
||||
() =>
|
||||
($lineData$[data.lineIndex] = {
|
||||
id: data.line.id,
|
||||
text: data.originalText,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
lineInEdit = inEdit;
|
||||
}
|
||||
|
||||
function applyMaxLinesAndGetRemainingLineData(diffMod = 0) {
|
||||
const oldLinesToRemove = new Set<string>();
|
||||
const startIndex = $maxLines$ ? $lineData$.length - $maxLines$ + diffMod : 0;
|
||||
const remainingLineData =
|
||||
startIndex > 0
|
||||
? $lineData$.filter((oldLine, index) => {
|
||||
if (index < startIndex) {
|
||||
oldLinesToRemove.add(oldLine.id);
|
||||
|
||||
$uniqueLines$.delete(oldLine.text);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
: $lineData$;
|
||||
|
||||
if (oldLinesToRemove.size) {
|
||||
selectedLineIds = selectedLineIds.filter((selectedLineId) => !oldLinesToRemove.has(selectedLineId));
|
||||
}
|
||||
|
||||
return remainingLineData;
|
||||
}
|
||||
|
||||
function updateLineData(executeUpdate: boolean) {
|
||||
if (!executeUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
$showSpinner$ = true;
|
||||
|
||||
try {
|
||||
for (let index = 0, { length } = $lineData$; index < length; index += 1) {
|
||||
const line = $lineData$[index];
|
||||
const newText = transformLine(line.text);
|
||||
|
||||
if (newText && newText !== line.text) {
|
||||
$uniqueLines$.delete(line.text);
|
||||
|
||||
$lineData$[index] = { ...line, text: newText };
|
||||
}
|
||||
}
|
||||
|
||||
$openDialog$ = {
|
||||
message: `Operation executed`,
|
||||
showCancel: false,
|
||||
};
|
||||
} catch ({ message }) {
|
||||
$openDialog$ = {
|
||||
type: 'error',
|
||||
message: `An Error occured: ${message}`,
|
||||
showCancel: false,
|
||||
};
|
||||
}
|
||||
|
||||
$lineData$ = applyEqualLineStartMerge(applyMaxLinesAndGetRemainingLineData());
|
||||
|
||||
$showSpinner$ = false;
|
||||
}
|
||||
|
||||
function applyEqualLineStartMerge(currentLineData: LineItem[]) {
|
||||
if (!$mergeEqualLineStarts$ || currentLineData.length < 2) {
|
||||
return currentLineData;
|
||||
}
|
||||
|
||||
const lastIndex = currentLineData.length - 1;
|
||||
const comparisonIndex = lastIndex - 1;
|
||||
const lastLine = currentLineData[lastIndex];
|
||||
const comparisonLine = currentLineData[comparisonIndex].text;
|
||||
|
||||
if (lastLine.text.startsWith(comparisonLine)) {
|
||||
$uniqueLines$.delete(comparisonLine);
|
||||
|
||||
selectedLineIds = selectedLineIds.filter(
|
||||
(selectedLineId) => selectedLineId !== currentLineData[comparisonIndex].id,
|
||||
);
|
||||
|
||||
currentLineData.splice(comparisonIndex, 2, lastLine);
|
||||
}
|
||||
|
||||
return currentLineData;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keyup={handleKeyPress} />
|
||||
|
||||
{$visibilityHandler$ ?? ''}
|
||||
{$handleLine$ ?? ''}
|
||||
{$pasteHandler$ ?? ''}
|
||||
{$copyBlocker$ ?? ''}
|
||||
{$resizeHandler$ ?? ''}
|
||||
|
||||
{#if $showSpinner$}
|
||||
<Spinner />
|
||||
{/if}
|
||||
|
||||
<DialogManager />
|
||||
|
||||
<header class="fixed top-0 right-0 flex justify-end items-center p-2 bg-base-100" bind:this={settingsContainer}>
|
||||
<Stats on:afkBlur={onAfkBlur} />
|
||||
{#if $websocketUrl$}
|
||||
<SocketConnector />
|
||||
{/if}
|
||||
{#if $secondaryWebsocketUrl$}
|
||||
<SocketConnector isPrimary={false} />
|
||||
{/if}
|
||||
{#if $isPaused$}
|
||||
<div
|
||||
role="button"
|
||||
title="Continue"
|
||||
class="mr-1 animate-[pulse_1.25s_cubic-bezier(0.4,0,0.6,1)_infinite] hover:text-primary sm:mr-2"
|
||||
>
|
||||
<Icon path={mdiPlay} width={iconSize} height={iconSize} on:click={() => ($isPaused$ = false)} />
|
||||
</div>
|
||||
{:else}
|
||||
<div role="button" title="Pause" class="mr-1 hover:text-primary sm:mr-2">
|
||||
<Icon path={mdiPause} width={iconSize} height={iconSize} on:click={() => ($isPaused$ = true)} />
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
role="button"
|
||||
title="Delete last Line"
|
||||
class="mr-1 hover:text-primary sm:mr-2"
|
||||
class:opacity-50={!$lineData$.length}
|
||||
class:cursor-not-allowed={!$lineData$.length}
|
||||
class:hover:text-primary={$lineData$.length}
|
||||
>
|
||||
<Icon path={mdiDeleteForever} width={iconSize} height={iconSize} on:click={removeLastLine} />
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
title="Undo last Action"
|
||||
class="mr-1 hover:text-primary sm:mr-2"
|
||||
class:opacity-50={!$actionHistory$.length}
|
||||
class:cursor-not-allowed={!$actionHistory$.length}
|
||||
class:hover:text-primary={$actionHistory$.length}
|
||||
>
|
||||
<Icon path={mdiArrowULeftTop} width={iconSize} height={iconSize} on:click={undoLastAction} />
|
||||
</div>
|
||||
{#if selectedLineIds.length}
|
||||
<div role="button" title="Remove selected Lines" class="mr-1 hover:text-primary sm:mr-2">
|
||||
<Icon path={mdiDelete} width={iconSize} height={iconSize} on:click={removeLines} />
|
||||
</div>
|
||||
<div role="button" title="Deselect Lines" class="mr-1 hover:text-primary sm:mr-2">
|
||||
<Icon path={mdiCancel} width={iconSize} height={iconSize} on:click={deselectLines} />
|
||||
</div>
|
||||
{/if}
|
||||
<div role="button" title="Open Notes" class="mr-1 hover:text-primary sm:mr-2">
|
||||
<Icon path={mdiNoteEdit} width={iconSize} height={iconSize} on:click={() => ($notesOpen$ = true)} />
|
||||
</div>
|
||||
{#if pipAvailable}
|
||||
<div
|
||||
role="button"
|
||||
class="mr-1 hover:text-primary sm:mr-2"
|
||||
title={pipWindow ? 'Close Floating Window' : 'Open Floating Window'}
|
||||
>
|
||||
<Icon
|
||||
width={iconSize}
|
||||
height={iconSize}
|
||||
path={pipWindow ? mdiWindowMaximize : mdiWindowRestore}
|
||||
on:click={handlePipAction}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<Icon
|
||||
class="cursor-pointer mr-1 hover:text-primary md:mr-2"
|
||||
path={mdiCog}
|
||||
width={iconSize}
|
||||
height={iconSize}
|
||||
bind:element={settingsElement}
|
||||
on:click={() => (settingsOpen = !settingsOpen)}
|
||||
/>
|
||||
<Settings
|
||||
{settingsElement}
|
||||
{pipAvailable}
|
||||
bind:settingsOpen
|
||||
bind:selectedLineIds
|
||||
bind:this={settingsComponent}
|
||||
on:applyReplacements={() => updateLineData(!!$enabledReplacements$.length)}
|
||||
on:layoutChange={executeUpdateScroll}
|
||||
on:maxLinesChange={() => ($lineData$ = applyMaxLinesAndGetRemainingLineData())}
|
||||
/>
|
||||
<Presets isQuickSwitch={true} on:layoutChange={executeUpdateScroll} />
|
||||
</header>
|
||||
<main
|
||||
class="flex flex-col flex-1 break-all px-4 w-full h-full overflow-auto"
|
||||
class:py-16={!$displayVertical$}
|
||||
class:py-8={$displayVertical$}
|
||||
class:opacity-50={$notesOpen$}
|
||||
class:flex-col-reverse={$reverseLineOrder$}
|
||||
style:font-size={`${$fontSize$}px`}
|
||||
style:font-family={$onlineFont$ !== OnlineFont.OFF ? $onlineFont$ : undefined}
|
||||
style:writing-mode={$displayVertical$ ? 'vertical-rl' : 'horizontal-tb'}
|
||||
bind:this={lineContainer}
|
||||
>
|
||||
{@html newLineCharacter}
|
||||
{#each $lineData$ as line, index (line.id)}
|
||||
<Line
|
||||
{line}
|
||||
{index}
|
||||
isLast={$lineData$.length - 1 === index}
|
||||
bind:this={lineElements[index]}
|
||||
on:selected={({ detail }) => {
|
||||
selectedLineIds = [...selectedLineIds, detail];
|
||||
}}
|
||||
on:deselected={({ detail }) => {
|
||||
selectedLineIds = selectedLineIds.filter((selectedLineId) => selectedLineId !== detail);
|
||||
}}
|
||||
on:edit={handleLineEdit}
|
||||
/>
|
||||
{/each}
|
||||
</main>
|
||||
{#if $notesOpen$}
|
||||
<div
|
||||
class="bg-base-200 fixed top-0 right-0 z-[60] flex h-full w-full max-w-3xl flex-col justify-between"
|
||||
in:fly|local={{ x: 100, duration: 100, easing: quintInOut }}
|
||||
>
|
||||
<Notes />
|
||||
</div>
|
||||
{/if}
|
||||
<div
|
||||
id="pip-container"
|
||||
class="flex flex-col flex-1 flex flex-col break-all px-4 w-full h-full overflow-auto"
|
||||
class:flex-col-reverse={$reverseLineOrder$}
|
||||
class:hidden={!pipWindow}
|
||||
style:font-size={`${$fontSize$}px`}
|
||||
style:font-family={$onlineFont$ !== OnlineFont.OFF ? $onlineFont$ : undefined}
|
||||
bind:this={pipContainer}
|
||||
>
|
||||
{#if pipWindow}
|
||||
{#each pipLines as line, index (line.id)}
|
||||
<Line {line} {index} {pipWindow} isLast={pipLines.length - 1 === index} />
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
64
vendor/texthooker-ui/src/components/Dialog.svelte
vendored
Normal file
64
vendor/texthooker-ui/src/components/Dialog.svelte
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
export let icon: string | undefined;
|
||||
export let message: string | undefined;
|
||||
export let type = 'info';
|
||||
export let showCancel = true;
|
||||
export let askForData = '';
|
||||
export let dataValue: string | number | undefined;
|
||||
export let callback: <T>(param: { canceled: boolean; data: T }) => void;
|
||||
|
||||
const dispatch = createEventDispatcher<{ close: void }>();
|
||||
|
||||
function handleChange(event: Event) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
|
||||
dataValue = target.value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="fixed top-12 flex justify-center w-full z-30">
|
||||
<div class="alert shadow-lg max-w-xl" class:alert-info={type === 'info'} class:alert-error={type === 'error'}>
|
||||
<div>
|
||||
{#if icon}
|
||||
<Icon path={icon} />
|
||||
{/if}
|
||||
<span>
|
||||
{#if askForData}
|
||||
<div>
|
||||
{#if askForData === 'text'}
|
||||
<input
|
||||
type={askForData}
|
||||
class="input input-bordered h-8 ml-2"
|
||||
value={dataValue}
|
||||
on:change={handleChange}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
{message}
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
{#if showCancel}
|
||||
<button
|
||||
class="btn btn-sm btn-ghost"
|
||||
on:click={() => {
|
||||
callback?.({ canceled: true, data: dataValue });
|
||||
dispatch('close');
|
||||
}}>Cancel</button
|
||||
>
|
||||
{/if}
|
||||
<button
|
||||
class="btn btn-sm btn-primary"
|
||||
on:click={() => {
|
||||
callback?.({ canceled: false, data: dataValue });
|
||||
dispatch('close');
|
||||
}}>Confirm</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
36
vendor/texthooker-ui/src/components/DialogManager.svelte
vendored
Normal file
36
vendor/texthooker-ui/src/components/DialogManager.svelte
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy } from 'svelte';
|
||||
import { dialogOpen$, openDialog$ } from '../stores/stores';
|
||||
import Dialog from './Dialog.svelte';
|
||||
|
||||
let props: any;
|
||||
let dialogPropsQueue: any[] = [];
|
||||
|
||||
const sub = openDialog$.subscribe((d) => {
|
||||
if (
|
||||
!d ||
|
||||
((d.message.includes('Lost Connection to') || d.message.includes('Unable to connect to')) &&
|
||||
(props?.message === d.message || dialogPropsQueue.find((dialog) => dialog.message === d.message)))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
dialogPropsQueue.unshift(d);
|
||||
|
||||
if (!props) {
|
||||
handleDialog();
|
||||
}
|
||||
});
|
||||
|
||||
function handleDialog() {
|
||||
props = dialogPropsQueue.pop();
|
||||
|
||||
$dialogOpen$ = !!props;
|
||||
}
|
||||
|
||||
onDestroy(() => sub?.unsubscribe());
|
||||
</script>
|
||||
|
||||
{#if props}
|
||||
<Dialog {...props} on:close={handleDialog} />
|
||||
{/if}
|
||||
21
vendor/texthooker-ui/src/components/Icon.svelte
vendored
Normal file
21
vendor/texthooker-ui/src/components/Icon.svelte
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
<script lang="ts">
|
||||
export let path: string;
|
||||
export let width = '1.5rem';
|
||||
export let height = '1.5rem';
|
||||
export let element: SVGElement | undefined = undefined;
|
||||
export { _class as class };
|
||||
|
||||
let _class = '';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
style="width: {width}; height: {height};"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class={_class}
|
||||
bind:this={element}
|
||||
on:click
|
||||
on:keyup
|
||||
>
|
||||
<path d={path} />
|
||||
</svg>
|
||||
143
vendor/texthooker-ui/src/components/Line.svelte
vendored
Normal file
143
vendor/texthooker-ui/src/components/Line.svelte
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
<script lang="ts">
|
||||
import { mdiTrophy } from '@mdi/js';
|
||||
import { createEventDispatcher, onDestroy, onMount, tick } from 'svelte';
|
||||
import { fly } from 'svelte/transition';
|
||||
import {
|
||||
displayVertical$,
|
||||
enableLineAnimation$,
|
||||
milestoneLines$,
|
||||
preserveWhitespace$,
|
||||
reverseLineOrder$,
|
||||
} from '../stores/stores';
|
||||
import type { LineItem, LineItemEditEvent } from '../types';
|
||||
import { dummyFn, newLineCharacter, updateScroll } from '../util';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
export let line: LineItem;
|
||||
export let index: number;
|
||||
export let isLast: boolean;
|
||||
export let pipWindow: Window = undefined;
|
||||
|
||||
export function deselect() {
|
||||
isSelected = false;
|
||||
}
|
||||
|
||||
export function getIdIfSelected(range: Range) {
|
||||
return isSelected || range.intersectsNode(paragraph) ? line.id : undefined;
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher<{ deselected: string; selected: string; edit: LineItemEditEvent }>();
|
||||
|
||||
let paragraph: HTMLElement;
|
||||
let originalText = '';
|
||||
let isSelected = false;
|
||||
let isEditable = false;
|
||||
|
||||
$: isVerticalDisplay = !pipWindow && $displayVertical$;
|
||||
|
||||
onMount(() => {
|
||||
if (isLast) {
|
||||
updateScroll(
|
||||
pipWindow || window,
|
||||
paragraph.parentElement,
|
||||
$reverseLineOrder$,
|
||||
isVerticalDisplay,
|
||||
$enableLineAnimation$ ? 'smooth' : 'auto',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
document.removeEventListener('click', clickOutsideHandler, false);
|
||||
dispatch('edit', { inEdit: false });
|
||||
});
|
||||
|
||||
function handleDblClick(event: MouseEvent) {
|
||||
if (pipWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.getSelection()?.removeAllRanges();
|
||||
|
||||
if (event.ctrlKey || event.metaKey) {
|
||||
if (isSelected) {
|
||||
isSelected = false;
|
||||
dispatch('deselected', line.id);
|
||||
} else {
|
||||
isSelected = true;
|
||||
dispatch('selected', line.id);
|
||||
}
|
||||
} else {
|
||||
originalText = paragraph.innerText;
|
||||
isEditable = true;
|
||||
|
||||
dispatch('edit', { inEdit: true });
|
||||
|
||||
document.addEventListener('click', clickOutsideHandler, false);
|
||||
|
||||
tick().then(() => {
|
||||
paragraph.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function clickOutsideHandler(event: MouseEvent) {
|
||||
const target = event.target as Node;
|
||||
|
||||
if (!paragraph.contains(target)) {
|
||||
isEditable = false;
|
||||
document.removeEventListener('click', clickOutsideHandler, false);
|
||||
|
||||
dispatch('edit', {
|
||||
inEdit: false,
|
||||
data: { originalText, newText: paragraph.innerText, lineIndex: index, line },
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#key line.text}
|
||||
<p
|
||||
class="my-2 cursor-pointer border-2"
|
||||
class:py-4={!isVerticalDisplay}
|
||||
class:px-2={!isVerticalDisplay}
|
||||
class:py-2={isVerticalDisplay}
|
||||
class:px-4={isVerticalDisplay}
|
||||
class:border-transparent={!isSelected}
|
||||
class:cursor-text={isEditable}
|
||||
class:border-primary={isSelected}
|
||||
class:border-accent-focus={isEditable}
|
||||
class:whitespace-pre-wrap={$preserveWhitespace$}
|
||||
contenteditable={isEditable}
|
||||
on:dblclick={handleDblClick}
|
||||
on:keyup={dummyFn}
|
||||
bind:this={paragraph}
|
||||
in:fly={{ x: isVerticalDisplay ? 100 : -100, duration: $enableLineAnimation$ ? 250 : 0 }}
|
||||
>
|
||||
{line.text}
|
||||
</p>
|
||||
{/key}
|
||||
{@html newLineCharacter}
|
||||
{#if $milestoneLines$.has(line.id)}
|
||||
<div
|
||||
class="flex justify-center text-xs my-2 py-2 border-primary border-dashed milestone"
|
||||
class:border-x-2={$displayVertical$}
|
||||
class:border-y-2={!$displayVertical$}
|
||||
class:py-4={!isVerticalDisplay}
|
||||
class:px-2={!isVerticalDisplay}
|
||||
class:py-2={isVerticalDisplay}
|
||||
class:px-4={isVerticalDisplay}
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<Icon class={$displayVertical$ ? '' : 'mr-2'} path={mdiTrophy}></Icon>
|
||||
<span class:mt-2={$displayVertical$}>{$milestoneLines$.get(line.id)}</span>
|
||||
</div>
|
||||
</div>
|
||||
{@html newLineCharacter}
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
p:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
</style>
|
||||
26
vendor/texthooker-ui/src/components/Notes.svelte
vendored
Normal file
26
vendor/texthooker-ui/src/components/Notes.svelte
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import { mdiClose } from '@mdi/js';
|
||||
import { notesOpen$, userNotes$ } from '../stores/stores';
|
||||
import { dummyFn } from '../util';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
function handleBlur(event: FocusEvent) {
|
||||
$userNotes$ = (event.target as HTMLTextAreaElement).value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-end p-4">
|
||||
<div
|
||||
class="flex cursor-pointer items-end md:items-center"
|
||||
on:click={() => ($notesOpen$ = false)}
|
||||
on:keyup={dummyFn}
|
||||
>
|
||||
<Icon path={mdiClose} />
|
||||
</div>
|
||||
</div>
|
||||
<textarea
|
||||
class="flex-1 overflow-auto ml-10 mr-2 mb-4 p-1 pb-2"
|
||||
style="resize: none;"
|
||||
value={$userNotes$}
|
||||
on:blur={handleBlur}
|
||||
/>
|
||||
330
vendor/texthooker-ui/src/components/Presets.svelte
vendored
Normal file
330
vendor/texthooker-ui/src/components/Presets.svelte
vendored
Normal file
@@ -0,0 +1,330 @@
|
||||
<script lang="ts">
|
||||
import { mdiContentSave, mdiDatabaseSync, mdiDelete, mdiHelpCircle, mdiReload } from '@mdi/js';
|
||||
import { createEventDispatcher, tick } from 'svelte';
|
||||
import {
|
||||
adjustTimerOnAfk$,
|
||||
afkTimer$,
|
||||
allowNewLineDuringPause$,
|
||||
allowPasteDuringPause$,
|
||||
autoStartTimerDuringPause$,
|
||||
autoStartTimerDuringPausePaste$,
|
||||
blockCopyOnPage$,
|
||||
blurStats$,
|
||||
characterMilestone$,
|
||||
continuousReconnect$,
|
||||
customCSS$,
|
||||
defaultSettings,
|
||||
displayVertical$,
|
||||
enableAfkBlur$,
|
||||
enableAfkBlurRestart$,
|
||||
enableExternalClipboardMonitor$,
|
||||
enableLineAnimation$,
|
||||
enablePaste$,
|
||||
filterNonCJKLines$,
|
||||
flashOnMissedLine$,
|
||||
fontSize$,
|
||||
lastSettingPreset$,
|
||||
maxLines$,
|
||||
maxPipLines$,
|
||||
mergeEqualLineStarts$,
|
||||
milestoneLines$,
|
||||
onlineFont$,
|
||||
openDialog$,
|
||||
persistActionHistory$,
|
||||
persistLines$,
|
||||
persistNotes$,
|
||||
persistStats$,
|
||||
preserveWhitespace$,
|
||||
preventGlobalDuplicate$,
|
||||
preventLastDuplicate$,
|
||||
reconnectSecondarySocket$,
|
||||
reconnectSocket$,
|
||||
removeAllWhitespace$,
|
||||
replacements$,
|
||||
reverseLineOrder$,
|
||||
secondarySocketState$,
|
||||
secondaryWebsocketUrl$,
|
||||
settingPresets$,
|
||||
showCharacterCount$,
|
||||
showConnectionErrors$,
|
||||
showConnectionIcon$,
|
||||
showLineCount$,
|
||||
showPresetQuickSwitch$,
|
||||
showSpeed$,
|
||||
showTimer$,
|
||||
skipResetConfirmations$,
|
||||
socketState$,
|
||||
theme$,
|
||||
websocketUrl$,
|
||||
windowTitle$,
|
||||
} from '../stores/stores';
|
||||
import type { DialogResult, SettingPreset, Settings } from '../types';
|
||||
import { dummyFn } from '../util';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
export let isQuickSwitch = false;
|
||||
|
||||
export function getCurrentSettings(): Settings {
|
||||
return {
|
||||
theme$: $theme$,
|
||||
replacements$: $replacements$,
|
||||
windowTitle$: $windowTitle$,
|
||||
websocketUrl$: $websocketUrl$,
|
||||
secondaryWebsocketUrl$: $secondaryWebsocketUrl$,
|
||||
fontSize$: $fontSize$,
|
||||
characterMilestone$: $characterMilestone$,
|
||||
onlineFont$: $onlineFont$,
|
||||
preventLastDuplicate$: $preventLastDuplicate$,
|
||||
maxLines$: $maxLines$,
|
||||
maxPipLines$: $maxPipLines$,
|
||||
afkTimer$: $afkTimer$,
|
||||
adjustTimerOnAfk$: $adjustTimerOnAfk$,
|
||||
enableExternalClipboardMonitor$: $enableExternalClipboardMonitor$,
|
||||
showPresetQuickSwitch$: $showPresetQuickSwitch$,
|
||||
skipResetConfirmations$: $skipResetConfirmations$,
|
||||
persistStats$: $persistStats$,
|
||||
persistNotes$: $persistNotes$,
|
||||
persistLines$: $persistLines$,
|
||||
persistActionHistory$: $persistActionHistory$,
|
||||
enablePaste$: $enablePaste$,
|
||||
blockCopyOnPage$: $blockCopyOnPage$,
|
||||
allowPasteDuringPause$: $allowPasteDuringPause$,
|
||||
allowNewLineDuringPause$: $allowNewLineDuringPause$,
|
||||
autoStartTimerDuringPausePaste$: $autoStartTimerDuringPausePaste$,
|
||||
autoStartTimerDuringPause$: $autoStartTimerDuringPause$,
|
||||
preventGlobalDuplicate$: $preventGlobalDuplicate$,
|
||||
mergeEqualLineStarts$: $mergeEqualLineStarts$,
|
||||
filterNonCJKLines: $filterNonCJKLines$,
|
||||
flashOnMissedLine$: $flashOnMissedLine$,
|
||||
displayVertical$: $displayVertical$,
|
||||
reverseLineOrder$: $reverseLineOrder$,
|
||||
preserveWhitespace$: $preserveWhitespace$,
|
||||
removeAllWhitespace$: $removeAllWhitespace$,
|
||||
showTimer$: $showTimer$,
|
||||
showSpeed$: $showSpeed$,
|
||||
showCharacterCount$: $showCharacterCount$,
|
||||
showLineCount$: $showLineCount$,
|
||||
blurStats$: $blurStats$,
|
||||
enableLineAnimation$: $enableLineAnimation$,
|
||||
enableAfkBlur$: $enableAfkBlur$,
|
||||
enableAfkBlurRestart$: $enableAfkBlurRestart$,
|
||||
continuousReconnect$: $continuousReconnect$,
|
||||
showConnectionErrors$: $showConnectionErrors$,
|
||||
showConnectionIcon$: $showConnectionIcon$,
|
||||
customCSS$: $customCSS$,
|
||||
};
|
||||
}
|
||||
|
||||
export function updateSettingsWithPreset(preset: SettingPreset, updateLastPreset = true) {
|
||||
theme$.next(preset.settings.theme$ ?? defaultSettings.theme$);
|
||||
replacements$.next(preset.settings.replacements$ ?? defaultSettings.replacements$);
|
||||
windowTitle$.next(preset.settings.windowTitle$ ?? defaultSettings.windowTitle$);
|
||||
websocketUrl$.next(preset.settings.websocketUrl$ ?? defaultSettings.websocketUrl$);
|
||||
secondaryWebsocketUrl$.next(preset.settings.secondaryWebsocketUrl$ ?? '');
|
||||
fontSize$.next(preset.settings.fontSize$ ?? defaultSettings.fontSize$);
|
||||
characterMilestone$.next(preset.settings.characterMilestone$ ?? defaultSettings.characterMilestone$);
|
||||
onlineFont$.next(preset.settings.onlineFont$ ?? defaultSettings.onlineFont$);
|
||||
preventLastDuplicate$.next(preset.settings.preventLastDuplicate$ ?? defaultSettings.preventLastDuplicate$);
|
||||
maxLines$.next(preset.settings.maxLines$ ?? defaultSettings.maxLines$);
|
||||
maxPipLines$.next(preset.settings.maxPipLines$ ?? defaultSettings.maxPipLines$);
|
||||
afkTimer$.next(preset.settings.afkTimer$ ?? defaultSettings.afkTimer$);
|
||||
adjustTimerOnAfk$.next(preset.settings.adjustTimerOnAfk$ ?? defaultSettings.adjustTimerOnAfk$);
|
||||
enableExternalClipboardMonitor$.next(
|
||||
preset.settings.enableExternalClipboardMonitor$ ?? defaultSettings.enableExternalClipboardMonitor$,
|
||||
);
|
||||
showPresetQuickSwitch$.next(preset.settings.showPresetQuickSwitch$ ?? defaultSettings.showPresetQuickSwitch$);
|
||||
skipResetConfirmations$.next(
|
||||
preset.settings.skipResetConfirmations$ ?? defaultSettings.skipResetConfirmations$,
|
||||
);
|
||||
persistStats$.next(preset.settings.persistStats$ ?? defaultSettings.persistStats$);
|
||||
persistNotes$.next(preset.settings.persistNotes$ ?? defaultSettings.persistNotes$);
|
||||
persistLines$.next(preset.settings.persistLines$ ?? defaultSettings.persistLines$);
|
||||
persistActionHistory$.next(preset.settings.persistActionHistory$ ?? defaultSettings.persistActionHistory$);
|
||||
enablePaste$.next(preset.settings.enablePaste$ ?? defaultSettings.enablePaste$);
|
||||
blockCopyOnPage$.next(preset.settings.blockCopyOnPage$ ?? defaultSettings.blockCopyOnPage$);
|
||||
allowPasteDuringPause$.next(preset.settings.allowPasteDuringPause$ ?? defaultSettings.allowPasteDuringPause$);
|
||||
allowNewLineDuringPause$.next(
|
||||
preset.settings.allowNewLineDuringPause$ ?? defaultSettings.allowNewLineDuringPause$,
|
||||
);
|
||||
autoStartTimerDuringPausePaste$.next(
|
||||
preset.settings.autoStartTimerDuringPausePaste$ ?? defaultSettings.autoStartTimerDuringPausePaste$,
|
||||
);
|
||||
autoStartTimerDuringPause$.next(
|
||||
preset.settings.autoStartTimerDuringPause$ ?? defaultSettings.autoStartTimerDuringPause$,
|
||||
);
|
||||
preventGlobalDuplicate$.next(
|
||||
preset.settings.preventGlobalDuplicate$ ?? defaultSettings.preventGlobalDuplicate$,
|
||||
);
|
||||
mergeEqualLineStarts$.next(preset.settings.mergeEqualLineStarts$ ?? defaultSettings.mergeEqualLineStarts$);
|
||||
filterNonCJKLines$.next(preset.settings.filterNonCJKLines ?? defaultSettings.filterNonCJKLines);
|
||||
flashOnMissedLine$.next(preset.settings.flashOnMissedLine$ ?? defaultSettings.flashOnMissedLine$);
|
||||
displayVertical$.next(preset.settings.displayVertical$ ?? defaultSettings.displayVertical$);
|
||||
reverseLineOrder$.next(preset.settings.reverseLineOrder$ ?? defaultSettings.reverseLineOrder$);
|
||||
preserveWhitespace$.next(preset.settings.preserveWhitespace$ ?? defaultSettings.preserveWhitespace$);
|
||||
removeAllWhitespace$.next(preset.settings.removeAllWhitespace$ ?? defaultSettings.removeAllWhitespace$);
|
||||
showTimer$.next(preset.settings.showTimer$ ?? defaultSettings.showTimer$);
|
||||
showSpeed$.next(preset.settings.showSpeed$ ?? defaultSettings.showSpeed$);
|
||||
showCharacterCount$.next(preset.settings.showCharacterCount$ ?? defaultSettings.showCharacterCount$);
|
||||
showLineCount$.next(preset.settings.showLineCount$ ?? defaultSettings.showLineCount$);
|
||||
blurStats$.next(preset.settings.blurStats$ ?? defaultSettings.blurStats$);
|
||||
enableLineAnimation$.next(preset.settings.enableLineAnimation$ ?? defaultSettings.enableLineAnimation$);
|
||||
enableAfkBlur$.next(preset.settings.enableAfkBlur$ ?? defaultSettings.enableAfkBlur$);
|
||||
enableAfkBlurRestart$.next(preset.settings.enableAfkBlurRestart$ ?? defaultSettings.enableAfkBlurRestart$);
|
||||
continuousReconnect$.next(preset.settings.continuousReconnect$ ?? defaultSettings.continuousReconnect$);
|
||||
showConnectionErrors$.next(preset.settings.showConnectionErrors$ ?? defaultSettings.showConnectionErrors$);
|
||||
showConnectionIcon$.next(preset.settings.showConnectionIcon$ ?? defaultSettings.showConnectionIcon$);
|
||||
customCSS$.next(preset.settings.customCSS$ ?? defaultSettings.customCSS$);
|
||||
|
||||
if (updateLastPreset) {
|
||||
$lastSettingPreset$ = preset.name;
|
||||
}
|
||||
|
||||
if ($characterMilestone$ === 0) {
|
||||
$milestoneLines$ = new Map<string, string>();
|
||||
}
|
||||
|
||||
tick().then(() => {
|
||||
dispatch('layoutChange');
|
||||
|
||||
if ($socketState$ !== 1 && $continuousReconnect$) {
|
||||
reconnectSocket$.next();
|
||||
}
|
||||
|
||||
if ($secondarySocketState$ !== 1 && $continuousReconnect$) {
|
||||
reconnectSecondarySocket$.next();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const fallbackPresetEntry = [{ name: '' }];
|
||||
const dispatch = createEventDispatcher<{ layoutChange: void; exportImportPreset: MouseEvent }>();
|
||||
|
||||
function selectPreset(event: Event) {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
|
||||
changePreset(target.selectedOptions[0].value);
|
||||
}
|
||||
|
||||
function changePreset(presetName: string) {
|
||||
const existingEntry = $settingPresets$.find((entry) => entry.name === presetName);
|
||||
|
||||
if (existingEntry) {
|
||||
updateSettingsWithPreset(existingEntry);
|
||||
}
|
||||
}
|
||||
|
||||
async function savePreset() {
|
||||
const { canceled, data } = await new Promise<DialogResult<string>>((resolve) => {
|
||||
$openDialog$ = {
|
||||
icon: mdiHelpCircle,
|
||||
askForData: 'text',
|
||||
dataValue: $lastSettingPreset$ || 'Preset Name',
|
||||
message: '',
|
||||
callback: resolve,
|
||||
};
|
||||
});
|
||||
|
||||
if (canceled || !data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existingEntryIndex = $settingPresets$.findIndex((entry) => entry.name === data);
|
||||
const entry: SettingPreset = {
|
||||
name: data,
|
||||
settings: getCurrentSettings(),
|
||||
};
|
||||
|
||||
if (existingEntryIndex > -1) {
|
||||
$settingPresets$[existingEntryIndex] = entry;
|
||||
} else {
|
||||
$settingPresets$ = [...$settingPresets$, entry];
|
||||
}
|
||||
|
||||
$lastSettingPreset$ = data;
|
||||
}
|
||||
|
||||
async function deletePreset() {
|
||||
if (!$skipResetConfirmations$) {
|
||||
const { canceled } = await new Promise<DialogResult>((resolve) => {
|
||||
$openDialog$ = {
|
||||
icon: mdiHelpCircle,
|
||||
message: 'Preset will be deleted',
|
||||
callback: resolve,
|
||||
};
|
||||
});
|
||||
|
||||
if (canceled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$settingPresets$ = $settingPresets$.filter((entry) => entry.name !== $lastSettingPreset$);
|
||||
$lastSettingPreset$ = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if isQuickSwitch}
|
||||
<select
|
||||
class="w-48 hidden sm:block"
|
||||
class:sm:hidden={!$showPresetQuickSwitch$ || $settingPresets$.length < 2}
|
||||
value={$lastSettingPreset$}
|
||||
on:change={selectPreset}
|
||||
>
|
||||
{#each $settingPresets$.length ? $settingPresets$ : fallbackPresetEntry as preset (preset.name)}
|
||||
<option value={preset.name}>
|
||||
{preset.name}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<details role="button" class="col-span-4 mb-2">
|
||||
<summary>Presets</summary>
|
||||
<div class="flex items-center justify-between mt-2">
|
||||
<select class="select flex-1 max-w-md" value={$lastSettingPreset$} on:change={selectPreset}>
|
||||
{#each $settingPresets$.length ? $settingPresets$ : fallbackPresetEntry as preset (preset.name)}
|
||||
<option value={preset.name}>
|
||||
{preset.name || 'No Presets stored'}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
<div
|
||||
role="button"
|
||||
class="flex flex-col items-center hover:text-primary ml-3"
|
||||
on:click={savePreset}
|
||||
on:keyup={dummyFn}
|
||||
>
|
||||
<Icon path={mdiContentSave} />
|
||||
<span class="label-text">Save</span>
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
class="flex flex-col items-center hover:text-primary ml-3"
|
||||
on:click={(event) => dispatch('exportImportPreset', event)}
|
||||
on:keyup={dummyFn}
|
||||
>
|
||||
<Icon path={mdiDatabaseSync} />
|
||||
<span class="label-text">Export/Import</span>
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
class="flex flex-col items-center hover:text-primary ml-3"
|
||||
class:invisible={!$lastSettingPreset$}
|
||||
on:click={() => changePreset($lastSettingPreset$)}
|
||||
on:keyup={dummyFn}
|
||||
>
|
||||
<Icon path={mdiReload} />
|
||||
<span class="label-text">Reload</span>
|
||||
</div>
|
||||
<div
|
||||
role="button"
|
||||
class="flex flex-col items-center hover:text-primary ml-3"
|
||||
class:invisible={!$lastSettingPreset$}
|
||||
on:click={deletePreset}
|
||||
on:keyup={dummyFn}
|
||||
>
|
||||
<Icon path={mdiDelete} />
|
||||
<span class="label-text">Delete</span>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
{/if}
|
||||
52
vendor/texthooker-ui/src/components/ReplacementSettings.svelte
vendored
Normal file
52
vendor/texthooker-ui/src/components/ReplacementSettings.svelte
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
<script lang="ts">
|
||||
import { mdiPlus } from '@mdi/js';
|
||||
import { replacements$ } from '../stores/stores';
|
||||
import type { ReplacementItem } from '../types';
|
||||
import Icon from './Icon.svelte';
|
||||
import ReplacementSettingsInput from './ReplacementSettingsInput.svelte';
|
||||
import ReplacementSettingsList from './ReplacementSettingsList.svelte';
|
||||
|
||||
let inEditMode = false;
|
||||
|
||||
let currentReplacement: ReplacementItem | undefined;
|
||||
|
||||
$: hasReplacements = !!$replacements$.length;
|
||||
|
||||
$: resetEditMode($replacements$);
|
||||
|
||||
function resetEditMode(_replacements: ReplacementItem[]) {
|
||||
inEditMode = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<details class="col-span-4 mb-2 cursor-pointer max-w-lg">
|
||||
<summary>Replacements</summary>
|
||||
<div class="mb-8">
|
||||
{#if inEditMode}
|
||||
<ReplacementSettingsInput
|
||||
{currentReplacement}
|
||||
on:close={() => {
|
||||
inEditMode = false;
|
||||
currentReplacement = undefined;
|
||||
}}
|
||||
/>
|
||||
{:else if hasReplacements}
|
||||
{#key $replacements$}
|
||||
<ReplacementSettingsList
|
||||
on:edit={({ detail }) => {
|
||||
currentReplacement = detail;
|
||||
inEditMode = true;
|
||||
}}
|
||||
on:applyReplacements
|
||||
/>
|
||||
{/key}
|
||||
{:else}
|
||||
<div class="flex justify-end my-2">
|
||||
<button title="Add replacement" class="ml-2 hover:text-primary" on:click={() => (inEditMode = true)}>
|
||||
<Icon path={mdiPlus} />
|
||||
</button>
|
||||
</div>
|
||||
<div>You have currently no replacements configured</div>
|
||||
{/if}
|
||||
</div>
|
||||
</details>
|
||||
132
vendor/texthooker-ui/src/components/ReplacementSettingsInput.svelte
vendored
Normal file
132
vendor/texthooker-ui/src/components/ReplacementSettingsInput.svelte
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
<script lang="ts">
|
||||
import { mdiCancel, mdiFloppy, mdiInformation } from '@mdi/js';
|
||||
import { debounceTime, Subject, tap } from 'rxjs';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import { replacements$ } from '../stores/stores';
|
||||
import type { ReplacementItem } from '../types';
|
||||
import { applyReplacements, reduceToEmptyString } from '../util';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
export let currentReplacement: ReplacementItem | undefined;
|
||||
|
||||
const dispatch = createEventDispatcher<{ close: void }>();
|
||||
|
||||
const applyPattern$ = new Subject<void>();
|
||||
const replacement: ReplacementItem = currentReplacement
|
||||
? JSON.parse(JSON.stringify(currentReplacement))
|
||||
: { pattern: '', replaces: '', flags: [], enabled: true };
|
||||
const flags = [
|
||||
{ label: 'global', value: 'g' },
|
||||
{ label: 'multiline', value: 'm' },
|
||||
{ label: 'insensitive', value: 'i' },
|
||||
{ label: 'unicode', value: 'u' },
|
||||
];
|
||||
|
||||
const executePattern$ = applyPattern$.pipe(
|
||||
debounceTime(500),
|
||||
tap(() => {
|
||||
try {
|
||||
currentPatternError = '';
|
||||
|
||||
if (!replacement.pattern || !currentTestValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentTestOutcome = applyReplacements(currentTestValue, [replacement]);
|
||||
} catch ({ message }) {
|
||||
currentPatternError = `Error: ${message}`;
|
||||
}
|
||||
}),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
let patternInput: HTMLInputElement;
|
||||
let currentTestValue = '';
|
||||
let currentTestOutcome = '';
|
||||
let currentPatternError = '';
|
||||
|
||||
function onExecutePattern() {
|
||||
patternInput.setCustomValidity(currentPatternError);
|
||||
|
||||
applyPattern$.next();
|
||||
}
|
||||
|
||||
function onSave() {
|
||||
if (!currentReplacement && $replacements$.find((entry) => entry.pattern === replacement.pattern)) {
|
||||
patternInput.setCustomValidity('This pattern already exists');
|
||||
|
||||
return patternInput.reportValidity();
|
||||
}
|
||||
|
||||
if (currentReplacement) {
|
||||
$replacements$ = $replacements$.map((entry) => {
|
||||
if (entry.pattern === currentReplacement.pattern) {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
return entry;
|
||||
});
|
||||
} else {
|
||||
$replacements$ = [...$replacements$, replacement];
|
||||
}
|
||||
|
||||
dispatch('close');
|
||||
}
|
||||
</script>
|
||||
|
||||
{$executePattern$ ?? ''}
|
||||
<div class="flex justify-end my-2">
|
||||
{#if replacement.pattern}
|
||||
<button title="Save" class="hover:text-primary" on:click={onSave}>
|
||||
<Icon path={mdiFloppy} />
|
||||
</button>
|
||||
{/if}
|
||||
<button title="Cancel" class="ml-2 hover:text-primary" on:click={() => dispatch('close')}>
|
||||
<Icon path={mdiCancel} />
|
||||
</button>
|
||||
<button
|
||||
title="Cancel"
|
||||
class="ml-2 hover:text-primary"
|
||||
on:click={() =>
|
||||
window.open(
|
||||
'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#description',
|
||||
'_blank',
|
||||
)}
|
||||
>
|
||||
<Icon path={mdiInformation} />
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
placeholder="text pattern"
|
||||
class="w-full my-2"
|
||||
bind:value={replacement.pattern}
|
||||
bind:this={patternInput}
|
||||
on:input={onExecutePattern}
|
||||
/>
|
||||
<input
|
||||
placeholder="replacement pattern"
|
||||
class="w-full my-2"
|
||||
bind:value={replacement.replaces}
|
||||
on:input={onExecutePattern}
|
||||
/>
|
||||
<div class="flex justify-between my-4">
|
||||
{#each flags as flag (flag.value)}
|
||||
<label>
|
||||
<input type="checkbox" value={flag.value} bind:group={replacement.flags} on:change={onExecutePattern} />
|
||||
{flag.label}
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
<textarea
|
||||
name="test-value"
|
||||
placeholder="test value"
|
||||
class="w-full my-4"
|
||||
rows="3"
|
||||
bind:value={currentTestValue}
|
||||
on:input={onExecutePattern}
|
||||
/>
|
||||
<div class="whitespace-pre-wrap break-all">
|
||||
{@html currentPatternError || currentTestOutcome}
|
||||
</div>
|
||||
</div>
|
||||
118
vendor/texthooker-ui/src/components/ReplacementSettingsList.svelte
vendored
Normal file
118
vendor/texthooker-ui/src/components/ReplacementSettingsList.svelte
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
mdiDownloadMultiple,
|
||||
mdiPencil,
|
||||
mdiPlus,
|
||||
mdiToggleSwitchOffOutline,
|
||||
mdiToggleSwitchOutline,
|
||||
mdiTrashCanOutline,
|
||||
} from '@mdi/js';
|
||||
import Sortable, { Swap } from 'sortablejs';
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
import { enabledReplacements$, lineData$, replacements$ } from '../stores/stores';
|
||||
import type { ReplacementItem } from '../types';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
const dispatch = createEventDispatcher<{ edit: ReplacementItem | undefined; applyReplacements: void }>();
|
||||
|
||||
let sortableInstance: Sortable;
|
||||
let listContainer: HTMLDivElement;
|
||||
let listItems = JSON.parse(JSON.stringify($replacements$));
|
||||
|
||||
$: canApplyReplacements = !!$lineData$.length && !!$enabledReplacements$.length;
|
||||
|
||||
onMount(() => {
|
||||
try {
|
||||
Sortable.mount(new Swap());
|
||||
} catch (_) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
sortableInstance = Sortable.create(listContainer, {
|
||||
swap: true,
|
||||
swapClass: 'swap',
|
||||
animation: 150,
|
||||
store: {
|
||||
get: getSortableList,
|
||||
set: onUpdateList,
|
||||
},
|
||||
});
|
||||
|
||||
return () => sortableInstance?.destroy();
|
||||
});
|
||||
|
||||
function onToggle(newValue: boolean) {
|
||||
const sortedList = getSortedList();
|
||||
|
||||
listItems = sortedList.map((replacement) => ({ ...replacement, enabled: newValue }));
|
||||
$replacements$ = listItems;
|
||||
}
|
||||
|
||||
function onUpdateList() {
|
||||
$replacements$ = getSortedList();
|
||||
}
|
||||
|
||||
function onReplaceItems(newReplacements: ReplacementItem[]) {
|
||||
listItems = newReplacements;
|
||||
$replacements$ = newReplacements;
|
||||
|
||||
sortableInstance.sort(getSortableList(), false);
|
||||
}
|
||||
|
||||
function getSortableList() {
|
||||
return [...listItems.map((replacments) => replacments.pattern)];
|
||||
}
|
||||
|
||||
function getSortedList() {
|
||||
const sortedList = sortableInstance.toArray();
|
||||
|
||||
return listItems.slice().sort((a, b) => sortedList.indexOf(a.pattern) - sortedList.indexOf(b.pattern));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex justify-end my-2">
|
||||
<button
|
||||
title="Apply to current lines"
|
||||
class:hover:text-primary={canApplyReplacements}
|
||||
class:cursor-not-allowed={!canApplyReplacements}
|
||||
disabled={!canApplyReplacements}
|
||||
on:click={() => dispatch('applyReplacements')}
|
||||
>
|
||||
<Icon path={mdiDownloadMultiple} />
|
||||
</button>
|
||||
<button title="Add replacement" class="ml-2 hover:text-primary" on:click={() => dispatch('edit', undefined)}>
|
||||
<Icon path={mdiPlus} />
|
||||
</button>
|
||||
<button title="Enable all" class="ml-2 hover:text-primary" on:click={() => onToggle(true)}>
|
||||
<Icon path={mdiToggleSwitchOutline} />
|
||||
</button>
|
||||
<button title="Disable all" class="ml-2 hover:text-primary" on:click={() => onToggle(false)}>
|
||||
<Icon path={mdiToggleSwitchOffOutline} />
|
||||
</button>
|
||||
<button title="Remove all" class="ml-2 hover:text-primary" on:click={() => onReplaceItems([])}>
|
||||
<Icon path={mdiTrashCanOutline} />
|
||||
</button>
|
||||
</div>
|
||||
<div class="max-h-72 overflow-auto" bind:this={listContainer}>
|
||||
{#each listItems as replacement (replacement.pattern)}
|
||||
<div class="border my-2 p-2 flex items-center justify-between" data-id={replacement.pattern}>
|
||||
<div class="break-all">
|
||||
{replacement.pattern}
|
||||
</div>
|
||||
<div class="min-w-max ml-2">
|
||||
<button title="Edit" class="hover:text-primary" on:click={() => dispatch('edit', replacement)}>
|
||||
<Icon path={mdiPencil} height="1rem" />
|
||||
</button>
|
||||
<button
|
||||
title="Remove"
|
||||
class="hover:text-primary"
|
||||
on:click={() =>
|
||||
onReplaceItems($replacements$.filter((entry) => entry.pattern !== replacement.pattern))}
|
||||
>
|
||||
<Icon path={mdiTrashCanOutline} height="1rem" />
|
||||
</button>
|
||||
<input type="checkbox" class="ml-1" bind:checked={replacement.enabled} on:change={onUpdateList} />
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
1013
vendor/texthooker-ui/src/components/Settings.svelte
vendored
Normal file
1013
vendor/texthooker-ui/src/components/Settings.svelte
vendored
Normal file
File diff suppressed because it is too large
Load Diff
121
vendor/texthooker-ui/src/components/SocketConnector.svelte
vendored
Normal file
121
vendor/texthooker-ui/src/components/SocketConnector.svelte
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
<script lang="ts">
|
||||
import { mdiConnection } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { SocketConnection } from '../socket';
|
||||
import {
|
||||
continuousReconnect$,
|
||||
isPaused$,
|
||||
openDialog$,
|
||||
reconnectSecondarySocket$,
|
||||
reconnectSocket$,
|
||||
secondarySocketState$,
|
||||
secondaryWebsocketUrl$,
|
||||
showConnectionErrors$,
|
||||
showConnectionIcon$,
|
||||
socketState$,
|
||||
websocketUrl$,
|
||||
} from '../stores/stores';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
export let isPrimary = true;
|
||||
|
||||
let socketConnection: SocketConnection | undefined;
|
||||
let intitialAttemptDone = false;
|
||||
let wasConnected = false;
|
||||
let closeRequested = false;
|
||||
let socketState = isPrimary ? socketState$ : secondarySocketState$;
|
||||
|
||||
$: connectedWithLabel = updateConnectedWithLabel(wasConnected);
|
||||
|
||||
$: handleSocketState($socketState);
|
||||
|
||||
onMount(() => {
|
||||
toggleSocket();
|
||||
|
||||
return () => {
|
||||
closeRequested = true;
|
||||
socketConnection?.cleanUp();
|
||||
};
|
||||
});
|
||||
|
||||
function handleSocketState(socketStateValue) {
|
||||
switch (socketStateValue) {
|
||||
case 0:
|
||||
wasConnected = false;
|
||||
closeRequested = false;
|
||||
break;
|
||||
case 1:
|
||||
intitialAttemptDone = true;
|
||||
wasConnected = true;
|
||||
break;
|
||||
case 3:
|
||||
const socketType = isPrimary ? 'primary' : 'secondary';
|
||||
const socketUrl = isPrimary ? $websocketUrl$ : $secondaryWebsocketUrl$;
|
||||
|
||||
if (
|
||||
$showConnectionErrors$ &&
|
||||
!closeRequested &&
|
||||
intitialAttemptDone &&
|
||||
socketUrl &&
|
||||
(wasConnected || !$continuousReconnect$)
|
||||
) {
|
||||
$openDialog$ = {
|
||||
type: 'error',
|
||||
message: wasConnected
|
||||
? `Lost Connection to ${socketType} Websocket`
|
||||
: `Unable to connect to ${socketType} Websocket`,
|
||||
showCancel: false,
|
||||
};
|
||||
}
|
||||
|
||||
$isPaused$ = true;
|
||||
|
||||
intitialAttemptDone = true;
|
||||
wasConnected = false;
|
||||
|
||||
if (!closeRequested) {
|
||||
(isPrimary ? reconnectSocket$ : reconnectSecondarySocket$).next();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
connectedWithLabel = updateConnectedWithLabel(wasConnected);
|
||||
}
|
||||
|
||||
function updateConnectedWithLabel(hasConnection: boolean) {
|
||||
return hasConnection
|
||||
? `Connected with ${isPrimary ? $websocketUrl$ : $secondaryWebsocketUrl$}`
|
||||
: 'Not Connected';
|
||||
}
|
||||
|
||||
async function toggleSocket() {
|
||||
if ($socketState === 1 && socketConnection) {
|
||||
closeRequested = true;
|
||||
socketConnection.disconnect();
|
||||
} else {
|
||||
socketConnection = socketConnection || new SocketConnection(isPrimary);
|
||||
socketConnection.connect();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $socketState !== 0}
|
||||
<div
|
||||
class="hover:text-primary"
|
||||
class:text-red-500={$socketState !== -1}
|
||||
class:text-green-700={$socketState === 1}
|
||||
class:hidden={!$showConnectionIcon$}
|
||||
title={connectedWithLabel}
|
||||
>
|
||||
<Icon path={mdiConnection} class="cursor-pointer mx-2" on:click={toggleSocket} />
|
||||
</div>
|
||||
{:else}
|
||||
<span
|
||||
class="animate-ping relative inline-flex rounded-full h-3 w-3 mx-3 bg-primary"
|
||||
class:hidden={!$showConnectionIcon$}
|
||||
/>
|
||||
{/if}
|
||||
23
vendor/texthooker-ui/src/components/Spinner.svelte
vendored
Normal file
23
vendor/texthooker-ui/src/components/Spinner.svelte
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<div class="tap-highlight-transparent absolute inset-0 bg-black/[.3] z-20" />
|
||||
<div class="fixed inset-0 flex h-full w-full items-center justify-center z-50">
|
||||
<div role="status">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div />
|
||||
216
vendor/texthooker-ui/src/components/Stats.svelte
vendored
Normal file
216
vendor/texthooker-ui/src/components/Stats.svelte
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
combineLatest,
|
||||
debounceTime,
|
||||
fromEvent,
|
||||
interval,
|
||||
merge,
|
||||
NEVER,
|
||||
startWith,
|
||||
switchMap,
|
||||
tap,
|
||||
throttleTime,
|
||||
} from 'rxjs';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
import {
|
||||
adjustTimerOnAfk$,
|
||||
afkTimer$,
|
||||
blurStats$,
|
||||
characterMilestone$,
|
||||
enableAfkBlur$,
|
||||
enableAfkBlurRestart$,
|
||||
isPaused$,
|
||||
lineData$,
|
||||
milestoneLines$,
|
||||
newLine$,
|
||||
showCharacterCount$,
|
||||
showLineCount$,
|
||||
showSpeed$,
|
||||
showTimer$,
|
||||
timeValue$,
|
||||
} from '../stores/stores';
|
||||
import { reduceToEmptyString, toTimeString } from '../util';
|
||||
|
||||
let lastTick = 0;
|
||||
let idleTime = 0;
|
||||
|
||||
const dispatch = createEventDispatcher<{ afkBlur: boolean }>();
|
||||
|
||||
const isNotJapaneseRegex = /[^0-9A-Z○◯々-〇〻ぁ-ゖゝ-ゞァ-ヺー0-9A-Zヲ-ン\p{Radical}\p{Unified_Ideograph}]+/gimu;
|
||||
|
||||
const timer$ = isPaused$.pipe(
|
||||
switchMap((isPaused) => {
|
||||
if (isPaused) {
|
||||
idleTime = 0;
|
||||
|
||||
return NEVER;
|
||||
}
|
||||
|
||||
lastTick = performance.now();
|
||||
|
||||
return interval(1000);
|
||||
}),
|
||||
tap(updateElapsedTime),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
const waitForIdle$ = combineLatest([isPaused$, afkTimer$]).pipe(
|
||||
switchMap(([isPaused, afkTimer]) =>
|
||||
isPaused || afkTimer < 1
|
||||
? NEVER
|
||||
: merge(
|
||||
newLine$,
|
||||
fromEvent<PointerEvent>(window, 'pointermove'),
|
||||
fromEvent<Event>(document, 'selectionchange'),
|
||||
).pipe(
|
||||
startWith(true),
|
||||
throttleTime(1000),
|
||||
tap(() => (idleTime = performance.now() + $afkTimer$ * 1000)),
|
||||
debounceTime($afkTimer$ * 1000),
|
||||
),
|
||||
),
|
||||
reduceToEmptyString(),
|
||||
);
|
||||
|
||||
let timerElm: HTMLElement;
|
||||
let speed = 0;
|
||||
let characters = 0;
|
||||
let statstring = '';
|
||||
|
||||
$: if (($showCharacterCount$ || $characterMilestone$ > 1) && $lineData$) {
|
||||
const newMilestoneLines = new Map<string, string>();
|
||||
|
||||
let newCount = 0;
|
||||
let nextMilestone = $characterMilestone$ > 1 ? $characterMilestone$ : 0;
|
||||
|
||||
for (let index = 0, { length } = $lineData$; index < length; index += 1) {
|
||||
newCount += getCharacterCount($lineData$[index].text);
|
||||
|
||||
if (nextMilestone && newCount >= nextMilestone) {
|
||||
let currentCount = newCount;
|
||||
let achievedMilestone = nextMilestone;
|
||||
|
||||
newMilestoneLines.set($lineData$[index].id, `Milestone ${achievedMilestone} (${newCount})`);
|
||||
|
||||
while (currentCount >= nextMilestone) {
|
||||
nextMilestone += $characterMilestone$;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$milestoneLines$ = newMilestoneLines;
|
||||
|
||||
characters = newCount;
|
||||
speed = $timeValue$ ? Math.ceil((3600 * characters) / $timeValue$) : 0;
|
||||
}
|
||||
|
||||
$: if ($timeValue$ > -1 && ($showTimer$ || $showSpeed$ || $showCharacterCount$ || $showLineCount$)) {
|
||||
buildString($timeValue$, speed, characters, $lineData$.length);
|
||||
} else {
|
||||
statstring = '';
|
||||
}
|
||||
|
||||
function handlePointerLeave() {
|
||||
const selection = window.getSelection();
|
||||
|
||||
if (selection?.toString() && selection.getRangeAt(0).intersectsNode(timerElm)) {
|
||||
selection.removeAllRanges();
|
||||
}
|
||||
}
|
||||
|
||||
function updateElapsedTime() {
|
||||
const now = idleTime ? Math.min(idleTime, performance.now()) : performance.now();
|
||||
const elapsed = Math.round((now - lastTick + Number.EPSILON) / 1000);
|
||||
|
||||
if (idleTime && now >= idleTime) {
|
||||
$isPaused$ = true;
|
||||
|
||||
if ($adjustTimerOnAfk$) {
|
||||
$timeValue$ = Math.max(0, $timeValue$ + elapsed - $afkTimer$);
|
||||
} else {
|
||||
$timeValue$ += elapsed;
|
||||
}
|
||||
|
||||
if ($enableAfkBlur$) {
|
||||
dispatch('afkBlur', true);
|
||||
|
||||
document.addEventListener(
|
||||
'dblclick',
|
||||
(event) => {
|
||||
event.stopPropagation();
|
||||
|
||||
window.getSelection().removeAllRanges();
|
||||
|
||||
dispatch('afkBlur', false);
|
||||
|
||||
if ($enableAfkBlurRestart$) {
|
||||
$isPaused$ = false;
|
||||
}
|
||||
},
|
||||
{ once: true, capture: false },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
lastTick = now;
|
||||
$timeValue$ += elapsed;
|
||||
}
|
||||
}
|
||||
|
||||
function getCharacterCount(text: string) {
|
||||
if (!text) return 0;
|
||||
return countUnicodeCharacters(text.replace(isNotJapaneseRegex, ''));
|
||||
}
|
||||
|
||||
function countUnicodeCharacters(s: string) {
|
||||
return Array.from(s).length;
|
||||
}
|
||||
|
||||
function buildString(currentTime: number, currentSpeed: number, currentCharacters: number, currentLines: number) {
|
||||
let newString = '';
|
||||
|
||||
if ($showTimer$) {
|
||||
newString += toTimeString(currentTime);
|
||||
}
|
||||
|
||||
if ($showSpeed$) {
|
||||
newString += ` (${currentSpeed}/h) `;
|
||||
}
|
||||
|
||||
if ($showCharacterCount$) {
|
||||
newString += ` ${currentCharacters}`;
|
||||
}
|
||||
|
||||
if ($showLineCount$) {
|
||||
newString += $showCharacterCount$ ? ' /' : '';
|
||||
newString += ` ${currentLines}`;
|
||||
}
|
||||
|
||||
statstring = newString.replace(/[ ]+/g, ' ').trim();
|
||||
}
|
||||
</script>
|
||||
|
||||
{$timer$ ?? ''}
|
||||
{$waitForIdle$ ?? ''}
|
||||
|
||||
<div
|
||||
class="text-sm timer mr-1 sm:text-base sm:mr-2"
|
||||
class:blur={$blurStats$}
|
||||
bind:this={timerElm}
|
||||
on:pointerleave={handlePointerLeave}
|
||||
>
|
||||
<div>{statstring}</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.timer {
|
||||
transition: 0.1s filter linear;
|
||||
}
|
||||
|
||||
.blur:hover {
|
||||
filter: blur(0);
|
||||
}
|
||||
|
||||
.blur:not(:hover) {
|
||||
filter: blur(0.25rem);
|
||||
}
|
||||
</style>
|
||||
14
vendor/texthooker-ui/src/global.d.ts
vendored
Normal file
14
vendor/texthooker-ui/src/global.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
declare global {
|
||||
interface Window {
|
||||
documentPictureInPicture: {
|
||||
requestWindow: (arg?: {
|
||||
height?: number;
|
||||
width?: number;
|
||||
preferInitialWindowPlacement?: boolean;
|
||||
}) => Promise<Window | undefined>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export { };
|
||||
|
||||
9
vendor/texthooker-ui/src/main.ts
vendored
Normal file
9
vendor/texthooker-ui/src/main.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import './app.css';
|
||||
|
||||
import App from './components/App.svelte';
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
});
|
||||
|
||||
export default app;
|
||||
112
vendor/texthooker-ui/src/socket.ts
vendored
Normal file
112
vendor/texthooker-ui/src/socket.ts
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
import { BehaviorSubject, NEVER, Subscription, filter, switchMap } from 'rxjs';
|
||||
import {
|
||||
continuousReconnect$,
|
||||
newLine$,
|
||||
reconnectSecondarySocket$,
|
||||
reconnectSocket$,
|
||||
secondarySocketState$,
|
||||
secondaryWebsocketUrl$,
|
||||
socketState$,
|
||||
websocketUrl$,
|
||||
} from './stores/stores';
|
||||
|
||||
import { LineType } from './types';
|
||||
|
||||
export class SocketConnection {
|
||||
private websocketUrl: string;
|
||||
|
||||
private socket: WebSocket | undefined;
|
||||
|
||||
private socketState: BehaviorSubject<number>;
|
||||
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(isPrimary = true) {
|
||||
this.socketState = isPrimary ? socketState$ : secondarySocketState$;
|
||||
this.subscriptions.push(
|
||||
(isPrimary ? websocketUrl$ : secondaryWebsocketUrl$).subscribe((websocketUrl) => {
|
||||
if (websocketUrl !== this.websocketUrl) {
|
||||
this.websocketUrl = websocketUrl;
|
||||
this.reloadSocket();
|
||||
}
|
||||
}),
|
||||
continuousReconnect$
|
||||
.pipe(
|
||||
switchMap((continuousReconnect) =>
|
||||
continuousReconnect
|
||||
? (isPrimary ? reconnectSocket$ : reconnectSecondarySocket$).pipe(
|
||||
filter(() => this.socket?.readyState === 3)
|
||||
)
|
||||
: NEVER
|
||||
)
|
||||
)
|
||||
.subscribe(() => this.reloadSocket())
|
||||
);
|
||||
}
|
||||
|
||||
getCurrentUrl() {
|
||||
return this.websocketUrl;
|
||||
}
|
||||
|
||||
connect() {
|
||||
if (this.socket?.readyState < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.websocketUrl) {
|
||||
this.socketState.next(3);
|
||||
return;
|
||||
}
|
||||
|
||||
this.socketState.next(0);
|
||||
|
||||
try {
|
||||
this.socket = new WebSocket(this.websocketUrl);
|
||||
this.socket.onopen = this.updateSocketState.bind(this);
|
||||
this.socket.onclose = this.updateSocketState.bind(this);
|
||||
this.socket.onmessage = this.handleMessage.bind(this);
|
||||
} catch (error) {
|
||||
this.socketState.next(3);
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.socket?.readyState === 1) {
|
||||
this.socket.close(1000, 'User Request');
|
||||
}
|
||||
}
|
||||
|
||||
cleanUp() {
|
||||
this.disconnect();
|
||||
|
||||
for (let index = 0, { length } = this.subscriptions; index < length; index += 1) {
|
||||
this.subscriptions[index].unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private reloadSocket() {
|
||||
this.disconnect();
|
||||
this.socket = undefined;
|
||||
this.connect();
|
||||
}
|
||||
|
||||
private updateSocketState() {
|
||||
if (!this.socket) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.socketState.next(this.socket.readyState);
|
||||
}
|
||||
|
||||
private handleMessage(event: MessageEvent) {
|
||||
let line = event.data;
|
||||
|
||||
try {
|
||||
line = JSON.parse(event.data)?.sentence || event.data;
|
||||
} catch (_) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
newLine$.next([line, LineType.SOCKET]);
|
||||
}
|
||||
}
|
||||
369
vendor/texthooker-ui/src/stores/stores.ts
vendored
Normal file
369
vendor/texthooker-ui/src/stores/stores.ts
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
import {
|
||||
LineType,
|
||||
OnlineFont,
|
||||
Theme,
|
||||
type DialogResult,
|
||||
type LineItem,
|
||||
type ReplacementItem,
|
||||
type SettingPreset,
|
||||
type Settings,
|
||||
} from './../types';
|
||||
|
||||
import { mdiHelpCircle } from '@mdi/js';
|
||||
import { Subject } from 'rxjs';
|
||||
import { writable } from 'svelte/store';
|
||||
import { writableBooleanSubject } from './transformer/writeable-boolean-subject';
|
||||
import { writableNumberSubject } from './transformer/writeable-number-subject';
|
||||
import { writeableArraySubject } from './transformer/writeable-object-sibject';
|
||||
import { writableStringSubject } from './transformer/writeable-string-subject';
|
||||
import { writableSubject } from './transformer/writeable-subject';
|
||||
|
||||
export const defaultSettings: Settings = {
|
||||
theme$: Theme.BUSINESS,
|
||||
replacements$: [],
|
||||
windowTitle$: 'SubMiner Texthooker',
|
||||
websocketUrl$: 'ws://localhost:6677',
|
||||
secondaryWebsocketUrl$: '',
|
||||
fontSize$: 24,
|
||||
characterMilestone$: 0,
|
||||
onlineFont$: OnlineFont.OFF,
|
||||
preventLastDuplicate$: 0,
|
||||
maxLines$: 0,
|
||||
maxPipLines$: 1,
|
||||
afkTimer$: 0,
|
||||
adjustTimerOnAfk$: false,
|
||||
enableExternalClipboardMonitor$: false,
|
||||
showPresetQuickSwitch$: false,
|
||||
skipResetConfirmations$: false,
|
||||
persistStats$: true,
|
||||
persistNotes$: true,
|
||||
persistLines$: true,
|
||||
persistActionHistory$: false,
|
||||
enablePaste$: false,
|
||||
blockCopyOnPage$: false,
|
||||
allowPasteDuringPause$: false,
|
||||
allowNewLineDuringPause$: false,
|
||||
autoStartTimerDuringPausePaste$: false,
|
||||
autoStartTimerDuringPause$: false,
|
||||
preventGlobalDuplicate$: false,
|
||||
mergeEqualLineStarts$: false,
|
||||
filterNonCJKLines: false,
|
||||
flashOnMissedLine$: true,
|
||||
displayVertical$: false,
|
||||
reverseLineOrder$: false,
|
||||
preserveWhitespace$: false,
|
||||
removeAllWhitespace$: true,
|
||||
showTimer$: true,
|
||||
showSpeed$: true,
|
||||
showCharacterCount$: true,
|
||||
showLineCount$: true,
|
||||
blurStats$: false,
|
||||
enableLineAnimation$: true,
|
||||
enableAfkBlur$: false,
|
||||
enableAfkBlurRestart$: false,
|
||||
continuousReconnect$: true,
|
||||
showConnectionErrors$: true,
|
||||
showConnectionIcon$: true,
|
||||
customCSS$: '',
|
||||
};
|
||||
|
||||
export const theme$ = writableStringSubject()('bannou-texthooker-theme', defaultSettings.theme$);
|
||||
|
||||
export const settingPresets$ = writeableArraySubject<SettingPreset>()('bannou-texthooker-settingPresets', []);
|
||||
|
||||
export const replacements$ = writeableArraySubject<ReplacementItem>()('bannou-texthooker-replacements', []);
|
||||
|
||||
export const windowTitle$ = writableStringSubject()('bannou-texthooker-windowTitle', defaultSettings.windowTitle$);
|
||||
|
||||
export const websocketUrl$ = writableStringSubject()('bannou-texthooker-websocketUrl', defaultSettings.websocketUrl$);
|
||||
|
||||
export const secondaryWebsocketUrl$ = writableStringSubject()(
|
||||
'bannou-texthooker-secondary-websocketUrl',
|
||||
defaultSettings.secondaryWebsocketUrl$
|
||||
);
|
||||
|
||||
export const fontSize$ = writableNumberSubject()('bannou-texthooker-fontSize', defaultSettings.fontSize$);
|
||||
|
||||
export const characterMilestone$ = writableNumberSubject()(
|
||||
'bannou-texthooker-characterMilestone',
|
||||
defaultSettings.characterMilestone$
|
||||
);
|
||||
|
||||
export const onlineFont$ = writableStringSubject()('bannou-texthooker-onlineFont', defaultSettings.onlineFont$);
|
||||
|
||||
export const preventLastDuplicate$ = writableNumberSubject()(
|
||||
'bannou-texthooker-preventLastDuplicate',
|
||||
defaultSettings.preventLastDuplicate$
|
||||
);
|
||||
|
||||
export const maxLines$ = writableNumberSubject()('bannou-texthooker-maxLines', defaultSettings.maxLines$);
|
||||
|
||||
export const maxPipLines$ = writableNumberSubject()('bannou-texthooker-maxPipLines', defaultSettings.maxPipLines$);
|
||||
|
||||
export const afkTimer$ = writableNumberSubject()('bannou-texthooker-afkTimer', defaultSettings.afkTimer$);
|
||||
|
||||
export const adjustTimerOnAfk$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-adjustTimerOnAfk',
|
||||
defaultSettings.adjustTimerOnAfk$
|
||||
);
|
||||
|
||||
export const enableExternalClipboardMonitor$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-enableExternalClipboardMonitor',
|
||||
defaultSettings.enableExternalClipboardMonitor$
|
||||
);
|
||||
|
||||
export const showPresetQuickSwitch$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-showPresetQuickSwitch',
|
||||
defaultSettings.showPresetQuickSwitch$
|
||||
);
|
||||
|
||||
export const skipResetConfirmations$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-skipResetConfirmations',
|
||||
defaultSettings.skipResetConfirmations$
|
||||
);
|
||||
|
||||
export const persistStats$ = writableBooleanSubject()('bannou-texthooker-persistStats', defaultSettings.persistStats$);
|
||||
|
||||
export const persistNotes$ = writableBooleanSubject()('bannou-texthooker-persistNotes', defaultSettings.persistNotes$);
|
||||
|
||||
export const persistLines$ = writableBooleanSubject()('bannou-texthooker-persistLines', defaultSettings.persistLines$);
|
||||
|
||||
export const persistActionHistory$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-persistActionHistory',
|
||||
defaultSettings.persistActionHistory$
|
||||
);
|
||||
|
||||
export const enablePaste$ = writableBooleanSubject()('bannou-texthooker-enablePaste', defaultSettings.enablePaste$);
|
||||
|
||||
export const blockCopyOnPage$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-blockCopyOnPage',
|
||||
defaultSettings.blockCopyOnPage$
|
||||
);
|
||||
|
||||
export const allowPasteDuringPause$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-allowPasteDuringPause',
|
||||
defaultSettings.allowPasteDuringPause$
|
||||
);
|
||||
|
||||
export const allowNewLineDuringPause$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-allowNewLineDuringPause',
|
||||
defaultSettings.allowNewLineDuringPause$
|
||||
);
|
||||
|
||||
export const autoStartTimerDuringPausePaste$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-autoStartTimerDuringPausePaste',
|
||||
defaultSettings.autoStartTimerDuringPausePaste$
|
||||
);
|
||||
|
||||
export const autoStartTimerDuringPause$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-autoStartTimerDuringPause',
|
||||
defaultSettings.autoStartTimerDuringPause$
|
||||
);
|
||||
|
||||
export const preventGlobalDuplicate$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-preventGlobalDuplicate',
|
||||
defaultSettings.preventGlobalDuplicate$
|
||||
);
|
||||
|
||||
export const mergeEqualLineStarts$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-mergeEqualLineStarts',
|
||||
defaultSettings.mergeEqualLineStarts$
|
||||
);
|
||||
|
||||
export const filterNonCJKLines$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-filterNonCJKLines',
|
||||
defaultSettings.mergeEqualLineStarts$
|
||||
);
|
||||
|
||||
export const flashOnMissedLine$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-flashOnMissedLine',
|
||||
defaultSettings.flashOnMissedLine$
|
||||
);
|
||||
|
||||
export const displayVertical$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-displayVertical',
|
||||
defaultSettings.displayVertical$
|
||||
);
|
||||
|
||||
export const reverseLineOrder$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-reverseLineOrder',
|
||||
defaultSettings.reverseLineOrder$
|
||||
);
|
||||
|
||||
export const preserveWhitespace$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-preserveWhitespace',
|
||||
defaultSettings.preserveWhitespace$
|
||||
);
|
||||
|
||||
export const removeAllWhitespace$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-removeAllWhitespace',
|
||||
defaultSettings.removeAllWhitespace$
|
||||
);
|
||||
|
||||
export const showTimer$ = writableBooleanSubject()('bannou-texthooker-showTimer', defaultSettings.showTimer$);
|
||||
|
||||
export const showSpeed$ = writableBooleanSubject()('bannou-texthooker-showSpeed', defaultSettings.showSpeed$);
|
||||
|
||||
export const showCharacterCount$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-showCharacterCount',
|
||||
defaultSettings.showCharacterCount$
|
||||
);
|
||||
|
||||
export const showLineCount$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-showLineCount',
|
||||
defaultSettings.showLineCount$
|
||||
);
|
||||
|
||||
export const blurStats$ = writableBooleanSubject()('bannou-texthooker-blurStats', defaultSettings.blurStats$);
|
||||
|
||||
export const enableLineAnimation$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-enableLineAnimation',
|
||||
defaultSettings.enableLineAnimation$
|
||||
);
|
||||
|
||||
export const enableAfkBlur$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-enableAfkBlur',
|
||||
defaultSettings.enableAfkBlur$
|
||||
);
|
||||
|
||||
export const enableAfkBlurRestart$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-enableAfkBlurRestart',
|
||||
defaultSettings.enableAfkBlurRestart$
|
||||
);
|
||||
|
||||
export const continuousReconnect$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-continuousReconnect',
|
||||
defaultSettings.continuousReconnect$
|
||||
);
|
||||
|
||||
export const showConnectionErrors$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-showConnectionErrors',
|
||||
defaultSettings.showConnectionErrors$
|
||||
);
|
||||
|
||||
export const showConnectionIcon$ = writableBooleanSubject()(
|
||||
'bannou-texthooker-showConnectionIcon',
|
||||
defaultSettings.showConnectionIcon$
|
||||
);
|
||||
|
||||
export const customCSS$ = writableStringSubject()('bannou-texthooker-customCSS', defaultSettings.customCSS$);
|
||||
|
||||
export const timeValue$ = writableNumberSubject()('bannou-texthooker-timeValue', 0, persistStats$);
|
||||
|
||||
export const notesOpen$ = writableBooleanSubject()('bannou-texthooker-notesOpen', false);
|
||||
|
||||
export const userNotes$ = writableStringSubject()('bannou-texthooker-userNotes', '', persistNotes$);
|
||||
|
||||
export const socketState$ = writableSubject<number>(-1);
|
||||
|
||||
export const secondarySocketState$ = writableSubject<number>(-1);
|
||||
|
||||
export const openDialog$ = writableSubject<Record<string, any>>(undefined);
|
||||
|
||||
export const dialogOpen$ = writableSubject<boolean>(false);
|
||||
|
||||
export const lastSettingPreset$ = writableStringSubject()('bannou-texthooker-lastSettingPreset', '');
|
||||
|
||||
export const lineData$ = writeableArraySubject<LineItem>()('bannou-texthooker-lineData', [], persistLines$);
|
||||
|
||||
export const milestoneLines$ = writable<Map<string, string>>(new Map<string, string>());
|
||||
|
||||
export const actionHistory$ = writeableArraySubject<LineItem[]>()(
|
||||
'bannou-texthooker-actionHistory',
|
||||
[],
|
||||
persistActionHistory$
|
||||
);
|
||||
|
||||
export const flashOnPauseTimeout$ = writable<number>(undefined);
|
||||
|
||||
export const isPaused$ = writableSubject<boolean>(true);
|
||||
|
||||
export const newLine$ = new Subject<[string, LineType]>();
|
||||
|
||||
export const reconnectSocket$ = new Subject<void>();
|
||||
|
||||
export const reconnectSecondarySocket$ = new Subject<void>();
|
||||
|
||||
export const showSpinner$ = writable<boolean>(false);
|
||||
|
||||
export const enabledReplacements$ = writable<ReplacementItem[]>([]);
|
||||
|
||||
export const lastPipHeight$ = writableNumberSubject()('bannou-texthooker-lastPipHeight', 0);
|
||||
|
||||
export const lastPipWidth$ = writableNumberSubject()('bannou-texthooker-lastPipWidth', 0);
|
||||
|
||||
export async function resetAllData() {
|
||||
if (!skipResetConfirmations$.getValue()) {
|
||||
const { canceled } = await new Promise<DialogResult>((resolve) => {
|
||||
openDialog$.next({
|
||||
icon: mdiHelpCircle,
|
||||
message: 'All Settings and Data will be reset',
|
||||
callback: resolve,
|
||||
});
|
||||
});
|
||||
|
||||
if (canceled) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
lastSettingPreset$.next('');
|
||||
settingPresets$.next([]);
|
||||
isPaused$.next(true);
|
||||
timeValue$.next(0);
|
||||
userNotes$.next('');
|
||||
lineData$.next([]);
|
||||
actionHistory$.next([]);
|
||||
flashOnPauseTimeout$.set(undefined);
|
||||
|
||||
window.localStorage.removeItem('bannou-texthooker-timeValue');
|
||||
window.localStorage.removeItem('bannou-texthooker-userNotes');
|
||||
window.localStorage.removeItem('bannou-texthooker-lineData');
|
||||
window.localStorage.removeItem('bannou-texthooker-actionHistory');
|
||||
|
||||
theme$.next(defaultSettings.theme$);
|
||||
replacements$.next(defaultSettings.replacements$);
|
||||
windowTitle$.next(defaultSettings.windowTitle$);
|
||||
websocketUrl$.next(defaultSettings.websocketUrl$);
|
||||
secondaryWebsocketUrl$.next(defaultSettings.secondaryWebsocketUrl$);
|
||||
fontSize$.next(defaultSettings.fontSize$);
|
||||
characterMilestone$.next(defaultSettings.characterMilestone$);
|
||||
onlineFont$.next(defaultSettings.onlineFont$);
|
||||
preventLastDuplicate$.next(defaultSettings.preventLastDuplicate$);
|
||||
maxPipLines$.next(defaultSettings.maxPipLines$);
|
||||
afkTimer$.next(defaultSettings.afkTimer$);
|
||||
adjustTimerOnAfk$.next(defaultSettings.adjustTimerOnAfk$);
|
||||
enableExternalClipboardMonitor$.next(defaultSettings.enableExternalClipboardMonitor$);
|
||||
showPresetQuickSwitch$.next(defaultSettings.showPresetQuickSwitch$);
|
||||
skipResetConfirmations$.next(defaultSettings.skipResetConfirmations$);
|
||||
persistStats$.next(defaultSettings.persistStats$);
|
||||
persistNotes$.next(defaultSettings.persistNotes$);
|
||||
persistLines$.next(defaultSettings.persistLines$);
|
||||
persistActionHistory$.next(defaultSettings.persistActionHistory$);
|
||||
enablePaste$.next(defaultSettings.enablePaste$);
|
||||
blockCopyOnPage$.next(defaultSettings.blockCopyOnPage$);
|
||||
allowPasteDuringPause$.next(defaultSettings.allowPasteDuringPause$);
|
||||
allowNewLineDuringPause$.next(defaultSettings.allowNewLineDuringPause$);
|
||||
autoStartTimerDuringPausePaste$.next(defaultSettings.autoStartTimerDuringPausePaste$);
|
||||
autoStartTimerDuringPause$.next(defaultSettings.autoStartTimerDuringPause$);
|
||||
preventGlobalDuplicate$.next(defaultSettings.preventGlobalDuplicate$);
|
||||
mergeEqualLineStarts$.next(defaultSettings.mergeEqualLineStarts$);
|
||||
filterNonCJKLines$.next(defaultSettings.filterNonCJKLines);
|
||||
flashOnMissedLine$.next(defaultSettings.flashOnMissedLine$);
|
||||
displayVertical$.next(defaultSettings.displayVertical$);
|
||||
reverseLineOrder$.next(defaultSettings.reverseLineOrder$);
|
||||
preserveWhitespace$.next(defaultSettings.preserveWhitespace$);
|
||||
removeAllWhitespace$.next(defaultSettings.removeAllWhitespace$);
|
||||
showTimer$.next(defaultSettings.showTimer$);
|
||||
showSpeed$.next(defaultSettings.showSpeed$);
|
||||
showCharacterCount$.next(defaultSettings.showCharacterCount$);
|
||||
showLineCount$.next(defaultSettings.showLineCount$);
|
||||
blurStats$.next(defaultSettings.blurStats$);
|
||||
enableLineAnimation$.next(defaultSettings.enableLineAnimation$);
|
||||
enableAfkBlur$.next(defaultSettings.enableAfkBlur$);
|
||||
enableAfkBlurRestart$.next(defaultSettings.enableAfkBlurRestart$);
|
||||
continuousReconnect$.next(defaultSettings.continuousReconnect$);
|
||||
showConnectionErrors$.next(defaultSettings.showConnectionErrors$);
|
||||
showConnectionIcon$.next(defaultSettings.showConnectionIcon$);
|
||||
customCSS$.next(defaultSettings.customCSS$);
|
||||
}
|
||||
7
vendor/texthooker-ui/src/stores/transformer/subject-to-writeable.ts
vendored
Normal file
7
vendor/texthooker-ui/src/stores/transformer/subject-to-writeable.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Subject } from 'rxjs';
|
||||
|
||||
export function subjectToSvelteWritable<S extends Subject<any>>(subject: S) {
|
||||
// @ts-expect-error Svelte uses `set` like `next`
|
||||
subject.set = subject.next;
|
||||
return subject;
|
||||
}
|
||||
30
vendor/texthooker-ui/src/stores/transformer/writable-storage-subject.ts
vendored
Normal file
30
vendor/texthooker-ui/src/stores/transformer/writable-storage-subject.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
import { BehaviorSubject, skip } from 'rxjs';
|
||||
|
||||
import { writableSubject } from './writeable-subject';
|
||||
|
||||
export function writableStorageSubject<T>(mapFromString: (s: string) => T, mapToString: (t: T) => string) {
|
||||
return (key: string, defaultValue: T, persistenceBehavior?: BehaviorSubject<boolean>) => {
|
||||
const initValue = getStoredOrDefault()(key, defaultValue, mapFromString);
|
||||
const subject = writableSubject(initValue);
|
||||
|
||||
let persist = true;
|
||||
|
||||
if (persistenceBehavior) {
|
||||
persistenceBehavior.subscribe((shallPersist) => (persist = shallPersist));
|
||||
}
|
||||
|
||||
subject.pipe(skip(1)).subscribe((updatedValue) => {
|
||||
if (persist) {
|
||||
window.localStorage.setItem(key, mapToString(updatedValue ?? defaultValue));
|
||||
}
|
||||
});
|
||||
return subject;
|
||||
};
|
||||
}
|
||||
|
||||
function getStoredOrDefault() {
|
||||
return <T>(key: string, defaultVal: T, mapFn: (s: string) => T) => {
|
||||
const stored = window.localStorage.getItem(key);
|
||||
return stored ? mapFn(stored) : defaultVal;
|
||||
};
|
||||
}
|
||||
8
vendor/texthooker-ui/src/stores/transformer/writeable-boolean-subject.ts
vendored
Normal file
8
vendor/texthooker-ui/src/stores/transformer/writeable-boolean-subject.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { writableStorageSubject } from './writable-storage-subject';
|
||||
|
||||
export function writableBooleanSubject() {
|
||||
return writableStorageSubject(
|
||||
(x) => !!+x,
|
||||
(x) => (x ? '1' : '0')
|
||||
);
|
||||
}
|
||||
8
vendor/texthooker-ui/src/stores/transformer/writeable-number-subject.ts
vendored
Normal file
8
vendor/texthooker-ui/src/stores/transformer/writeable-number-subject.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { writableStorageSubject } from './writable-storage-subject';
|
||||
|
||||
export function writableNumberSubject() {
|
||||
return writableStorageSubject<number>(
|
||||
(x) => +x,
|
||||
(x) => `${x}`
|
||||
);
|
||||
}
|
||||
16
vendor/texthooker-ui/src/stores/transformer/writeable-object-sibject.ts
vendored
Normal file
16
vendor/texthooker-ui/src/stores/transformer/writeable-object-sibject.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { writableStorageSubject } from './writable-storage-subject';
|
||||
|
||||
function createwritteableObjectSubject<T>(fallback: string) {
|
||||
return writableStorageSubject(
|
||||
(x) => JSON.parse(x || fallback) as T,
|
||||
(x) => JSON.stringify(x)
|
||||
);
|
||||
}
|
||||
|
||||
export function writeableObjectSubject<T>() {
|
||||
return createwritteableObjectSubject<T>('{}');
|
||||
}
|
||||
|
||||
export function writeableArraySubject<T>() {
|
||||
return createwritteableObjectSubject<T[]>('[]');
|
||||
}
|
||||
8
vendor/texthooker-ui/src/stores/transformer/writeable-string-subject.ts
vendored
Normal file
8
vendor/texthooker-ui/src/stores/transformer/writeable-string-subject.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { writableStorageSubject } from './writable-storage-subject';
|
||||
|
||||
export function writableStringSubject<T extends string>() {
|
||||
return writableStorageSubject(
|
||||
(x) => x as T,
|
||||
(x) => x
|
||||
);
|
||||
}
|
||||
6
vendor/texthooker-ui/src/stores/transformer/writeable-subject.ts
vendored
Normal file
6
vendor/texthooker-ui/src/stores/transformer/writeable-subject.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { subjectToSvelteWritable } from './subject-to-writeable';
|
||||
|
||||
export function writableSubject<T>(value: T) {
|
||||
return subjectToSvelteWritable(new BehaviorSubject<T>(value));
|
||||
}
|
||||
145
vendor/texthooker-ui/src/types.ts
vendored
Normal file
145
vendor/texthooker-ui/src/types.ts
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
export enum Theme {
|
||||
LIGHT = 'light',
|
||||
DARK = 'dark',
|
||||
CUPCAKE = 'cupcake',
|
||||
BUMBLEBEE = 'bumblebee',
|
||||
EMERALD = 'emerald',
|
||||
CORPORATE = 'corporate',
|
||||
SYNTHWAVE = 'synthwave',
|
||||
RETRO = 'retro',
|
||||
CYBERPUNK = 'cyberpunk',
|
||||
VALENTINE = 'valentine',
|
||||
HALLOWEEN = 'halloween',
|
||||
GARDEN = 'garden',
|
||||
FOREST = 'forest',
|
||||
AQUA = 'aqua',
|
||||
LOFI = 'lofi',
|
||||
PASTEL = 'pastel',
|
||||
FANTASY = 'fantasy',
|
||||
WIREFRAME = 'wireframe',
|
||||
BLACK = 'black',
|
||||
LUXURY = 'luxury',
|
||||
DRACULA = 'dracula',
|
||||
CMYK = 'cmyk',
|
||||
AUTUMN = 'autumn',
|
||||
BUSINESS = 'business',
|
||||
ACID = 'acid',
|
||||
LEMONADE = 'lemonade',
|
||||
NIGHT = 'night',
|
||||
COFFEE = 'coffee',
|
||||
WINTER = 'winter',
|
||||
}
|
||||
|
||||
export enum OnlineFont {
|
||||
OFF = 'Off',
|
||||
NOTO = 'Noto Serif JP',
|
||||
KLEE = 'Klee One',
|
||||
SHIPPORI = 'Shippori Mincho',
|
||||
ACKAISYO = 'Ackaisyo',
|
||||
CINECAPTION226 = 'CineCaption226',
|
||||
}
|
||||
|
||||
export interface Settings {
|
||||
theme$: string;
|
||||
replacements$: ReplacementItem[];
|
||||
windowTitle$: string;
|
||||
websocketUrl$: string;
|
||||
secondaryWebsocketUrl$: string;
|
||||
fontSize$: number;
|
||||
characterMilestone$: number;
|
||||
onlineFont$: string;
|
||||
preventLastDuplicate$: number;
|
||||
maxLines$: number;
|
||||
maxPipLines$: number;
|
||||
afkTimer$: number;
|
||||
adjustTimerOnAfk$: boolean;
|
||||
enableExternalClipboardMonitor$: boolean;
|
||||
showPresetQuickSwitch$: boolean;
|
||||
skipResetConfirmations$: boolean;
|
||||
persistStats$: boolean;
|
||||
persistNotes$: boolean;
|
||||
persistLines$: boolean;
|
||||
persistActionHistory$: boolean;
|
||||
enablePaste$: boolean;
|
||||
blockCopyOnPage$: boolean;
|
||||
allowPasteDuringPause$: boolean;
|
||||
allowNewLineDuringPause$: boolean;
|
||||
autoStartTimerDuringPausePaste$: boolean;
|
||||
autoStartTimerDuringPause$: boolean;
|
||||
preventGlobalDuplicate$: boolean;
|
||||
mergeEqualLineStarts$: boolean;
|
||||
filterNonCJKLines: boolean;
|
||||
flashOnMissedLine$: boolean;
|
||||
displayVertical$: boolean;
|
||||
reverseLineOrder$: boolean;
|
||||
preserveWhitespace$: boolean;
|
||||
removeAllWhitespace$: boolean;
|
||||
showTimer$: boolean;
|
||||
showSpeed$: boolean;
|
||||
showCharacterCount$: boolean;
|
||||
showLineCount$: boolean;
|
||||
blurStats$: boolean;
|
||||
enableLineAnimation$: boolean;
|
||||
enableAfkBlur$: boolean;
|
||||
enableAfkBlurRestart$: boolean;
|
||||
continuousReconnect$: boolean;
|
||||
showConnectionErrors$: boolean;
|
||||
showConnectionIcon$: boolean;
|
||||
customCSS$: string;
|
||||
}
|
||||
|
||||
export interface ExportedData {
|
||||
'bannou-texthooker-timeValue': number;
|
||||
'bannou-texthooker-userNotes': string;
|
||||
'bannou-texthooker-lineData': LineItem[];
|
||||
'bannou-texthooker-actionHistory': LineItem[][];
|
||||
}
|
||||
|
||||
export interface ExportedSettings {
|
||||
currentSettings: Settings;
|
||||
settingPresets: SettingPreset[];
|
||||
lastSettingsPreset: string;
|
||||
}
|
||||
|
||||
export interface ReplacementItem {
|
||||
pattern: string;
|
||||
replaces: string;
|
||||
flags: string[];
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
export interface SettingPreset {
|
||||
name: string;
|
||||
settings: Settings;
|
||||
}
|
||||
|
||||
export interface DialogResult<T = undefined> {
|
||||
canceled: boolean;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export enum LineType {
|
||||
SOCKET = 'socket',
|
||||
PASTE = 'paste',
|
||||
EXTERNAL = 'external',
|
||||
EDIT = 'edit',
|
||||
UNDO = 'undo',
|
||||
}
|
||||
|
||||
export interface LineItem {
|
||||
id: string;
|
||||
text: string;
|
||||
index?: number;
|
||||
}
|
||||
|
||||
export interface LineItemEditEvent {
|
||||
inEdit: boolean;
|
||||
data?: LineItemEditData;
|
||||
}
|
||||
|
||||
export interface LineItemEditData {
|
||||
originalText: string;
|
||||
newText: string;
|
||||
lineIndex: number;
|
||||
line: LineItem;
|
||||
}
|
||||
15
vendor/texthooker-ui/src/use-click-outside.ts
vendored
Normal file
15
vendor/texthooker-ui/src/use-click-outside.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
export function clickOutside(node: Node, listener: (ev: MouseEvent) => void) {
|
||||
const handler = (ev: MouseEvent) => {
|
||||
if (!ev.defaultPrevented && !node.contains(ev.target as Node)) {
|
||||
listener(ev);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('click', handler, true);
|
||||
|
||||
return {
|
||||
destroy() {
|
||||
document.removeEventListener('click', handler, true);
|
||||
},
|
||||
};
|
||||
}
|
||||
119
vendor/texthooker-ui/src/util.ts
vendored
Normal file
119
vendor/texthooker-ui/src/util.ts
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
import { filter, map, pipe } from 'rxjs';
|
||||
|
||||
import type { ReplacementItem } from './types';
|
||||
|
||||
export function dummyFn() {}
|
||||
|
||||
export function reduceToEmptyString() {
|
||||
return pipe(
|
||||
map((): '' => ''),
|
||||
filter((_, index) => !index)
|
||||
);
|
||||
}
|
||||
|
||||
export function updateScroll(
|
||||
window: Window,
|
||||
scrollElement: HTMLElement,
|
||||
reverseLineOrder: boolean,
|
||||
displayVertical: boolean,
|
||||
behavior: ScrollBehavior = 'auto'
|
||||
) {
|
||||
if (!scrollElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (reverseLineOrder) {
|
||||
if (displayVertical) {
|
||||
scrollElement.scrollTo({ top: 0, left: scrollElement.scrollWidth, behavior });
|
||||
} else {
|
||||
window.scrollTo({ top: -scrollElement.scrollHeight, left: 0, behavior });
|
||||
}
|
||||
} else if (displayVertical) {
|
||||
scrollElement.scrollTo({ top: 0, left: -scrollElement.scrollWidth, behavior });
|
||||
} else {
|
||||
window.scrollTo({ top: scrollElement.scrollHeight + 100, left: 0, behavior });
|
||||
}
|
||||
if (behavior === 'smooth') {
|
||||
setTimeout(() => updateScroll(window, scrollElement, reverseLineOrder, displayVertical), 250);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function toTimeString(s: number) {
|
||||
const hours = Math.floor(s / 3600);
|
||||
const minutes = Math.floor((s - hours * 3600) / 60);
|
||||
const seconds = s - hours * 3600 - minutes * 60;
|
||||
|
||||
return `${`${hours}`.padStart(2, '0')}:${`${minutes}`.padStart(2, '0')}:${`${seconds}`.padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
export function timeStringToSeconds(timeString: string) {
|
||||
const [hours, minutes, seconds] = timeString.split(':').map((part) => Number.parseInt(part, 10));
|
||||
|
||||
return hours * 60 * 60 + minutes * 60 + seconds;
|
||||
}
|
||||
|
||||
export function generateRandomUUID() {
|
||||
const bytes = new Uint8Array(16);
|
||||
|
||||
crypto.getRandomValues(bytes);
|
||||
|
||||
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
||||
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
||||
|
||||
const uuid = Array.prototype.map
|
||||
.call(bytes, (b: number, i: number) => {
|
||||
return (b < 16 ? '0' : '') + b.toString(16) + (i % 2 && i < 10 && i > 2 ? '-' : '');
|
||||
})
|
||||
.join('');
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
export function applyReplacements(originalText: string, replacements: ReplacementItem[]) {
|
||||
if (!originalText || !replacements.length) {
|
||||
return originalText;
|
||||
}
|
||||
|
||||
let adjustedText = originalText;
|
||||
|
||||
for (let index = 0, { length } = replacements; index < length; index += 1) {
|
||||
const replacement = replacements[index];
|
||||
|
||||
adjustedText = adjustedText.replace(
|
||||
new RegExp(replacement.pattern, replacement.flags.join('')),
|
||||
replacement.replaces.replace(/\\t/gm, '\t').replace(/\\n/gm, '\n')
|
||||
);
|
||||
}
|
||||
|
||||
return adjustedText;
|
||||
}
|
||||
|
||||
export function applyCustomCSS(document: Document, customCSS: string) {
|
||||
const textNode = document.createTextNode(customCSS || '');
|
||||
|
||||
let styleElement = document.getElementById('user-css');
|
||||
|
||||
if (styleElement) {
|
||||
styleElement.replaceChild(textNode, styleElement.firstChild);
|
||||
} else {
|
||||
styleElement = document.createElement('style');
|
||||
styleElement.id = 'user-css';
|
||||
|
||||
styleElement.appendChild(textNode);
|
||||
document.head.append(styleElement);
|
||||
}
|
||||
}
|
||||
|
||||
export function applyAfkBlur(document: Document, isAfk: boolean) {
|
||||
if (isAfk) {
|
||||
document.body.style.filter = 'blur(8px)';
|
||||
document.body.style.pointerEvents = 'none';
|
||||
} else {
|
||||
document.body.style.filter = null;
|
||||
document.body.style.pointerEvents = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
export const newLineCharacter = '\n';
|
||||
2
vendor/texthooker-ui/src/vite-env.d.ts
vendored
Normal file
2
vendor/texthooker-ui/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference types="svelte" />
|
||||
/// <reference types="vite/client" />
|
||||
5
vendor/texthooker-ui/svelte.config.js
vendored
Normal file
5
vendor/texthooker-ui/svelte.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import sveltePreprocess from 'svelte-preprocess';
|
||||
|
||||
export default {
|
||||
preprocess: sveltePreprocess(),
|
||||
};
|
||||
7
vendor/texthooker-ui/tailwind.config.cjs
vendored
Normal file
7
vendor/texthooker-ui/tailwind.config.cjs
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
content: ['./src/components/*.{svelte,js,ts}'],
|
||||
plugins: [require('daisyui')],
|
||||
daisyui: {
|
||||
themes: ['garden', 'business'],
|
||||
},
|
||||
};
|
||||
14
vendor/texthooker-ui/tsconfig.json
vendored
Normal file
14
vendor/texthooker-ui/tsconfig.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"resolveJsonModule": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"isolatedModules": true
|
||||
},
|
||||
"include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
8
vendor/texthooker-ui/tsconfig.node.json
vendored
Normal file
8
vendor/texthooker-ui/tsconfig.node.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node"
|
||||
},
|
||||
"include": ["vite.lib.config.ts", "vite.main.config.ts"]
|
||||
}
|
||||
22
vendor/texthooker-ui/vite.lib.config.ts
vendored
Normal file
22
vendor/texthooker-ui/vite.lib.config.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
import { setDefaultResultOrder } from 'dns';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
const nodeVersion = Number.parseInt(process.versions.node.match(/^(\d+)\./)?.[1] || '17', 10);
|
||||
|
||||
if (nodeVersion < 17) {
|
||||
setDefaultResultOrder('verbatim');
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
base: '',
|
||||
build: {
|
||||
emptyOutDir: true,
|
||||
lib: { name: 'texthooker', entry: './src/main.ts', formats: ['iife'] },
|
||||
outDir: './texthooker-ui',
|
||||
},
|
||||
server: {
|
||||
port: 5174,
|
||||
},
|
||||
});
|
||||
44
vendor/texthooker-ui/vite.main.config.ts
vendored
Normal file
44
vendor/texthooker-ui/vite.main.config.ts
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||
import { setDefaultResultOrder } from 'dns';
|
||||
import { cpSync } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { defineConfig } from 'vite';
|
||||
import { viteSingleFile } from 'vite-plugin-singlefile';
|
||||
|
||||
const nodeVersion = Number.parseInt(process.versions.node.match(/^(\d+)\./)?.[1] || '17', 10);
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
if (nodeVersion < 17) {
|
||||
setDefaultResultOrder('verbatim');
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
svelte(),
|
||||
viteSingleFile(),
|
||||
(() => {
|
||||
{
|
||||
return {
|
||||
name: 'copy-header',
|
||||
writeBundle() {
|
||||
cpSync(join(__dirname, 'public', 'assets'), join(__dirname, 'docs', 'assets'), {
|
||||
recursive: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
})(),
|
||||
],
|
||||
base: '/texthooker-ui',
|
||||
build: {
|
||||
copyPublicDir: false,
|
||||
emptyOutDir: true,
|
||||
outDir: './docs',
|
||||
},
|
||||
server: {
|
||||
port: 5174,
|
||||
},
|
||||
});
|
||||
64
vendor/yomitan/action-popup.html
vendored
Normal file
64
vendor/yomitan/action-popup.html
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Yomitan Action Popup</title>
|
||||
<link rel="icon" type="image/png" href="/images/icon16.png" sizes="16x16">
|
||||
<link rel="icon" type="image/png" href="/images/icon19.png" sizes="19x19">
|
||||
<link rel="icon" type="image/png" href="/images/icon32.png" sizes="32x32">
|
||||
<link rel="icon" type="image/png" href="/images/icon38.png" sizes="38x38">
|
||||
<link rel="icon" type="image/png" href="/images/icon48.png" sizes="48x48">
|
||||
<link rel="icon" type="image/png" href="/images/icon64.png" sizes="64x64">
|
||||
<link rel="icon" type="image/png" href="/images/icon128.png" sizes="128x128">
|
||||
<link rel="stylesheet" type="text/css" href="/css/material.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/action-popup.css">
|
||||
<script src="/js/pages/action-popup-main.js" type="module"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading">
|
||||
Loading...
|
||||
</div>
|
||||
<div id="action-popup">
|
||||
<div class="action-container action-select-profile" hidden>
|
||||
<div class="action-item-left">
|
||||
<h2 class="action-title">Profile</h2>
|
||||
</div>
|
||||
<div class="action-item-right">
|
||||
<select tabindex="0" class="profile-select" id="profile-select">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-container">
|
||||
<div class="action-item-center">
|
||||
<label class="toggle">
|
||||
<input tabindex="0" type="checkbox" class="enable-search">
|
||||
<div class="toggle-group">
|
||||
<span class="toggle-on">On</span>
|
||||
<span class="toggle-off">Off</span>
|
||||
<span class="toggle-handle"></span>
|
||||
</div>
|
||||
</label>
|
||||
<p class="tooltip">Hover over text to scan</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-container action-buttons">
|
||||
<button tabindex="0" type="button" class="low-emphasis action-open-settings" title="Settings" data-hotkey='["global:openSettingsPage","title","Settings ({0})"]'>
|
||||
<div class="action-icon">
|
||||
<span class="icon" data-icon="cog"></span>
|
||||
</div>
|
||||
</button>
|
||||
<button tabindex="0" type="button" class="low-emphasis action-open-search" title="Search
Shift+click to open here" data-hotkey='["global:openSearchPage","title","Search ({0})\nShift+click to open here"]'>
|
||||
<div class="action-icon">
|
||||
<span class="icon" data-icon="magnifying-glass"></span>
|
||||
</div>
|
||||
</button>
|
||||
<button tabindex="0" type="button" class="low-emphasis action-open-info" title="Information" data-hotkey='["global:openInfoPage","title","Information ({0})"]'>
|
||||
<div class="action-icon">
|
||||
<span class="icon" data-icon="question-mark-circle"></span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
10
vendor/yomitan/background.html
vendored
Normal file
10
vendor/yomitan/background.html
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Yomitan Background</title>
|
||||
</head>
|
||||
<body>
|
||||
<script type="module" src="js/background/background-main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
376
vendor/yomitan/css/action-popup.css
vendored
Normal file
376
vendor/yomitan/css/action-popup.css
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2020-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Variables */
|
||||
|
||||
:root {
|
||||
--font-size-no-units: 14;
|
||||
--font-size: calc(1px * var(--font-size-no-units));
|
||||
--line-height-no-units: 20;
|
||||
--line-height: calc(var(--line-height-no-units) / var(--font-size-no-units));
|
||||
--background-color: #f8f9fa;
|
||||
--text-color: #333333;
|
||||
}
|
||||
|
||||
:root[data-theme=dark] {
|
||||
--background-color: #1e1e1e;
|
||||
--text-color: #cccccc;
|
||||
}
|
||||
|
||||
/* Initilization */
|
||||
|
||||
body[data-loaded=true] #loading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body:not([data-loaded=true]) #action-popup {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:root[data-mode=full] #action-popup {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
#action-popup {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 5px;
|
||||
margin: 0;
|
||||
font-family: 'Segoe UI', Tahoma, sans-serif;
|
||||
font-size: var(--font-size);
|
||||
width: max-content;
|
||||
height: max-content;
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
|
||||
/* Toggle */
|
||||
|
||||
body[data-loaded=true] .toggle-group {
|
||||
transition: transform 0.35s;
|
||||
}
|
||||
|
||||
.toggle>input[type=checkbox] {
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
display: block;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.toggle>input[type=checkbox]:not(:checked)~.toggle-group {
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.toggle {
|
||||
box-sizing: border-box;
|
||||
width: 85px;
|
||||
height: 43px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid #245580;
|
||||
border-radius: 4px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.toggle-group {
|
||||
position: absolute;
|
||||
width: 200%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.toggle-on,
|
||||
.toggle-off,
|
||||
.toggle-handle {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 6px 12px;
|
||||
font-size: var(--font-size);
|
||||
font-weight: bold;
|
||||
line-height: var(--line-height);
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toggle-on,
|
||||
.toggle-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.toggle-on {
|
||||
padding-right: 24px;
|
||||
left: 0;
|
||||
right: 50%;
|
||||
color: #ffffff;
|
||||
border-color: #2e6da4;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), inset 0 3px 5px rgba(0, 0, 0, 0);
|
||||
background-image: linear-gradient(225deg, #bc00ff, #00eeff);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
input[type=checkbox]:focus~.toggle-group>.toggle-on,
|
||||
input[type=checkbox]~.toggle-group>.toggle-on:hover {
|
||||
filter: grayscale(30%);
|
||||
}
|
||||
input[type=checkbox]:focus:not(:focus-visible)~.toggle-group>.toggle-on:not(:hover) {
|
||||
background-image: linear-gradient(225deg, #bc00ff, #00eeff);
|
||||
}
|
||||
input[type=checkbox]:focus-visible~.toggle-group>.toggle-on {
|
||||
filter: grayscale(30%);
|
||||
}
|
||||
input[type=checkbox]~.toggle-group>.toggle-on:active,
|
||||
input[type=checkbox]~.toggle-group>.toggle-on:active:focus {
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
.toggle-off {
|
||||
padding-left: 24px;
|
||||
left: 50%;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.toggle-handle {
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
border-style: solid;
|
||||
border-width: 0 1px;
|
||||
border-radius: 4px;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
.toggle-off,
|
||||
.toggle-handle {
|
||||
color: #333333;
|
||||
text-shadow: 0 1px 0 #ffffff;
|
||||
background-color: #ffffff;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
input[type=checkbox]:focus~.toggle-group>.toggle-off,
|
||||
input[type=checkbox]~.toggle-group>.toggle-off:hover,
|
||||
input[type=checkbox]~.toggle-group>.toggle-handle:hover {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
input[type=checkbox]:focus:not(:focus-visible)~.toggle-group>.toggle-off:not(:hover) {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
input[type=checkbox]:focus-visible~.toggle-group>.toggle-off,
|
||||
input[type=checkbox]~.toggle-group>.toggle-off:hover {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
input[type=checkbox]~.toggle-group>.toggle-off:active,
|
||||
input[type=checkbox]~.toggle-group>.toggle-handle:active,
|
||||
input[type=checkbox]~.toggle-group>.toggle-off:active:focus,
|
||||
input[type=checkbox]~.toggle-group>.toggle-handle:active:focus {
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
/* Action Containers */
|
||||
|
||||
h2.action-title {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1.125em;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.action-icon:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
flex: 0 0 auto;
|
||||
align-self: center;
|
||||
}
|
||||
.action-icon>.icon {
|
||||
display: block;
|
||||
background-color: var(--button-default-icon-color);
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.low-emphasis {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.action-item-left {
|
||||
flex: 1 1 auto;
|
||||
align-self: center;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.action-item-center {
|
||||
flex: 1 1 auto;
|
||||
align-self: center;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.action-item-right {
|
||||
flex: 0 1 auto;
|
||||
align-self: stretch;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.action-container:not([hidden]) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.action-container button {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.action-container.action-buttons {
|
||||
gap: 0.25em;
|
||||
}
|
||||
|
||||
/* Actions */
|
||||
|
||||
.action-container.action-select-profile {
|
||||
position: relative;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
select.profile-select {
|
||||
width: 7em;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Tooltip */
|
||||
|
||||
.tooltip {
|
||||
color: #808080;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.enable-dictionary-tooltip {
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
.tooltip>a:link, a:visited {
|
||||
color: #f0ad4e;
|
||||
}
|
||||
|
||||
/* Mobile overrides */
|
||||
|
||||
:root[data-mode=full] #action-popup {
|
||||
display: initial;
|
||||
}
|
||||
:root[data-mode=full] body {
|
||||
min-width: 95%;
|
||||
width: max-content;
|
||||
font-size: calc(var(--font-size) * 2);
|
||||
text-align: center;
|
||||
}
|
||||
:root[data-mode=full] .toggle-on, :root[data-mode=full] .toggle-off {
|
||||
font-size: calc(var(--font-size) * 4);
|
||||
}
|
||||
:root[data-mode=full] .toggle-handle {
|
||||
padding-left: 65px;
|
||||
padding-right: 65px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
:root[data-mode=full] .toggle {
|
||||
width: 100%;
|
||||
padding-top: 37.7%;
|
||||
}
|
||||
:root[data-mode=full] #extension-info {
|
||||
max-width: 95vw;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
:root[data-mode=full] select.profile-select {
|
||||
font-size: calc(var(--font-size) * 2);
|
||||
}
|
||||
|
||||
/* Fallback Mobile overrides */
|
||||
|
||||
/* Treat devices that can't hover as mobile devices */
|
||||
@media (hover: none) {
|
||||
#action-popup {
|
||||
display: initial;
|
||||
}
|
||||
body {
|
||||
min-width: 95%;
|
||||
width: max-content;
|
||||
font-size: calc(var(--font-size) * 2);
|
||||
text-align: center;
|
||||
}
|
||||
.toggle-on, .toggle-off {
|
||||
font-size: calc(var(--font-size) * 4);
|
||||
}
|
||||
.toggle-handle {
|
||||
padding-left: 65px;
|
||||
padding-right: 65px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.toggle {
|
||||
width: 100%;
|
||||
padding-top: 37.7%;
|
||||
}
|
||||
#extension-info {
|
||||
max-width: 95vw;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
select.profile-select {
|
||||
font-size: calc(var(--font-size) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dark mode before themes are applied
|
||||
DO NOT use this for normal theming */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body:not([data-loaded=true]) {
|
||||
color: #cccccc;
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
}
|
||||
30
vendor/yomitan/css/background.css
vendored
Normal file
30
vendor/yomitan/css/background.css
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* stylelint-disable declaration-no-important */
|
||||
#clipboard-rich-content-paste-target * {
|
||||
background-image: none !important;
|
||||
list-style-image: none !important;
|
||||
content: none !important;
|
||||
cursor: auto !important;
|
||||
border-image-source: none !important;
|
||||
offset-path: none !important;
|
||||
-webkit-mask-image: none !important;
|
||||
mask-image: none !important;
|
||||
}
|
||||
/* stylelint-enable declaration-no-important */
|
||||
132
vendor/yomitan/css/display-pronunciation.css
vendored
Normal file
132
vendor/yomitan/css/display-pronunciation.css
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2021-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the entrys of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--pronunciation-annotation-color: #000000;
|
||||
}
|
||||
:root[data-theme=dark] {
|
||||
--pronunciation-annotation-color: #ffffff;
|
||||
}
|
||||
|
||||
.pronunciation-downstep-notation {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pronunciation-text {
|
||||
display: inline;
|
||||
}
|
||||
.pronunciation-mora {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
.pronunciation-mora-line {
|
||||
border-color: var(--pronunciation-annotation-color);
|
||||
}
|
||||
.pronunciation-mora[data-pitch=high]>.pronunciation-mora-line {
|
||||
display: block;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
top: 0.1em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 0;
|
||||
border-top-width: 0.1em;
|
||||
border-top-style: solid;
|
||||
}
|
||||
.pronunciation-mora[data-pitch=high][data-pitch-next=low]>.pronunciation-mora-line {
|
||||
right: -0.1em;
|
||||
height: 0.4em;
|
||||
border-right-width: 0.1em;
|
||||
border-right-style: solid;
|
||||
}
|
||||
.pronunciation-mora[data-pitch=high][data-pitch-next=low] {
|
||||
padding-right: 0.1em;
|
||||
margin-right: 0.1em;
|
||||
}
|
||||
.pronunciation-devoice-indicator {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
width: 1.125em;
|
||||
height: 1.125em;
|
||||
border: calc(1.5em / var(--font-size-no-units)) dotted var(--danger-color);
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
z-index: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.pronunciation-nasal-indicator {
|
||||
display: block;
|
||||
position: absolute;
|
||||
right: -0.125em;
|
||||
top: 0.125em;
|
||||
width: 0.375em;
|
||||
height: 0.375em;
|
||||
border: calc(1.5em / var(--font-size-no-units)) solid var(--danger-color);
|
||||
border-radius: 50%;
|
||||
box-sizing: border-box;
|
||||
z-index: 1;
|
||||
}
|
||||
.pronunciation-nasal-diacritic {
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.pronunciation-character {
|
||||
display: inline;
|
||||
}
|
||||
.pronunciation-character-group {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pronunciation-graph {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 1.5em;
|
||||
}
|
||||
.pronunciation-graph-line,
|
||||
.pronunciation-graph-line-tail {
|
||||
fill: none;
|
||||
stroke: var(--pronunciation-annotation-color);
|
||||
stroke-width: 5;
|
||||
}
|
||||
.pronunciation-graph-line-tail {
|
||||
stroke-dasharray: 5 5;
|
||||
}
|
||||
.pronunciation-graph-dot {
|
||||
fill: var(--pronunciation-annotation-color);
|
||||
stroke: var(--pronunciation-annotation-color);
|
||||
stroke-width: 5;
|
||||
}
|
||||
.pronunciation-graph-dot-downstep1 {
|
||||
fill: none;
|
||||
stroke: var(--pronunciation-annotation-color);
|
||||
stroke-width: 5;
|
||||
}
|
||||
.pronunciation-graph-dot-downstep2 {
|
||||
fill: var(--pronunciation-annotation-color);
|
||||
}
|
||||
.pronunciation-graph-triangle {
|
||||
fill: none;
|
||||
stroke: var(--pronunciation-annotation-color);
|
||||
stroke-width: 5;
|
||||
}
|
||||
2100
vendor/yomitan/css/display.css
vendored
Normal file
2100
vendor/yomitan/css/display.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1344
vendor/yomitan/css/material.css
vendored
Normal file
1344
vendor/yomitan/css/material.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
36
vendor/yomitan/css/permissions.css
vendored
Normal file
36
vendor/yomitan/css/permissions.css
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2021-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#permissions-origin-list {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
grid-template-rows: auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.permissions-origin-index {
|
||||
margin: 0 0.5em;
|
||||
}
|
||||
input[type=text].permissions-origin-input {
|
||||
width: auto;
|
||||
justify-self: stretch;
|
||||
}
|
||||
.permissions-origin-button {
|
||||
justify-self: center;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
50
vendor/yomitan/css/popup-outer.css
vendored
Normal file
50
vendor/yomitan/css/popup-outer.css
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2016-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
iframe.yomitan-popup {
|
||||
all: initial;
|
||||
font-size: 1px;
|
||||
background-color: #ffffff;
|
||||
border: 1em solid #999999;
|
||||
box-shadow: 0 0 10em rgba(0, 0, 0, 0.5);
|
||||
position: fixed;
|
||||
resize: none;
|
||||
visibility: hidden;
|
||||
z-index: 2147483647;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
iframe.yomitan-popup[data-theme=dark] {
|
||||
background-color: #1e1e1e;
|
||||
border-color: #666666;
|
||||
}
|
||||
iframe.yomitan-popup[data-outer-theme=dark] {
|
||||
box-shadow: 0 0 10em rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
iframe.yomitan-popup[data-outer-theme=none] {
|
||||
box-shadow: none;
|
||||
}
|
||||
iframe.yomitan-popup[data-popup-display-mode=full-width] {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
iframe.yomitan-popup[data-popup-display-mode=full-width][data-below=true] {
|
||||
border-bottom: none;
|
||||
}
|
||||
iframe.yomitan-popup[data-popup-display-mode=full-width]:not([data-below=true]) {
|
||||
border-top: none;
|
||||
}
|
||||
164
vendor/yomitan/css/popup-preview.css
vendored
Normal file
164
vendor/yomitan/css/popup-preview.css
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2020-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
:root {
|
||||
--font-size-no-units: 14;
|
||||
--font-size: calc(1px * var(--font-size-no-units));
|
||||
|
||||
--line-height-no-units: 20;
|
||||
--line-height: calc(var(--line-height-no-units) / var(--font-size-no-units));
|
||||
|
||||
--animation-duration: 0s;
|
||||
|
||||
--example-text-color: #333333;
|
||||
--background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
:root[data-loaded=true] {
|
||||
--animation-duration: 0.25s;
|
||||
}
|
||||
|
||||
:root[data-theme=dark] {
|
||||
--example-text-color: #d4d4d4;
|
||||
--background-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
html {
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
html.dark {
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: var(--font-size);
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
min-width: 100%;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 1em;
|
||||
flex-flow: column nowrap;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.content-body {
|
||||
max-width: 100%;
|
||||
width: 400px;
|
||||
}
|
||||
.top-options {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
.top-options-left {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.top-options-right {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.example-text-container {
|
||||
position: relative;
|
||||
}
|
||||
.example-text {
|
||||
display: block;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
line-height: 1.25em;
|
||||
height: 1.25em;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid rgba(221, 221, 221, 0);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
color: var(--example-text-color);
|
||||
background-color: transparent;
|
||||
white-space: pre;
|
||||
transition: background-color var(--animation-duration) linear 0s, border-color var(--animation-duration) linear 0s;
|
||||
}
|
||||
.example-text:hover,
|
||||
.example-text-input {
|
||||
border-color: #dddddd;
|
||||
}
|
||||
.example-text[hidden] {
|
||||
display: none;
|
||||
}
|
||||
.example-text-input {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.example-text-input:not([hidden])+.example-text {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.popup-placeholder {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
padding-top: 10px;
|
||||
border: 1px solid rgba(0, 0, 0, 0);
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
}
|
||||
.placeholder-info {
|
||||
flex: 0 1 auto;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity var(--animation-duration) linear 0s, visibility 0s linear var(--animation-duration);
|
||||
}
|
||||
.placeholder-info.placeholder-info-visible {
|
||||
color: var(--example-text-color);
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity var(--animation-duration) linear 0s, visibility 0s linear 0s;
|
||||
}
|
||||
|
||||
.theme-button {
|
||||
display: inline-block;
|
||||
margin-left: 0.5em;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
line-height: 0;
|
||||
}
|
||||
.theme-button>input {
|
||||
vertical-align: middle;
|
||||
margin: 0 0.25em 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
.theme-button>span {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.theme-button:hover>span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
489
vendor/yomitan/css/search-settings.css
vendored
Normal file
489
vendor/yomitan/css/search-settings.css
vendored
Normal file
@@ -0,0 +1,489 @@
|
||||
:root {
|
||||
--padding: 10px;
|
||||
--padding-negative: calc(var(--padding) * -1);
|
||||
--content-width: 700px;
|
||||
--shadow-vertical: 0 1px 4px 0 var(--shadow-color), 0 2px 2px 0 var(--shadow-color);
|
||||
--shadow-left: -1px 0 4px 0 var(--shadow-color), -2px 0 2px 0 var(--shadow-color);
|
||||
--settings-group-horizontal-margin: 0;
|
||||
--settings-group-inner-vertical-padding: 0.85em;
|
||||
--settings-group-inner-horizontal-padding: 1.5em;
|
||||
--settings-group-inner-horizontal-padding-half: calc(var(--settings-group-inner-horizontal-padding) * 0.5);
|
||||
--settings-group-inner-horizontal-padding-half-wrappable: var(--settings-group-inner-horizontal-padding-half);
|
||||
--settings-group-inner-horizontal-padding-fourth: calc(var(--settings-group-inner-horizontal-padding) * 0.25);
|
||||
--settings-group-border-radius: 0.3em;
|
||||
--settings-group-right-max-height: 40px;
|
||||
--settings-group-wrap: nowrap;
|
||||
--show-preview-label-height: 40px;
|
||||
|
||||
--font-size-no-units: 14;
|
||||
--font-size: calc(1px * var(--font-size-no-units));
|
||||
--font-size-small: 12px;
|
||||
--outline-item-height: 40px;
|
||||
--outline-item-icon-size: 32px;
|
||||
--input-short-width: calc(var(--input-width-large) / 2 - var(--padding) / 2);
|
||||
--input-short-height: 24px;
|
||||
--input-medium-width: calc(var(--input-width-large) * 0.75);
|
||||
--fab-button-size: 56px;
|
||||
--fab-button-padding: 16px;
|
||||
--modal-width: 600px;
|
||||
--modal-height: 400px;
|
||||
--modal-width-small: 400px;
|
||||
--modal-height-small: 200px;
|
||||
--modal-width-medium: 600px;
|
||||
--modal-height-medium: 400px;
|
||||
--modal-transition-offset: -64px;
|
||||
--badge-size: 16px;
|
||||
|
||||
--link-color: var(--accent-color);
|
||||
--link-color-hover: var(--accent-color-dark);
|
||||
--separator-color1: #cccccc;
|
||||
--separator-color2: #eeeeee;
|
||||
--outline-item-background-color: rgba(13, 13, 13, 0);
|
||||
--outline-item-background-color-hover: rgba(13, 13, 13, 0.15);
|
||||
--warning-color: #96751c;
|
||||
--warning-color-light: #edc75e;
|
||||
--dim-background-color: rgba(0, 0, 0, 0.5);
|
||||
--content-dimmer-color: rgba(0, 0, 0, 0.1);
|
||||
--advanced-color: #6640be;
|
||||
--advanced-color-lighter: hsl(258, 50%, 75%);
|
||||
--advanced-color-transparent25: rgba(102, 64, 190, 0.5);
|
||||
|
||||
--modal-padding-horizontal: 1em;
|
||||
--modal-padding-vertical: 0.625em;
|
||||
--modal-padding-vertical-half: calc(var(--modal-padding-vertical) * 0.5);
|
||||
--modal-button-spacing: 0.625em;
|
||||
}
|
||||
:root:not([data-loaded=true]) {
|
||||
--animation-duration: 0s;
|
||||
}
|
||||
:root[data-theme=dark] {
|
||||
--separator-color1: #333333;
|
||||
--separator-color2: #222222;
|
||||
}
|
||||
|
||||
/* Modal */
|
||||
.modal {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
overscroll-behavior: contain;
|
||||
background-color: var(--dim-background-color);
|
||||
outline: none;
|
||||
z-index: 10000;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition:
|
||||
opacity var(--animation-duration2) ease-out,
|
||||
visibility 0s linear;
|
||||
}
|
||||
.modal[hidden] {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition:
|
||||
opacity var(--animation-duration2) ease-in,
|
||||
visibility 0s linear var(--animation-duration2);
|
||||
}
|
||||
.modal[hidden]:not(.hidden-animating) {
|
||||
display: none;
|
||||
}
|
||||
.modal-content {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
width: var(--modal-width);
|
||||
height: var(--modal-height);
|
||||
background-color: var(--background-color-light);
|
||||
flex: 0 1 auto;
|
||||
border-radius: 0.5em;
|
||||
transform: translate(0, 0);
|
||||
transition:
|
||||
transform var(--animation-duration2) ease-out,
|
||||
width var(--animation-duration2) ease-in-out,
|
||||
height var(--animation-duration2) ease-in-out,
|
||||
border-radius var(--animation-duration2) ease-in-out;
|
||||
box-shadow: var(--shadow-vertical);
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.modal[hidden] .modal-content {
|
||||
pointer-events: none;
|
||||
}
|
||||
.modal-content.modal-content-small {
|
||||
width: var(--modal-width-small);
|
||||
min-height: var(--modal-height-small);
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
}
|
||||
.modal-content.modal-content-medium {
|
||||
width: var(--modal-width-medium);
|
||||
min-height: var(--modal-height-medium);
|
||||
height: auto;
|
||||
max-height: 100%;
|
||||
}
|
||||
.modal-content.modal-content-full {
|
||||
width: var(--content-width);
|
||||
height: 100%;
|
||||
transform: translate(0, 0);
|
||||
border-radius: 0;
|
||||
}
|
||||
.modal[hidden] .modal-content {
|
||||
transform: translate(0, var(--modal-transition-offset));
|
||||
transition:
|
||||
transform 0s linear var(--animation-duration2),
|
||||
width var(--animation-duration2) ease-in-out,
|
||||
height var(--animation-duration2) ease-in-out,
|
||||
border-radius var(--animation-duration2) ease-in-out;
|
||||
}
|
||||
.modal-header {
|
||||
flex: 0 0 auto;
|
||||
padding: var(--modal-padding-vertical) var(--modal-padding-horizontal) var(--modal-padding-vertical-half);
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.modal-title {
|
||||
font-size: 1.125em;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.modal-footer {
|
||||
flex: 0 0 auto;
|
||||
padding: var(--modal-padding-vertical-half) var(--modal-padding-horizontal) var(--modal-padding-vertical);
|
||||
margin-right: calc(var(--modal-button-spacing) * -1);
|
||||
margin-top: calc(var(--modal-button-spacing) * -1);
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: flex-end;
|
||||
justify-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.modal-footer>* {
|
||||
margin-right: var(--modal-button-spacing);
|
||||
margin-top: var(--modal-button-spacing);
|
||||
}
|
||||
.modal-body {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
padding: var(--modal-padding-vertical-half) var(--modal-padding-horizontal);
|
||||
}
|
||||
.modal-body-addon {
|
||||
flex: 0 0 auto;
|
||||
padding: var(--modal-padding-vertical-half) var(--modal-padding-horizontal);
|
||||
}
|
||||
.modal-body>.settings-item,
|
||||
.modal-settings-group>.settings-item {
|
||||
margin-left: calc(var(--modal-padding-horizontal) * -1);
|
||||
}
|
||||
.modal-body .settings-item {
|
||||
margin-right: calc(var(--modal-padding-horizontal) * -1);
|
||||
}
|
||||
.modal-body .settings-item+.settings-item {
|
||||
border-top: none;
|
||||
}
|
||||
.modal-body .settings-item-left {
|
||||
padding-left: var(--modal-padding-horizontal);
|
||||
padding-top: var(--settings-group-inner-horizontal-padding-fourth);
|
||||
padding-bottom: var(--settings-group-inner-horizontal-padding-fourth);
|
||||
}
|
||||
.modal-body .settings-item-right {
|
||||
padding-right: var(--modal-padding-horizontal);
|
||||
padding-top: var(--settings-group-inner-horizontal-padding-fourth);
|
||||
padding-bottom: var(--settings-group-inner-horizontal-padding-fourth);
|
||||
}
|
||||
.modal-body .settings-item-children {
|
||||
padding-left: var(--modal-padding-horizontal);
|
||||
padding-right: var(--modal-padding-horizontal);
|
||||
padding-bottom: var(--settings-group-inner-horizontal-padding-fourth);
|
||||
}
|
||||
|
||||
.modal.modal-left {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
.modal-content-container {
|
||||
pointer-events: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.modal-content-container>.modal-content,
|
||||
.modal-content-container>.modal-content-dimmer {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.modal-content-container>.modal-content-dimmer {
|
||||
background: var(--custom-css-modal-background);
|
||||
width: var(--custom-css-dim-size);
|
||||
height: 100%;
|
||||
margin-right: calc(100% - var(--custom-css-dim-size));
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.modal-header-button-container {
|
||||
margin-top: calc(-1 * var(--modal-padding-vertical-half));
|
||||
margin-bottom: calc(-1 * var(--modal-padding-vertical-half));
|
||||
}
|
||||
.modal-header-button-group {
|
||||
display: block;
|
||||
position: relative;
|
||||
width: var(--icon-button-size);
|
||||
height: var(--icon-button-size);
|
||||
}
|
||||
.modal-header-button {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
button.icon-button.modal-header-button {
|
||||
--button-content-color: var(--button-default-icon-color-light);
|
||||
--button-hover-content-color: var(--button-default-icon-color);
|
||||
--button-active-content-color: var(--button-default-icon-color);
|
||||
}
|
||||
button.icon-button.modal-header-button>.icon-button-inner>.icon {
|
||||
transition: background-color var(--animation-duration) ease-in-out;
|
||||
}
|
||||
.modal-header-button[data-modal-action=expand],
|
||||
.modal-header-button[data-modal-action=collapse] {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
transition:
|
||||
opacity var(--animation-duration2) ease-in-out 0s,
|
||||
visibility 0s ease-in-out 0s;
|
||||
}
|
||||
.modal-content.modal-content-full .modal-header-button[data-modal-action=expand],
|
||||
.modal-content:not(.modal-content-full) .modal-header-button[data-modal-action=collapse] {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
transition:
|
||||
opacity var(--animation-duration2) ease-in-out 0s,
|
||||
visibility 0s ease-in-out var(--animation-duration2);
|
||||
}
|
||||
|
||||
.modal-separator-line {
|
||||
border-top: var(--thin-border-size) solid var(--separator-color1);
|
||||
margin: 0 calc(var(--modal-padding-horizontal) * -1);
|
||||
}
|
||||
.modal-separator-line-light {
|
||||
border-top: var(--thin-border-size) solid var(--separator-color2);
|
||||
margin: 0 calc(var(--modal-padding-horizontal) * -1);
|
||||
}
|
||||
|
||||
/* Settings styles */
|
||||
.settings-group {
|
||||
margin: 0 var(--settings-group-horizontal-margin);
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
background-color: var(--background-color-light);
|
||||
box-shadow: var(--shadow-vertical);
|
||||
border-radius: var(--settings-group-border-radius);
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.settings-group.settings-group-top-margin {
|
||||
margin-top: 1.0125em;
|
||||
}
|
||||
.settings-item {
|
||||
position: relative;
|
||||
}
|
||||
.settings-item:not([hidden]) {
|
||||
display: block;
|
||||
}
|
||||
.settings-item-outer {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
.settings-item-inner {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
justify-content: flex-end;
|
||||
align-content: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
.settings-item-inner.settings-item-inner-wrappable {
|
||||
flex-wrap: var(--settings-group-wrap);
|
||||
}
|
||||
.settings-item-left {
|
||||
padding: var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding-half) var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding);
|
||||
flex: 1 1 auto;
|
||||
align-self: center;
|
||||
position: relative;
|
||||
}
|
||||
.settings-item-left:last-child {
|
||||
padding-right: var(--settings-group-inner-horizontal-padding);
|
||||
}
|
||||
.settings-item-right {
|
||||
padding: var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding) var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding-half);
|
||||
flex: 0 1 auto;
|
||||
align-self: stretch;
|
||||
max-height: var(--settings-group-right-max-height);
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.settings-item-inner.settings-item-inner-wrappable>.settings-item-left {
|
||||
padding-right: var(--settings-group-inner-horizontal-padding-half-wrappable);
|
||||
}
|
||||
.settings-item-inner.settings-item-inner-wrappable>.settings-item-right {
|
||||
padding-left: var(--settings-group-inner-horizontal-padding-half-wrappable);
|
||||
}
|
||||
.settings-item-center {
|
||||
padding: var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding) var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding);
|
||||
flex: 0 1 100%;
|
||||
align-self: flex-start;
|
||||
text-align: center;
|
||||
}
|
||||
.settings-item+.settings-item {
|
||||
border-top: var(--thin-border-size) solid var(--separator-color2);
|
||||
}
|
||||
.settings-item-description {
|
||||
color: var(--text-color-light2);
|
||||
}
|
||||
.settings-item-right.open-panel-button-container {
|
||||
padding: 0.25em 1em 0.25em 0.75em;
|
||||
max-height: calc(var(--settings-group-right-max-height) + var(--settings-group-inner-vertical-padding) * 2);
|
||||
}
|
||||
.settings-item-children {
|
||||
padding: 0em var(--settings-group-inner-horizontal-padding-half) var(--settings-group-inner-vertical-padding) var(--settings-group-inner-horizontal-padding);
|
||||
margin-top: 0;
|
||||
}
|
||||
.settings-item-children.settings-item-children-group {
|
||||
padding: 0 0 0 calc(var(--settings-group-inner-horizontal-padding) + var(--settings-group-inner-horizontal-padding));
|
||||
}
|
||||
.settings-item-children.settings-item-children-group .settings-item {
|
||||
border-top: var(--thin-border-size) solid var(--separator-color2);
|
||||
}
|
||||
.settings-item-children.settings-item-children-group .settings-item-left {
|
||||
padding-left: 0;
|
||||
}
|
||||
.settings-item-children.settings-item-children-group .settings-item-inner.settings-item-inner-wrappable>.settings-item-left:not(:last-child) {
|
||||
padding-right: calc(var(--settings-group-inner-horizontal-padding-half-wrappable) * 2);
|
||||
}
|
||||
.settings-item-children.settings-item-children-group .settings-item-inner.settings-item-inner-wrappable>.settings-item-right {
|
||||
padding-left: 0;
|
||||
}
|
||||
.settings-item-children.settings-item-children-group .settings-item-children {
|
||||
padding-left: 0;
|
||||
}
|
||||
.settings-item.settings-item-button,
|
||||
a.settings-item.settings-item-button {
|
||||
cursor: pointer;
|
||||
color: var(--text-color);
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
transition: background-color var(--animation-duration) ease-in-out;
|
||||
}
|
||||
.settings-item.settings-item-button>.settings-item-inner,
|
||||
.settings-item.settings-item-button>.settings-item-inner>.settings-item-left,
|
||||
.settings-item.settings-item-button>.settings-item-inner>.settings-item-right {
|
||||
margin-top: 0;
|
||||
}
|
||||
.settings-item.settings-item-button:hover,
|
||||
.settings-item.settings-item-button:active {
|
||||
background-color: var(--background-color);
|
||||
}
|
||||
.settings-item.settings-item-button .icon-button>.icon-button-inner>.icon {
|
||||
transition: background-color var(--animation-duration) ease-in-out;
|
||||
}
|
||||
.settings-item.settings-item-button:hover .icon-button>.icon-button-inner>.icon,
|
||||
.settings-item.settings-item-button:active .icon-button>.icon-button-inner>.icon {
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
.settings-item-invalid-indicator {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 0.5em;
|
||||
background-color: var(--danger-color);
|
||||
}
|
||||
.settings-item[data-invalid=true] .settings-item-invalid-indicator {
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
/* Settings item groups */
|
||||
.settings-item-group {
|
||||
margin-right: var(--padding-negative);
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.settings-item-group.settings-item-group-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.settings-item-group-item {
|
||||
flex: 0 1 auto;
|
||||
padding-right: var(--padding);
|
||||
}
|
||||
.settings-item-group-item-label {
|
||||
font-size: var(--font-size-small);
|
||||
line-height: 1;
|
||||
}
|
||||
input[type=text].short-width,
|
||||
input[type=number].short-width,
|
||||
select.short-width {
|
||||
width: var(--input-short-width);
|
||||
}
|
||||
input[type=text].medium-width,
|
||||
input[type=number].medium-width,
|
||||
select.medium-width {
|
||||
width: var(--input-medium-width);
|
||||
}
|
||||
input[type=text].short-height,
|
||||
input[type=number].short-height,
|
||||
select.short-height {
|
||||
height: var(--input-short-height);
|
||||
margin-top: calc(var(--settings-group-right-max-height) - var(--input-short-height) - var(--font-size-small));
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
.settings-item-button-group-container {
|
||||
max-height: none;
|
||||
width: 100%;
|
||||
}
|
||||
.settings-item-button-group {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-flow: row wrap;
|
||||
max-height: none;
|
||||
justify-content: flex-start;
|
||||
margin-top: var(--padding-negative);
|
||||
margin-right: var(--padding-negative);
|
||||
}
|
||||
.settings-item-button-group-item {
|
||||
flex: 0 1 auto;
|
||||
padding-top: var(--padding);
|
||||
padding-right: var(--padding);
|
||||
}
|
||||
.settings-item-progress-report {
|
||||
display: none;
|
||||
font-weight: bold;
|
||||
color: #4169e1;
|
||||
}
|
||||
.settings-item-error-report {
|
||||
display: none;
|
||||
font-weight: bold;
|
||||
color: #8b0000;
|
||||
}
|
||||
245
vendor/yomitan/css/search.css
vendored
Normal file
245
vendor/yomitan/css/search.css
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2020-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Variables */
|
||||
:root {
|
||||
--search-scroll-container-horizontal-padding: 0.72em;
|
||||
--query-horizontal-padding: 0;
|
||||
|
||||
--padding: calc(10em / var(--font-size-no-units));
|
||||
--content-width-search: 700;
|
||||
--content-width: calc(1em * var(--content-width-search) / var(--font-size-no-units));
|
||||
|
||||
--background-color: #ffffff;
|
||||
--separator-color1: #cccccc;
|
||||
|
||||
--search-textbox-height: calc(var(--textarea-line-height) + var(--textarea-padding) * 2);
|
||||
--search-textbox-min-height: calc(var(--textarea-line-height) + var(--textarea-padding) * 2);
|
||||
--search-textbox-max-height: calc(var(--textarea-line-height) * 5 + var(--textarea-padding) * 2);
|
||||
|
||||
--cog-icon-size: 26px;
|
||||
}
|
||||
:root:not([data-loaded=true]) {
|
||||
--animation-duration: 0s;
|
||||
}
|
||||
:root[data-theme=dark] {
|
||||
--separator-color1: #333333;
|
||||
}
|
||||
|
||||
/* Common styles */
|
||||
:root {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: var(--background-color);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--text-color);
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.search-header {
|
||||
padding-left: var(--search-scroll-container-horizontal-padding);
|
||||
padding-right: var(--search-scroll-container-horizontal-padding);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
line-height: 1.5em;
|
||||
margin: 0;
|
||||
padding: 0.25em 0 0;
|
||||
font-weight: normal;
|
||||
box-sizing: border-box;
|
||||
border-bottom: calc(1em / (var(--font-size-no-units) * 2)) solid var(--separator-color1);
|
||||
}
|
||||
|
||||
/* Search bar */
|
||||
.search-textbox-container {
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
#search-textbox {
|
||||
color: var(--text-color);
|
||||
flex: 1 1 auto;
|
||||
box-sizing: border-box;
|
||||
padding: var(--textarea-padding);
|
||||
background-color: var(--input-background-color);
|
||||
border-radius: 0;
|
||||
line-height: var(--textarea-line-height);
|
||||
border: 0;
|
||||
outline: none;
|
||||
width: 100%;
|
||||
height: var(--search-textbox-height);
|
||||
min-height: var(--search-textbox-min-height);
|
||||
max-height: var(--search-textbox-max-height);
|
||||
resize: none;
|
||||
font-size: var(--font-size);
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
white-space: pre-wrap;
|
||||
z-index: 1;
|
||||
}
|
||||
.search-button {
|
||||
flex: 0 0 auto;
|
||||
position: relative;
|
||||
width: 2.5em;
|
||||
height: var(--search-textbox-height);
|
||||
min-height: var(--search-textbox-min-height);
|
||||
max-height: var(--search-textbox-max-height);
|
||||
background-color: var(--input-background-color);
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: background-color var(--animation-duration) ease-in-out;
|
||||
border-radius: 0;
|
||||
}
|
||||
.search-button:hover,
|
||||
.search-button:focus {
|
||||
background-color: var(--input-background-color-dark);
|
||||
}
|
||||
.search-button:focus:not(:focus-visible):not(:hover) {
|
||||
background-color: var(--input-background-color);
|
||||
}
|
||||
.search-button:focus-visible {
|
||||
background-color: var(--input-background-color-dark);
|
||||
}
|
||||
.search-button:active,
|
||||
.search-button:active:focus {
|
||||
background-color: var(--input-background-color-darker);
|
||||
}
|
||||
|
||||
.search-button>.icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--button-default-icon-color);
|
||||
--icon-size: 16px 16px;
|
||||
}
|
||||
|
||||
.clear-button {
|
||||
flex: 0 0 auto;
|
||||
position: relative;
|
||||
width: 2.5em;
|
||||
height: var(--search-textbox-height);
|
||||
min-height: var(--search-textbox-min-height);
|
||||
max-height: var(--search-textbox-max-height);
|
||||
background-color: var(--input-background-color);
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: background-color var(--animation-duration) ease-in-out;
|
||||
border-radius: 0;
|
||||
}
|
||||
.clear-button:hover,
|
||||
.clear-button:focus {
|
||||
background-color: var(--input-background-color-dark);
|
||||
}
|
||||
.clear-button:focus:not(:focus-visible):not(:hover) {
|
||||
background-color: var(--input-background-color);
|
||||
}
|
||||
.clear-button:focus-visible {
|
||||
background-color: var(--input-background-color-dark);
|
||||
}
|
||||
.clear-button:active,
|
||||
.clear-button:active:focus {
|
||||
background-color: var(--input-background-color-darker);
|
||||
}
|
||||
|
||||
.clear-button>.icon {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--button-default-icon-color);
|
||||
--icon-size: 16px 16px;
|
||||
}
|
||||
|
||||
/* Search options */
|
||||
#search-settings-button>.icon {
|
||||
display: block;
|
||||
background-color: var(--button-default-icon-color);
|
||||
width: var(--cog-icon-size);
|
||||
height: var(--cog-icon-size);
|
||||
transition: var(--animation-duration) filter ease-in-out;
|
||||
}
|
||||
#search-settings-button>.icon:hover,
|
||||
#search-settings-button>.icon:focus {
|
||||
filter: invert(0.5);
|
||||
}
|
||||
#search-settings-button {
|
||||
margin-right: 0;
|
||||
float: right;
|
||||
}
|
||||
.search-options-right {
|
||||
flex: 1;
|
||||
}
|
||||
.search-options {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin: 0.5em 0 0 0;
|
||||
align-items: center;
|
||||
}
|
||||
.search-option {
|
||||
flex: 0 1 auto;
|
||||
margin: 0.5em 2em 0.5em 0;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
.search-option:not([hidden]) {
|
||||
display: flex;
|
||||
}
|
||||
.search-option-label {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
/* Search styles */
|
||||
#intro {
|
||||
overflow: hidden;
|
||||
}
|
||||
#intro>p {
|
||||
margin: 0;
|
||||
}
|
||||
:root[data-search-mode=action-popup] #intro,
|
||||
:root[data-search-mode=action-popup] #search-option-clipboard-monitor-container {
|
||||
display: none;
|
||||
}
|
||||
:root[data-search-mode=action-popup],
|
||||
:root[data-search-mode=action-popup] body {
|
||||
width: 640px;
|
||||
height: 480px;
|
||||
}
|
||||
|
||||
/* Dark mode before themes are applied
|
||||
DO NOT use this for normal theming */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-loaded=true]) {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
}
|
||||
2785
vendor/yomitan/css/settings.css
vendored
Normal file
2785
vendor/yomitan/css/settings.css
vendored
Normal file
File diff suppressed because it is too large
Load Diff
259
vendor/yomitan/css/structured-content.css
vendored
Normal file
259
vendor/yomitan/css/structured-content.css
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2021-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the entrys of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Glossary images */
|
||||
.gloss-image-container {
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
max-width: 100%;
|
||||
max-height: 100vh;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
line-height: 0;
|
||||
font-size: calc(1em / var(--font-size-no-units));
|
||||
overflow: hidden;
|
||||
}
|
||||
.gloss-image-link[data-background=true]>.gloss-image-container {
|
||||
background-color: var(--gloss-image-background-color);
|
||||
}
|
||||
.gloss-image-link {
|
||||
cursor: inherit;
|
||||
color: var(--accent-color);
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
line-height: 1;
|
||||
max-width: 100%;
|
||||
}
|
||||
.gloss-image-link:hover {
|
||||
color: var(--accent-color-dark);
|
||||
cursor: pointer;
|
||||
}
|
||||
.gloss-image-container-overlay {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: calc(1em * var(--font-size-no-units));
|
||||
line-height: var(--line-height);
|
||||
display: table;
|
||||
table-layout: fixed;
|
||||
white-space: normal;
|
||||
color: var(--text-color-light3);
|
||||
}
|
||||
.gloss-image-link[data-has-image=true][data-image-load-state=load-error] .gloss-image-container-overlay::after {
|
||||
content: 'Image failed to load';
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
padding: 0.25em;
|
||||
}
|
||||
.gloss-image-background {
|
||||
--image: none;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--text-color);
|
||||
-webkit-mask-repeat: no-repeat;
|
||||
-webkit-mask-position: center center;
|
||||
-webkit-mask-mode: alpha;
|
||||
-webkit-mask-size: contain;
|
||||
-webkit-mask-image: var(--image);
|
||||
mask-repeat: no-repeat;
|
||||
mask-position: center center;
|
||||
mask-mode: alpha;
|
||||
mask-size: contain;
|
||||
mask-image: var(--image);
|
||||
display: none;
|
||||
}
|
||||
.gloss-image {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
object-fit: contain;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
.gloss-image-link[data-has-aspect-ratio=true] .gloss-image {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.gloss-image-link[data-image-rendering=pixelated] .gloss-image,
|
||||
.gloss-image-link[data-image-rendering=pixelated] .gloss-image-background {
|
||||
image-rendering: auto;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: pixelated;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
.gloss-image-link[data-image-rendering=crisp-edges] .gloss-image,
|
||||
.gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background {
|
||||
image-rendering: auto;
|
||||
image-rendering: -moz-crisp-edges;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
image-rendering: crisp-edges;
|
||||
}
|
||||
:root[data-browser=firefox] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image,
|
||||
:root[data-browser=firefox] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background,
|
||||
:root[data-browser=firefox-mobile] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image,
|
||||
:root[data-browser=firefox-mobile] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background {
|
||||
image-rendering: auto;
|
||||
}
|
||||
.gloss-image-link[data-has-aspect-ratio=true] .gloss-image-sizer {
|
||||
display: inline-block;
|
||||
width: 0;
|
||||
vertical-align: top;
|
||||
font-size: 0;
|
||||
}
|
||||
.gloss-image-link-text {
|
||||
display: none;
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
.gloss-image-link-text::before {
|
||||
content: '[';
|
||||
}
|
||||
.gloss-image-link-text::after {
|
||||
content: ']';
|
||||
}
|
||||
.gloss-image-description {
|
||||
display: block;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.gloss-image-link[data-appearance=monochrome] .gloss-image {
|
||||
/* Workaround for coloring monochrome gloss images due to issues with masking using a canvas without loading extra media */
|
||||
/* drop-shadow with 0.01px blur is at minimum required for Firefox to render the shadow when used on a canvas */
|
||||
--shadow-settings: 0 0 0.01px var(--text-color);
|
||||
filter: grayscale(1) opacity(0.5) drop-shadow(var(--shadow-settings)) drop-shadow(var(--shadow-settings)) saturate(1000%) brightness(1000%);
|
||||
}
|
||||
|
||||
.gloss-image-link[data-size-units=em] .gloss-image-container {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.gloss-image-link[data-vertical-align=baseline] { vertical-align: baseline; }
|
||||
.gloss-image-link[data-vertical-align=sub] { vertical-align: sub; }
|
||||
.gloss-image-link[data-vertical-align=super] { vertical-align: super; }
|
||||
.gloss-image-link[data-vertical-align=text-top] { vertical-align: top; }
|
||||
.gloss-image-link[data-vertical-align=text-bottom] { vertical-align: bottom; }
|
||||
.gloss-image-link[data-vertical-align=middle] { vertical-align: middle; }
|
||||
.gloss-image-link[data-vertical-align=top] { vertical-align: top; }
|
||||
.gloss-image-link[data-vertical-align=bottom] { vertical-align: bottom; }
|
||||
.gloss-image-link[data-collapsed=true],
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true] {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.gloss-image-link[data-collapsed=true] .gloss-image-container,
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true] .gloss-image-container {
|
||||
display: none;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
.entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-link[data-collapsed=true] .gloss-image-container,
|
||||
:root[data-glossary-layout-mode^=compact] .entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-link[data-collapsible=true] .gloss-image-container,
|
||||
:root[data-glossary-layout-mode^=compact] .definition-item:nth-last-of-type(1) .gloss-image-link[data-collapsible=true] .gloss-image-container {
|
||||
bottom: 100%;
|
||||
top: auto;
|
||||
}
|
||||
.gloss-image-link[data-collapsed=true]:hover .gloss-image-container,
|
||||
.gloss-image-link[data-collapsed=true]:focus .gloss-image-container,
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true]:hover .gloss-image-container,
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true]:focus .gloss-image-container {
|
||||
display: block;
|
||||
}
|
||||
.gloss-image-link[data-collapsed=true] .gloss-image-link-text,
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true] .gloss-image-link-text {
|
||||
display: inline;
|
||||
}
|
||||
.gloss-image-link[data-collapsed=true]~.gloss-image-description,
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-image-description {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
/* Links */
|
||||
.gloss-link-text {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
.gloss-link-external-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: calc(16em / var(--font-size-no-units));
|
||||
height: calc(16em / var(--font-size-no-units));
|
||||
margin-left: 0.25em;
|
||||
background-color: var(--link-color);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
/* Structured content glossary styles */
|
||||
.gloss-sc-table-container {
|
||||
display: block;
|
||||
}
|
||||
.gloss-sc-table {
|
||||
table-layout: auto;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.gloss-sc-thead,
|
||||
.gloss-sc-tfoot,
|
||||
.gloss-sc-th {
|
||||
font-weight: bold;
|
||||
background-color: var(--background-color-dark1);
|
||||
}
|
||||
.gloss-sc-th,
|
||||
.gloss-sc-td {
|
||||
border-width: calc(1em / var(--font-size-no-units));
|
||||
border-style: solid;
|
||||
border-color: var(--text-color-light2);
|
||||
padding: 0.25em;
|
||||
vertical-align: top;
|
||||
}
|
||||
.gloss-sc-ol,
|
||||
.gloss-sc-ul {
|
||||
padding-left: var(--list-padding2);
|
||||
}
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-sc-ul[data-sc-content=glossary] {
|
||||
display: inline;
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-sc-ul[data-sc-content=glossary] .gloss-sc-li {
|
||||
display: inline;
|
||||
}
|
||||
:root[data-glossary-layout-mode^=compact] .gloss-sc-ul[data-sc-content=glossary] .gloss-sc-li:not(:first-child)::before {
|
||||
white-space: pre-wrap;
|
||||
content: var(--compact-list-separator);
|
||||
display: inline;
|
||||
color: var(--text-color-light3);
|
||||
}
|
||||
.gloss-sc-details {
|
||||
padding-left: var(--list-padding1);
|
||||
}
|
||||
.gloss-sc-summary {
|
||||
list-style-position: outside;
|
||||
}
|
||||
21
vendor/yomitan/css/visibility-modifiers.css
vendored
Normal file
21
vendor/yomitan/css/visibility-modifiers.css
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
:root:not([data-debug=true]) .debug-only {
|
||||
display: none;
|
||||
}
|
||||
:root:not([data-advanced=true]) .advanced-only {
|
||||
display: none;
|
||||
}
|
||||
:root:not([data-advanced=false]) .basic-only {
|
||||
display: none;
|
||||
}
|
||||
:root:not([data-language=ja]):not([data-language=zh]):not([data-language=yue]) .jpzhyue-only {
|
||||
display: none;
|
||||
}
|
||||
:root:not([data-language=ja]):not([data-language=zh]):not([data-language=yue]):not([data-language=ko]) .jpzhyueko-only {
|
||||
display: none;
|
||||
}
|
||||
:root:is([data-language=ja], [data-language=zh], [data-language=yue], [data-language=ko]) .not-jpzhyueko {
|
||||
display: none;
|
||||
}
|
||||
:root:not([data-language=ja]) .jp-only {
|
||||
display: none;
|
||||
}
|
||||
43
vendor/yomitan/data/anki-compact-gloss-style.js
vendored
Normal file
43
vendor/yomitan/data/anki-compact-gloss-style.js
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2023-2025 Yomitan Authors
|
||||
* Copyright (C) 2019-2022 Yomichan Authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const ANKI_COMPACT_GLOSS_STYLES = `
|
||||
ul[data-sc-content="glossary"] > li:not(:first-child)::before {
|
||||
white-space: pre-wrap;
|
||||
content: ' | ';
|
||||
display: inline;
|
||||
color: #777777;
|
||||
}
|
||||
|
||||
ul[data-sc-content="glossary"] > li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
ul[data-sc-content="glossary"] {
|
||||
display: inline;
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getAnkiCompactGlossStyles() {
|
||||
return ANKI_COMPACT_GLOSS_STYLES.trim();
|
||||
}
|
||||
BIN
vendor/yomitan/data/audio/fallback-bloop.mp3
vendored
Normal file
BIN
vendor/yomitan/data/audio/fallback-bloop.mp3
vendored
Normal file
Binary file not shown.
BIN
vendor/yomitan/data/audio/fallback-click.mp3
vendored
Normal file
BIN
vendor/yomitan/data/audio/fallback-click.mp3
vendored
Normal file
Binary file not shown.
BIN
vendor/yomitan/data/fonts/kanji-stroke-orders.ttf
vendored
Normal file
BIN
vendor/yomitan/data/fonts/kanji-stroke-orders.ttf
vendored
Normal file
Binary file not shown.
166
vendor/yomitan/data/pronunciation-style.json
vendored
Normal file
166
vendor/yomitan/data/pronunciation-style.json
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
[
|
||||
{
|
||||
"selectors": [".pronunciation-downstep-notation"],
|
||||
"styles": [
|
||||
["display", "inline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-text"],
|
||||
"styles": [
|
||||
["display", "inline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-mora"],
|
||||
"styles": [
|
||||
["display", "inline-block"],
|
||||
["position", "relative"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-mora-line"],
|
||||
"styles": [
|
||||
["border-color", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-mora[data-pitch=high]>.pronunciation-mora-line"],
|
||||
"styles": [
|
||||
["display", "block"],
|
||||
["user-select", "none"],
|
||||
["pointer-events", "none"],
|
||||
["position", "absolute"],
|
||||
["top", "0.1em"],
|
||||
["left", "0"],
|
||||
["right", "0"],
|
||||
["height", "0"],
|
||||
["border-top-width", "0.1em"],
|
||||
["border-top-style", "solid"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-mora[data-pitch=high][data-pitch-next=low]>.pronunciation-mora-line"],
|
||||
"styles": [
|
||||
["right", "-0.1em"],
|
||||
["height", "0.4em"],
|
||||
["border-right-width", "0.1em"],
|
||||
["border-right-style", "solid"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-mora[data-pitch=high][data-pitch-next=low]"],
|
||||
"styles": [
|
||||
["padding-right", "0.1em"],
|
||||
["margin-right", "0.1em"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-devoice-indicator"],
|
||||
"styles": [
|
||||
["display", "block"],
|
||||
["position", "absolute"],
|
||||
["left", "50%"],
|
||||
["top", "50%"],
|
||||
["width", "1.125em"],
|
||||
["height", "1.125em"],
|
||||
["border-radius", "50%"],
|
||||
["box-sizing", "border-box"],
|
||||
["z-index", "1"],
|
||||
["transform", "translate(-50%, -50%)"],
|
||||
["border", "1.5px dotted #c83c28"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-nasal-indicator"],
|
||||
"styles": [
|
||||
["display", "block"],
|
||||
["position", "absolute"],
|
||||
["right", "-0.125em"],
|
||||
["top", "0.125em"],
|
||||
["width", "0.375em"],
|
||||
["height", "0.375em"],
|
||||
["border-radius", "50%"],
|
||||
["box-sizing", "border-box"],
|
||||
["z-index", "1"],
|
||||
["border", "1.5px solid #c83c28"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-nasal-diacritic"],
|
||||
"styles": [
|
||||
["position", "absolute"],
|
||||
["width", "0"],
|
||||
["height", "0"],
|
||||
["opacity", "0"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-character"],
|
||||
"styles": [
|
||||
["display", "inline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-character-group"],
|
||||
"styles": [
|
||||
["display", "inline-block"],
|
||||
["position", "relative"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-graph"],
|
||||
"styles": [
|
||||
["display", "inline-block"],
|
||||
["vertical-align", "middle"],
|
||||
["height", "1.5em"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".pronunciation-graph-line",
|
||||
".pronunciation-graph-line-tail"
|
||||
],
|
||||
"styles": [
|
||||
["fill", "none"],
|
||||
["stroke-width", "5"],
|
||||
["stroke", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-graph-line-tail"],
|
||||
"styles": [
|
||||
["stroke-dasharray", "5 5"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-graph-dot"],
|
||||
"styles": [
|
||||
["stroke-width", "5"],
|
||||
["fill", "currentColor"],
|
||||
["stroke", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-graph-dot-downstep1"],
|
||||
"styles": [
|
||||
["fill", "none"],
|
||||
["stroke-width", "5"],
|
||||
["stroke", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-graph-dot-downstep2"],
|
||||
"styles": [
|
||||
["fill", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".pronunciation-graph-triangle"],
|
||||
"styles": [
|
||||
["fill", "none"],
|
||||
["stroke-width", "5"],
|
||||
["stroke", "currentColor"]
|
||||
]
|
||||
}
|
||||
]
|
||||
901
vendor/yomitan/data/recommended-dictionaries.json
vendored
Normal file
901
vendor/yomitan/data/recommended-dictionaries.json
vendored
Normal file
@@ -0,0 +1,901 @@
|
||||
{
|
||||
"afb": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-afb-en",
|
||||
"description": "Gulf Arabic to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-afb-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"aii": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [
|
||||
{
|
||||
"name": "kty-aii-en-ipa",
|
||||
"description": "Assyrian Neo-Aramaic IPA dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-aii-en-ipa.zip"
|
||||
}
|
||||
],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-aii-en",
|
||||
"description": "Assyrian Neo-Aramaic to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-aii-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ang": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-ang-en",
|
||||
"description": "Old English to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ang-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ar": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [
|
||||
{
|
||||
"name": "kty-ar-en-ipa",
|
||||
"description": "Arabic IPA dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ar-en-ipa.zip"
|
||||
}
|
||||
],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-ar-en",
|
||||
"description": "Arabic to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ar-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"arz": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [
|
||||
{
|
||||
"name": "kty-ar-en-ipa",
|
||||
"description": "Arabic IPA dictionary created from Wiktionary data.",
|
||||
"homepage": "https://github.com/yomidevs/kaikki-to-yomitan/blob/master/downloads.md",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ar-en-ipa.zip"
|
||||
}
|
||||
],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-ar-en",
|
||||
"description": "Arabic to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://github.com/yomidevs/kaikki-to-yomitan/blob/master/downloads.md",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ar-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cs": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-cs-en",
|
||||
"description": "Czech to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-cs-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"de": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-de-en",
|
||||
"description": "German to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-de-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"el": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-el-en",
|
||||
"description": "Greek to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-el-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"en": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-en-en",
|
||||
"description": "English to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-en-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enm": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-enm-en",
|
||||
"description": "Middle English to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-enm-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"eo": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-eo-en",
|
||||
"description": "Esperanto to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-eo-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"es": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-es-en",
|
||||
"description": "Spanish to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-es-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fa": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-fa-en",
|
||||
"description": "Persian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-fa-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fi": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-fi-en",
|
||||
"description": "Finnish to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-fi-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"fr": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-fr-en",
|
||||
"description": "French to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-fr-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"grc": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-grc-en",
|
||||
"description": "Ancient Greek to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-grc-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"haw": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "pukui-elbert-1986",
|
||||
"description": "English to Hawaiian Dictionary from Pukui-Elbert in 1986",
|
||||
"homepage": "https://github.com/bee-san/awesome-hawaiian-language",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-hawaiian-language/releases/download/0.0.1/Pukui-Elbert-1986-Deduped-Yomitan.zip"
|
||||
},
|
||||
{
|
||||
"name": "combined-dictionary",
|
||||
"description": "English to Hawaiian Dictionary from Stephen (Kepano) Trussel",
|
||||
"homepage": "https://github.com/bee-san/awesome-hawaiian-language",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-hawaiian-language/releases/download/0.0.1/Combined-Hawaiian-Dictionary-2020-Mitch-Cleaned.zip"
|
||||
},
|
||||
{
|
||||
"name": "hawaiian-place-names-2002",
|
||||
"description": "Hawaiian Place Names, published 2002",
|
||||
"homepage": "https://github.com/bee-san/awesome-hawaiian-language",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-hawaiian-language/releases/download/0.0.1/Hawaii-place-names-2002-yomitan.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"he": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-he-en",
|
||||
"description": "Hebrew to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-he-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hi": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-hi-en",
|
||||
"description": "Hindi to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-hi-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"hu": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-hu-en",
|
||||
"description": "Hungarian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-hu-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-id-en",
|
||||
"description": "Indonesian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-id-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"it": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-it-en",
|
||||
"description": "Italian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-it-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ja": {
|
||||
"frequency": [
|
||||
{
|
||||
"name": "BCCWJ",
|
||||
"description": "Based on the Balanced Corpus of Contemporary Written Japanese covering books, magazines, newspapers, blogs, forums, textbooks, and legal documents among others.",
|
||||
"homepage": "https://github.com/Kuuuube/yomitan-dictionaries?tab=readme-ov-file#bccwj-suw-luw-combined",
|
||||
"downloadUrl": "https://github.com/Kuuuube/yomitan-dictionaries/releases/download/yomitan-permalink/BCCWJ_SUW_LUW_combined.zip"
|
||||
},
|
||||
{
|
||||
"name": "JPDB",
|
||||
"description": "A frequency dictionary based on the corpus from the online Japanese dictionary and SRS system at https://jpdb.io.",
|
||||
"homepage": "https://github.com/Kuuuube/yomitan-dictionaries?tab=readme-ov-file#jpdb-v22-frequency",
|
||||
"downloadUrl": "https://github.com/Kuuuube/yomitan-dictionaries/releases/download/yomitan-permalink/JPDB_v2.2_Frequency_Kana.zip"
|
||||
},
|
||||
{
|
||||
"name": "Jiten",
|
||||
"description": "A frequency dictionary based on the corpus from the media stats database at https://jiten.moe",
|
||||
"homepage": "https://jiten.moe/other",
|
||||
"downloadUrl": "https://api.jiten.moe/api/frequency-list/download?downloadType=yomitan"
|
||||
}
|
||||
],
|
||||
"grammar": [],
|
||||
"kanji": [
|
||||
{
|
||||
"name": "KANJIDIC",
|
||||
"description": "An English dictionary with readings, meanings, stroke order diagrams, frequency, grade level, JLPT level and frequency of kanji characters.",
|
||||
"homepage": "https://github.com/yomidevs/jmdict-yomitan?tab=readme-ov-file#kanjidic-for-yomitan",
|
||||
"downloadUrl": "https://github.com/yomidevs/jmdict-yomitan/releases/latest/download/KANJIDIC_english.zip"
|
||||
}
|
||||
],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "Jitendex",
|
||||
"description": "A free and openly licensed Japanese-to-English dictionary with example sentences, usage notes, etymology notes, cross references, antonyms, definition notes.",
|
||||
"homepage": "https://jitendex.org",
|
||||
"downloadUrl": "https://github.com/stephenmk/stephenmk.github.io/releases/latest/download/jitendex-yomitan.zip"
|
||||
},
|
||||
{
|
||||
"name": "JMnedict",
|
||||
"description": "A dictionary of Japanese proper names maintained by the Electronic Dictionary Research and Development Group.",
|
||||
"homepage": "https://github.com/yomidevs/jmdict-yomitan?tab=readme-ov-file#jmnedict-for-yomitan",
|
||||
"downloadUrl": "https://github.com/yomidevs/jmdict-yomitan/releases/latest/download/JMnedict.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"km": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-km-en",
|
||||
"description": "Khmer to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-km-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"kn": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-kn-en",
|
||||
"description": "Kannada to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-kn-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ko": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-ko-en",
|
||||
"description": "Korean to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ko-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"la": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-la-en",
|
||||
"description": "Latin to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-la-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"lv": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-lv-en",
|
||||
"description": "Latvian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-lv-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mn": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-mn-en",
|
||||
"description": "Mongolian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-mn-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"mt": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [
|
||||
{
|
||||
"name": "kty-mt-en-ipa",
|
||||
"description": "Maltese IPA dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-mt-en-ipa.zip"
|
||||
}
|
||||
],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-mt-en",
|
||||
"description": "Maltese to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-mt-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"nl": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-nl-en",
|
||||
"description": "Dutch to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-nl-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"no": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-nb-en",
|
||||
"description": "Norwegian Bokmål to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-nb-en.zip"
|
||||
},
|
||||
{
|
||||
"name": "kty-nn-en",
|
||||
"description": "Norwegian Nynorsk to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-nn-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pl": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-pl-en",
|
||||
"description": "Polish to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-pl-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"pt": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-pt-en",
|
||||
"description": "Portuguese to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-pt-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ro": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-ro-en",
|
||||
"description": "Romanian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ro-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ru": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-ru-en",
|
||||
"description": "Russian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-ru-en.zip"
|
||||
},
|
||||
{
|
||||
"name": "opr-ru-en",
|
||||
"description": "OpenRussian is a user-contributed, libre Russian dictionary including the accents, examples, audio, related words and synonyms.",
|
||||
"homepage": "https://github.com/ImenaOphelia/openrussian-to-yomitan",
|
||||
"downloadUrl": "https://github.com/ImenaOphelia/openrussian-to-yomitan/releases/latest/download/opr-ru-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"scn": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-scn-en",
|
||||
"description": "Sicillian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-scn-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sga": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-sga-en",
|
||||
"description": "Old Irish to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-sga-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sh": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-sh-en",
|
||||
"description": "Serbo-Croatian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-sh-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sq": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-sq-en",
|
||||
"description": "Albanian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-sq-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sv": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-sv-en",
|
||||
"description": "Swedish to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-sv-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"th": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-th-en",
|
||||
"description": "Thai to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-th-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tl": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-tl-en",
|
||||
"description": "Tagalog to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-tl-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tok": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "toki-pona-to-chinese",
|
||||
"description": "Toki Pona to Chinese dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-chinese.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-czech",
|
||||
"description": "Toki Pona to Czech dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-czech.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-dutch",
|
||||
"description": "Toki Pona to Dutch dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-dutch.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-english",
|
||||
"description": "Toki Pona to English dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-english.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-esperanto",
|
||||
"description": "Toki Pona to Esperanto dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-esperanto.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-french",
|
||||
"description": "Toki Pona to French dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-french.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-german",
|
||||
"description": "Toki Pona to German dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-german.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-indonesian",
|
||||
"description": "Toki Pona to Indonesian dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-indonesian.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-italian",
|
||||
"description": "Toki Pona to Italian dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-italian.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-polish",
|
||||
"description": "Toki Pona to Polish dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-polish.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-portuguese",
|
||||
"description": "Toki Pona to Portuguese dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-portuguese.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-russian",
|
||||
"description": "Toki Pona to Russian dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-russian.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-slovak",
|
||||
"description": "Toki Pona to Slovak dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-slovak.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-spanish",
|
||||
"description": "Toki Pona to Spanish dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-spanish.zip"
|
||||
},
|
||||
{
|
||||
"name": "toki-pona-to-turkish",
|
||||
"description": "Toki Pona to Turkish dictionary",
|
||||
"homepage": "https://github.com/bee-san/awesome-toki-pona",
|
||||
"downloadUrl": "https://github.com/bee-san/awesome-toki-pona/releases/download/0.0.3/toki-pona-to-turkish.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"tr": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-tr-en",
|
||||
"description": "Turkish to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-tr-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"uk": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-uk-en",
|
||||
"description": "Ukranian to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-uk-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"vi": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "kty-vi-en",
|
||||
"description": "Vietnamese to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-vi-en.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"yue": {
|
||||
"frequency": [
|
||||
{
|
||||
"name": "Words.hk Frequency",
|
||||
"description": "Frequency list of Cantonese terms and honzi provided by words.hk.",
|
||||
"homepage": "https://github.com/MarvNC/wordshk-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/wordshk-yomitan/releases/download/2024-09-17/YUE.Freq.Words.hk.Frequency.zip"
|
||||
}
|
||||
],
|
||||
"grammar": [],
|
||||
"kanji": [
|
||||
{
|
||||
"name": "Words.hk 粵典 漢字",
|
||||
"description": "A free and open Cantonese dictionary with definitions and example sentences in Cantonese and English.",
|
||||
"homepage": "https://github.com/MarvNC/wordshk-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/wordshk-yomitan/releases/download/2025-07-09/Words.hk.Honzi.2025-07-08.zip"
|
||||
}
|
||||
],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "Words.hk 粵典",
|
||||
"description": "A free and open Cantonese dictionary with definitions and example sentences in Cantonese and English.",
|
||||
"homepage": "https://github.com/MarvNC/wordshk-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/wordshk-yomitan/releases/download/2025-07-09/Words.hk.2025-07-08.zip"
|
||||
},
|
||||
{
|
||||
"name": "CC-Canto",
|
||||
"description": "CC-Canto is an open source Cantonese dictionary project created by Pleco, intended to be used alongside the CC-CEDICT dictionary. It provides Cantonese specific words and definitions.",
|
||||
"homepage": "https://github.com/MarvNC/cc-cedict-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/cc-cedict-yomitan/releases/latest/download/CC-Canto.zip"
|
||||
},
|
||||
{
|
||||
"name": "CC-CEDICT Canto",
|
||||
"description": "CC-CEDICT is a continuation of the CEDICT project with the aim to provide a complete downloadable Chinese to English dictionary with pronunciation in pinyin for the Chinese characters. This version includes Cantonese readings provided by Pleco.",
|
||||
"homepage": "https://github.com/MarvNC/cc-cedict-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/cc-cedict-yomitan/releases/latest/download/CC-CEDICT.Canto.zip"
|
||||
},
|
||||
{
|
||||
"name": "Cantodict",
|
||||
"description": "CantoDict was a Cantonese-English dictionary created and maintained by Adam Sheik and public contributors.",
|
||||
"homepage": "https://github.com/MarvNC/yomitan-dictionaries?tab=readme-ov-file#cantodict",
|
||||
"downloadUrl": "https://github.com/MarvNC/yomichan-dictionaries/raw/master/dl/%5BCantonese%5D%20Cantodict.zip"
|
||||
}
|
||||
]
|
||||
},
|
||||
"zh": {
|
||||
"frequency": [],
|
||||
"grammar": [],
|
||||
"kanji": [
|
||||
{
|
||||
"name": "CC-CEDICT",
|
||||
"description": "A free and open Chinese-English dictionary provided by the CC-CEDICT project.",
|
||||
"homepage": "https://github.com/MarvNC/cc-cedict-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/cc-cedict-yomitan/releases/latest/download/CC-CEDICT.Hanzi.zip"
|
||||
}
|
||||
],
|
||||
"pronunciation": [],
|
||||
"terms": [
|
||||
{
|
||||
"name": "CC-CEDICT",
|
||||
"description": "A free and open Chinese-English dictionary provided by the CC-CEDICT project.",
|
||||
"homepage": "https://github.com/MarvNC/cc-cedict-yomitan",
|
||||
"downloadUrl": "https://github.com/MarvNC/cc-cedict-yomitan/releases/latest/download/CC-CEDICT.zip"
|
||||
},
|
||||
{
|
||||
"name": "kty-zh-en",
|
||||
"description": "Chinese to English dictionary created from Wiktionary data.",
|
||||
"homepage": "https://yomidevs.github.io/kaikki-to-yomitan/",
|
||||
"downloadUrl": "https://pub-c3d38cca4dc2403b88934c56748f5144.r2.dev/releases/latest/kty-zh-en.zip"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
862
vendor/yomitan/data/recommended-settings.json
vendored
Normal file
862
vendor/yomitan/data/recommended-settings.json
vendored
Normal file
@@ -0,0 +1,862 @@
|
||||
{
|
||||
"ar": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
}
|
||||
],
|
||||
"arz": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
}
|
||||
],
|
||||
"cs": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"da": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"de": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"el": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.length",
|
||||
"value": 24
|
||||
},
|
||||
"description": "Increase the default scanning length from 16 to 24 characters."
|
||||
}
|
||||
],
|
||||
"en": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "sentenceParsing.terminationCharacters",
|
||||
"value": [
|
||||
{
|
||||
"enabled": true,
|
||||
"character1": "\"",
|
||||
"character2": "\"",
|
||||
"includeCharacterAtStart": false,
|
||||
"includeCharacterAtEnd": false
|
||||
},
|
||||
{
|
||||
"enabled": false,
|
||||
"character1": "'",
|
||||
"character2": "'",
|
||||
"includeCharacterAtStart": false,
|
||||
"includeCharacterAtEnd": false
|
||||
},
|
||||
{
|
||||
"enabled": true,
|
||||
"character1": ".",
|
||||
"character2": null,
|
||||
"includeCharacterAtStart": false,
|
||||
"includeCharacterAtEnd": true
|
||||
},
|
||||
{
|
||||
"enabled": true,
|
||||
"character1": "!",
|
||||
"character2": null,
|
||||
"includeCharacterAtStart": false,
|
||||
"includeCharacterAtEnd": true
|
||||
},
|
||||
{
|
||||
"enabled": true,
|
||||
"character1": "?",
|
||||
"character2": null,
|
||||
"includeCharacterAtStart": false,
|
||||
"includeCharacterAtEnd": true
|
||||
},
|
||||
{
|
||||
"enabled": true,
|
||||
"character1": "…",
|
||||
"character2": null,
|
||||
"includeCharacterAtStart": false,
|
||||
"includeCharacterAtEnd": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "Disable apostrophes as a sentence terminator."
|
||||
}
|
||||
],
|
||||
"eo": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"es": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"fi": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"fr": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.textReplacements.groups",
|
||||
"value": [
|
||||
[
|
||||
{
|
||||
"pattern": "l('|’)",
|
||||
"ignoreCase": true,
|
||||
"replacement": ""
|
||||
},
|
||||
{
|
||||
"pattern": "j('|’)",
|
||||
"ignoreCase": true,
|
||||
"replacement": ""
|
||||
},
|
||||
{
|
||||
"pattern": "d('|’)",
|
||||
"ignoreCase": true,
|
||||
"replacement": ""
|
||||
},
|
||||
{
|
||||
"pattern": "s('|’)",
|
||||
"ignoreCase": true,
|
||||
"replacement": ""
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"description": "Separating the l', j', d', s' from the word."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"he": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"hi": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"hu": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"id": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"it": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"ja": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "character"
|
||||
},
|
||||
"description": "Scan text one character at a time."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "letter"
|
||||
},
|
||||
"description": "Lookup words by letter in the dictionary."
|
||||
}
|
||||
],
|
||||
"ko": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"kn": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"la": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"lv": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"mn": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"nl": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"no": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"pl": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"pt": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"ro": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"ru": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"sga": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"sh": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"sq": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"sv": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"tr": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"uk": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "parsing.enableScanningParser",
|
||||
"value": false
|
||||
},
|
||||
"description": "Turn off Yomitan's internal parser for languages with spaces."
|
||||
}
|
||||
],
|
||||
"vi": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Scan text one word at a time (as opposed to one character)."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "word"
|
||||
},
|
||||
"description": "Lookup whole words in the dictionary."
|
||||
}
|
||||
],
|
||||
"yue": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "character"
|
||||
},
|
||||
"description": "Scan text one character at a time."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "letter"
|
||||
},
|
||||
"description": "Lookup words by letter in the dictionary."
|
||||
}
|
||||
],
|
||||
"zh": [
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "scanning.scanResolution",
|
||||
"value": "character"
|
||||
},
|
||||
"description": "Scan text one character at a time."
|
||||
},
|
||||
{
|
||||
"modification": {
|
||||
"action": "set",
|
||||
"path": "translation.searchResolution",
|
||||
"value": "letter"
|
||||
},
|
||||
"description": "Lookup words by letter in the dictionary."
|
||||
}
|
||||
]
|
||||
}
|
||||
34
vendor/yomitan/data/schemas/custom-audio-list-schema.json
vendored
Normal file
34
vendor/yomitan/data/schemas/custom-audio-list-schema.json
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"$id": "customAudioList",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"audioSources"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "audioSourceList"
|
||||
},
|
||||
"audioSources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"url"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
125
vendor/yomitan/data/schemas/dictionary-index-schema.json
vendored
Normal file
125
vendor/yomitan/data/schemas/dictionary-index-schema.json
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"$id": "dictionaryIndex",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"isoLanguageCode": {
|
||||
"type": "string",
|
||||
"description": "ISO language code (ISO 639-1 where possible, ISO 639-3 otherwise).",
|
||||
"pattern": "^[a-z]{2,3}$"
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"description": "Index file containing information about the data contained in the dictionary.",
|
||||
"required": [
|
||||
"title",
|
||||
"revision"
|
||||
],
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Title of the dictionary."
|
||||
},
|
||||
"revision": {
|
||||
"type": "string",
|
||||
"description": "Revision of the dictionary. This value is displayed, and used to check for dictionary updates."
|
||||
},
|
||||
"minimumYomitanVersion": {
|
||||
"type": "string",
|
||||
"description": "Minimum version of Yomitan that is compatible with this dictionary."
|
||||
},
|
||||
"sequenced": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Whether or not this dictionary contains sequencing information for related terms."
|
||||
},
|
||||
"format": {
|
||||
"type": "integer",
|
||||
"description": "Format of data found in the JSON data files.",
|
||||
"enum": [1, 2, 3]
|
||||
},
|
||||
"version": {
|
||||
"type": "integer",
|
||||
"description": "Alias for format.",
|
||||
"enum": [1, 2, 3]
|
||||
},
|
||||
"author": {
|
||||
"type": "string",
|
||||
"description": "Creator of the dictionary."
|
||||
},
|
||||
"isUpdatable": {
|
||||
"type": "boolean",
|
||||
"const": true,
|
||||
"description": "Whether this dictionary contains links to its latest version."
|
||||
},
|
||||
"indexUrl": {
|
||||
"type": "string",
|
||||
"description": "URL for the index file of the latest revision of the dictionary, used to check for updates."
|
||||
},
|
||||
"downloadUrl": {
|
||||
"type": "string",
|
||||
"description": "URL for the download of the latest revision of the dictionary."
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"description": "URL for the source of the dictionary, displayed in the dictionary details."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of the dictionary data."
|
||||
},
|
||||
"attribution": {
|
||||
"type": "string",
|
||||
"description": "Attribution information for the dictionary data."
|
||||
},
|
||||
"sourceLanguage": {
|
||||
"$ref": "#/definitions/isoLanguageCode",
|
||||
"description": "Language of the terms in the dictionary."
|
||||
},
|
||||
"targetLanguage": {
|
||||
"$ref": "#/definitions/isoLanguageCode",
|
||||
"description": "Main language of the definitions in the dictionary."
|
||||
},
|
||||
"frequencyMode": {
|
||||
"type": "string",
|
||||
"enum": ["occurrence-based", "rank-based"]
|
||||
},
|
||||
"tagMeta": {
|
||||
"type": "object",
|
||||
"description": "Tag information for terms and kanji. This object is obsolete and individual tag files should be used instead.",
|
||||
"additionalProperties": {
|
||||
"type": "object",
|
||||
"description": "Information about a single tag. The object key is the name of the tag.",
|
||||
"properties": {
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "Category for the tag."
|
||||
},
|
||||
"order": {
|
||||
"type": "number",
|
||||
"description": "Sorting order for the tag."
|
||||
},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "Notes for the tag."
|
||||
},
|
||||
"score": {
|
||||
"type": "number",
|
||||
"description": "Score used to determine popularity. Negative values are more rare and positive values are more frequent. This score is also used to sort search results."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"anyOf": [
|
||||
{
|
||||
"required": ["format"]
|
||||
},
|
||||
{
|
||||
"required": ["version"]
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"isUpdatable": ["indexUrl", "downloadUrl"]
|
||||
}
|
||||
}
|
||||
35
vendor/yomitan/data/schemas/dictionary-kanji-bank-v1-schema.json
vendored
Normal file
35
vendor/yomitan/data/schemas/dictionary-kanji-bank-v1-schema.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$id": "dictionaryKanjiBankV1",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "array",
|
||||
"description": "Data file containing kanji information.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Information about a single kanji character.",
|
||||
"minItems": 4,
|
||||
"maxItems": 4,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Kanji character.",
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated onyomi readings for the kanji character. An empty string is treated as no readings."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated kunyomi readings for the kanji character. An empty string is treated as no readings."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated tags for the kanji character. An empty string is treated as no tags."
|
||||
}
|
||||
],
|
||||
"additionalItems": {
|
||||
"type": "string",
|
||||
"description": "A meaning for the kanji character."
|
||||
}
|
||||
}
|
||||
}
|
||||
47
vendor/yomitan/data/schemas/dictionary-kanji-bank-v3-schema.json
vendored
Normal file
47
vendor/yomitan/data/schemas/dictionary-kanji-bank-v3-schema.json
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$id": "dictionaryKanjiBankV3",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "array",
|
||||
"description": "Data file containing kanji information.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Information about a single kanji character.",
|
||||
"minItems": 6,
|
||||
"maxItems": 6,
|
||||
"additionalItems": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Kanji character.",
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated onyomi readings for the kanji character. An empty string is treated as no readings."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated kunyomi readings for the kanji character. An empty string is treated as no readings."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated tags for the kanji character. An empty string is treated as no tags."
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "Array of meanings for the kanji character.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A meaning for the kanji character."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Various stats for the kanji character.",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
52
vendor/yomitan/data/schemas/dictionary-kanji-meta-bank-v3-schema.json
vendored
Normal file
52
vendor/yomitan/data/schemas/dictionary-kanji-meta-bank-v3-schema.json
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"$id": "dictionaryKanjiMetaBankV3",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"frequency": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": ["string", "number"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"displayValue": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "array",
|
||||
"description": "Custom metadata for kanji characters.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Metadata about a single kanji character.",
|
||||
"minItems": 3,
|
||||
"maxItems": 3,
|
||||
"additionalItems": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"const": "freq",
|
||||
"description": "Type of data. \"freq\" corresponds to frequency information."
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/frequency",
|
||||
"description": "Data for the character."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
35
vendor/yomitan/data/schemas/dictionary-tag-bank-v3-schema.json
vendored
Normal file
35
vendor/yomitan/data/schemas/dictionary-tag-bank-v3-schema.json
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"$id": "dictionaryTagBankV3",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "array",
|
||||
"description": "Data file containing tag information for terms and kanji.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Information about a single tag.",
|
||||
"minItems": 5,
|
||||
"maxItems": 5,
|
||||
"additionalItems": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Tag name."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Category for the tag."
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"description": "Sorting order for the tag."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Notes for the tag."
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"description": "Score used to determine popularity. Negative values are more rare and positive values are more frequent. This score is also used to sort search results."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
38
vendor/yomitan/data/schemas/dictionary-term-bank-v1-schema.json
vendored
Normal file
38
vendor/yomitan/data/schemas/dictionary-term-bank-v1-schema.json
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$id": "dictionaryTermBankV1",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "array",
|
||||
"description": "Data file containing term information.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Information about a single term.",
|
||||
"minItems": 5,
|
||||
"maxItems": 5,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The text for the term."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Reading of the term, or an empty string if the reading is the same as the term."
|
||||
},
|
||||
{
|
||||
"type": ["string", "null"],
|
||||
"description": "String of space-separated tags for the definition. An empty string is treated as no tags."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated rule identifiers for the definition which is used to validate delinflection. Valid rule identifiers are: v1: ichidan verb; v5: godan verb; vs: suru verb; vz: zuru verb; vk: kuru verb; adj-i: i-adjective. An empty string corresponds to words which aren't inflected, such as nouns."
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"description": "Score used to determine popularity. Negative values are more rare and positive values are more frequent. This score is also used to sort search results."
|
||||
}
|
||||
],
|
||||
"additionalItems": {
|
||||
"type": "string",
|
||||
"description": "Single definition for the term."
|
||||
}
|
||||
}
|
||||
}
|
||||
593
vendor/yomitan/data/schemas/dictionary-term-bank-v3-schema.json
vendored
Normal file
593
vendor/yomitan/data/schemas/dictionary-term-bank-v3-schema.json
vendored
Normal file
@@ -0,0 +1,593 @@
|
||||
{
|
||||
"$id": "dictionaryTermBankV3",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"structuredContent": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Represents a text node."
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/structuredContent",
|
||||
"description": "An array of child content."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Empty tags.",
|
||||
"required": [
|
||||
"tag"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"const": "br"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/structuredContentData"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Generic container tags.",
|
||||
"required": [
|
||||
"tag"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"enum": ["ruby", "rt", "rp", "table", "thead", "tbody", "tfoot", "tr"]
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/structuredContent"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/structuredContentData"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "Defines the language of an element in the format defined by RFC 5646."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Table tags.",
|
||||
"required": [
|
||||
"tag"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"enum": ["td", "th"]
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/structuredContent"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/structuredContentData"
|
||||
},
|
||||
"colSpan": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"rowSpan": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"style": {
|
||||
"$ref": "#/definitions/structuredContentStyle"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "Defines the language of an element in the format defined by RFC 5646."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Container tags supporting configurable styles.",
|
||||
"required": [
|
||||
"tag"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"enum": ["span", "div", "ol", "ul", "li", "details", "summary"]
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/structuredContent"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/structuredContentData"
|
||||
},
|
||||
"style": {
|
||||
"$ref": "#/definitions/structuredContentStyle"
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Hover text for the element."
|
||||
},
|
||||
"open": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the details element is open by default."
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "Defines the language of an element in the format defined by RFC 5646."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Image tag.",
|
||||
"required": [
|
||||
"tag",
|
||||
"path"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"const": "img"
|
||||
},
|
||||
"data": {
|
||||
"$ref": "#/definitions/structuredContentData"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Path to the image file in the archive."
|
||||
},
|
||||
"width": {
|
||||
"type": "number",
|
||||
"description": "Preferred width of the image.",
|
||||
"minimum": 0
|
||||
},
|
||||
"height": {
|
||||
"type": "number",
|
||||
"description": "Preferred height of the image.",
|
||||
"minimum": 0
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Hover text for the image."
|
||||
},
|
||||
"alt": {
|
||||
"type": "string",
|
||||
"description": "Alt text for the image."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of the image."
|
||||
},
|
||||
"pixelated": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.",
|
||||
"default": false
|
||||
},
|
||||
"imageRendering": {
|
||||
"type": "string",
|
||||
"description": "Controls how the image is rendered. The value of this field supersedes the pixelated field.",
|
||||
"enum": ["auto", "pixelated", "crisp-edges"],
|
||||
"default": "auto"
|
||||
},
|
||||
"appearance": {
|
||||
"type": "string",
|
||||
"description": "Controls the appearance of the image. The \"monochrome\" value will mask the opaque parts of the image using the current text color.",
|
||||
"enum": ["auto", "monochrome"],
|
||||
"default": "auto"
|
||||
},
|
||||
"background": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not a background color is displayed behind the image.",
|
||||
"default": true
|
||||
},
|
||||
"collapsed": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the image is collapsed by default.",
|
||||
"default": false
|
||||
},
|
||||
"collapsible": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the image can be collapsed.",
|
||||
"default": false
|
||||
},
|
||||
"verticalAlign": {
|
||||
"type": "string",
|
||||
"description": "The vertical alignment of the image.",
|
||||
"enum": ["baseline", "sub", "super", "text-top", "text-bottom", "middle", "top", "bottom"]
|
||||
},
|
||||
"border": {
|
||||
"type": "string",
|
||||
"description": "Shorthand for border width, style, and color."
|
||||
},
|
||||
"borderRadius": {
|
||||
"type": "string",
|
||||
"description": "Roundness of the corners of the image's outer border edge."
|
||||
},
|
||||
"sizeUnits": {
|
||||
"type": "string",
|
||||
"description": "The units for the width and height.",
|
||||
"enum": ["px", "em"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Link tag.",
|
||||
"required": [
|
||||
"tag",
|
||||
"href"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"tag": {
|
||||
"type": "string",
|
||||
"const": "a"
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/structuredContent"
|
||||
},
|
||||
"href": {
|
||||
"type": "string",
|
||||
"description": "The URL for the link. URLs starting with a ? are treated as internal links to other dictionary content.",
|
||||
"pattern": "^(?:https?:|\\?)[\\w\\W]*"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string",
|
||||
"description": "Defines the language of an element in the format defined by RFC 5646."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"structuredContentData": {
|
||||
"type": "object",
|
||||
"description": "Generic data attributes that should be added to the element.",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"structuredContentStyle": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"fontStyle": {
|
||||
"type": "string",
|
||||
"enum": ["normal", "italic"],
|
||||
"default": "normal"
|
||||
},
|
||||
"fontWeight": {
|
||||
"type": "string",
|
||||
"enum": ["normal", "bold"],
|
||||
"default": "normal"
|
||||
},
|
||||
"fontSize": {
|
||||
"type": "string",
|
||||
"default": "medium"
|
||||
},
|
||||
"color": {
|
||||
"type": "string"
|
||||
},
|
||||
"background": {
|
||||
"type": "string"
|
||||
},
|
||||
"backgroundColor": {
|
||||
"type": "string"
|
||||
},
|
||||
"textDecorationLine": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["none", "underline", "overline", "line-through"],
|
||||
"default": "none"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["underline", "overline", "line-through"],
|
||||
"default": "none"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"textDecorationStyle": {
|
||||
"type": "string",
|
||||
"enum": ["solid", "double", "dotted", "dashed", "wavy"],
|
||||
"default": "solid"
|
||||
},
|
||||
"textDecorationColor": {
|
||||
"type": "string"
|
||||
},
|
||||
"borderColor": {
|
||||
"type": "string"
|
||||
},
|
||||
"borderStyle": {
|
||||
"type": "string"
|
||||
},
|
||||
"borderRadius": {
|
||||
"type": "string"
|
||||
},
|
||||
"borderWidth": {
|
||||
"type": "string"
|
||||
},
|
||||
"clipPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"verticalAlign": {
|
||||
"type": "string",
|
||||
"enum": ["baseline", "sub", "super", "text-top", "text-bottom", "middle", "top", "bottom"],
|
||||
"default": "baseline"
|
||||
},
|
||||
"textAlign": {
|
||||
"type": "string",
|
||||
"enum": ["start", "end", "left", "right", "center", "justify", "justify-all", "match-parent"],
|
||||
"default": "start"
|
||||
},
|
||||
"textEmphasis": {
|
||||
"type": "string"
|
||||
},
|
||||
"textShadow": {
|
||||
"type": "string"
|
||||
},
|
||||
"margin": {
|
||||
"type": "string"
|
||||
},
|
||||
"marginTop": {
|
||||
"type": ["number", "string"],
|
||||
"default": 0
|
||||
},
|
||||
"marginLeft": {
|
||||
"type": ["number", "string"],
|
||||
"default": 0
|
||||
},
|
||||
"marginRight": {
|
||||
"type": ["number", "string"],
|
||||
"default": 0
|
||||
},
|
||||
"marginBottom": {
|
||||
"type": ["number", "string"],
|
||||
"default": 0
|
||||
},
|
||||
"padding": {
|
||||
"type": "string"
|
||||
},
|
||||
"paddingTop": {
|
||||
"type": "string"
|
||||
},
|
||||
"paddingLeft": {
|
||||
"type": "string"
|
||||
},
|
||||
"paddingRight": {
|
||||
"type": "string"
|
||||
},
|
||||
"paddingBottom": {
|
||||
"type": "string"
|
||||
},
|
||||
"wordBreak": {
|
||||
"type": "string",
|
||||
"enum": ["normal", "break-all", "keep-all"],
|
||||
"default": "normal"
|
||||
},
|
||||
"whiteSpace": {
|
||||
"type": "string",
|
||||
"default": "normal"
|
||||
},
|
||||
"cursor": {
|
||||
"type": "string",
|
||||
"default": "auto"
|
||||
},
|
||||
"listStyleType": {
|
||||
"type": "string",
|
||||
"default": "disc"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "array",
|
||||
"description": "Data file containing term information.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Information about a single term.",
|
||||
"minItems": 8,
|
||||
"maxItems": 8,
|
||||
"additionalItems": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The text for the term."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Reading of the term, or an empty string if the reading is the same as the term."
|
||||
},
|
||||
{
|
||||
"type": ["string", "null"],
|
||||
"description": "String of space-separated tags for the definition. An empty string is treated as no tags."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated rule identifiers for the definition which is used to validate deinflection. An empty string should be used for words which aren't inflected."
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"description": "Score used to determine popularity. Negative values are more rare and positive values are more frequent. This score is also used to sort search results."
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "Array of definitions for the term.",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Single definition for the term."
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Single detailed definition for the term.",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "The type of the data for this definition.",
|
||||
"enum": ["text", "image", "structured-content"]
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"type",
|
||||
"text"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "text"
|
||||
},
|
||||
"text": {
|
||||
"type": "string",
|
||||
"description": "Single definition for the term."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"type",
|
||||
"content"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "structured-content"
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/structuredContent",
|
||||
"description": "Single definition for the term using a structured content object."
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"type",
|
||||
"path"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "image"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Path to the image file in the archive."
|
||||
},
|
||||
"width": {
|
||||
"type": "integer",
|
||||
"description": "Preferred width of the image.",
|
||||
"minimum": 1
|
||||
},
|
||||
"height": {
|
||||
"type": "integer",
|
||||
"description": "Preferred height of the image.",
|
||||
"minimum": 1
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"description": "Hover text for the image."
|
||||
},
|
||||
"alt": {
|
||||
"type": "string",
|
||||
"description": "Alt text for the image."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "Description of the image."
|
||||
},
|
||||
"pixelated": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the image should appear pixelated at sizes larger than the image's native resolution.",
|
||||
"default": false
|
||||
},
|
||||
"imageRendering": {
|
||||
"type": "string",
|
||||
"description": "Controls how the image is rendered. The value of this field supersedes the pixelated field.",
|
||||
"enum": ["auto", "pixelated", "crisp-edges"],
|
||||
"default": "auto"
|
||||
},
|
||||
"appearance": {
|
||||
"type": "string",
|
||||
"description": "Controls the appearance of the image. The \"monochrome\" value will mask the opaque parts of the image using the current text color.",
|
||||
"enum": ["auto", "monochrome"],
|
||||
"default": "auto"
|
||||
},
|
||||
"background": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not a background color is displayed behind the image.",
|
||||
"default": true
|
||||
},
|
||||
"collapsed": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the image is collapsed by default.",
|
||||
"default": false
|
||||
},
|
||||
"collapsible": {
|
||||
"type": "boolean",
|
||||
"description": "Whether or not the image can be collapsed.",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "Deinflection of the term to an uninflected term.",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The uninflected term."
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "A chain of inflection rules that produced the inflected term",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A single inflection rule."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Sequence number for the term. Terms with the same sequence number can be shown together when the \"resultOutputMode\" option is set to \"merge\"."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "String of space-separated tags for the term. An empty string is treated as no tags."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
227
vendor/yomitan/data/schemas/dictionary-term-meta-bank-v3-schema.json
vendored
Normal file
227
vendor/yomitan/data/schemas/dictionary-term-meta-bank-v3-schema.json
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
{
|
||||
"$id": "dictionaryTermMetaBankV3",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"frequency": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": ["string", "number"]
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"value"
|
||||
],
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "number"
|
||||
},
|
||||
"displayValue": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "array",
|
||||
"description": "Custom metadata for terms.",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "Metadata about a single term.",
|
||||
"minItems": 3,
|
||||
"maxItems": 3,
|
||||
"additionalItems": false,
|
||||
"items": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The text for the term."
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": ["freq", "pitch", "ipa"],
|
||||
"description": "Type of data. \"freq\" corresponds to frequency information; \"pitch\" corresponds to pitch information. \"ipa\" corresponds to IPA transcription."
|
||||
},
|
||||
{
|
||||
"description": "Data for the term."
|
||||
}
|
||||
],
|
||||
"oneOf": [
|
||||
{
|
||||
"minItems": 3,
|
||||
"maxItems": 3,
|
||||
"items": [
|
||||
{},
|
||||
{"const": "freq"},
|
||||
{
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/frequency",
|
||||
"description": "Frequency information for the term."
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"reading",
|
||||
"frequency"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"reading": {
|
||||
"type": "string",
|
||||
"description": "Reading for the term."
|
||||
},
|
||||
"frequency": {
|
||||
"$ref": "#/definitions/frequency",
|
||||
"description": "Frequency information for the term."
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"minItems": 3,
|
||||
"maxItems": 3,
|
||||
"items": [
|
||||
{},
|
||||
{"const": "pitch"},
|
||||
{
|
||||
"type": "object",
|
||||
"description": "Pitch accent information for the term.",
|
||||
"required": [
|
||||
"reading",
|
||||
"pitches"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"reading": {
|
||||
"type": "string",
|
||||
"description": "Reading for the term."
|
||||
},
|
||||
"pitches": {
|
||||
"type": "array",
|
||||
"description": "List of different pitch accent information for the term and reading combination.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"position"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"position": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Mora position of the pitch accent downstep. A value of 0 indicates that the word does not have a downstep (heiban).",
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Pitch level of each mora with H representing high and L representing low. For example: HHLL for a 4 mora word.",
|
||||
"pattern": "^[HL]+$"
|
||||
}
|
||||
]
|
||||
},
|
||||
"nasal": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Position of a mora with nasal sound.",
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "Positions of morae with nasal sound.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"devoice": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Position of a mora with devoiced sound.",
|
||||
"minimum": 0
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"description": "Positions of morae with devoiced sound.",
|
||||
"items": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"description": "List of tags for this pitch accent.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Tag for this pitch accent. This typically corresponds to a certain type of part of speech."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"minItems": 3,
|
||||
"maxItems": 3,
|
||||
"items": [
|
||||
{},
|
||||
{"const": "ipa"},
|
||||
{
|
||||
"type": ["object"],
|
||||
"description": "IPA transcription information for the term.",
|
||||
"required": [
|
||||
"reading",
|
||||
"transcriptions"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"reading": {
|
||||
"type": "string",
|
||||
"description": "Reading for the term."
|
||||
},
|
||||
"transcriptions": {
|
||||
"type": "array",
|
||||
"description": "List of different IPA transcription information for the term and reading combination.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"ipa"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ipa": {
|
||||
"type": "string",
|
||||
"description": "IPA transcription for the term."
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"description": "List of tags for this IPA transcription.",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Tag for this IPA transcription."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
1413
vendor/yomitan/data/schemas/options-schema.json
vendored
Normal file
1413
vendor/yomitan/data/schemas/options-schema.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
78
vendor/yomitan/data/schemas/recommended-dictionaries-schema.json
vendored
Normal file
78
vendor/yomitan/data/schemas/recommended-dictionaries-schema.json
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"$id": "recommendedDictionaries",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "Contains data for recommended dictionaries on welcome page.",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.{2,}$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"terms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Dictionary"
|
||||
}
|
||||
},
|
||||
"kanji": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Dictionary"
|
||||
}
|
||||
},
|
||||
"frequency": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Dictionary"
|
||||
}
|
||||
},
|
||||
"grammar": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Dictionary"
|
||||
}
|
||||
},
|
||||
"pronunciation": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Dictionary"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"terms",
|
||||
"kanji",
|
||||
"frequency",
|
||||
"grammar"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"Dictionary": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name",
|
||||
"downloadUrl",
|
||||
"description"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"minLength": 2
|
||||
},
|
||||
"downloadUrl": {
|
||||
"type": "string",
|
||||
"minLength": 2
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"minLength": 2
|
||||
},
|
||||
"homepage": {
|
||||
"type": "string",
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
180
vendor/yomitan/data/schemas/recommended-settings-schema.json
vendored
Normal file
180
vendor/yomitan/data/schemas/recommended-settings-schema.json
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"$id": "recommendedSettings",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"description": "Contains data for recommended default options overrides by language.",
|
||||
"type": "object",
|
||||
"$defs": {
|
||||
"path": {
|
||||
"type": "string",
|
||||
"minLength": 2
|
||||
},
|
||||
"value": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
{
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "array"
|
||||
},
|
||||
{
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"minLength": 2
|
||||
}
|
||||
},
|
||||
"patternProperties": {
|
||||
"^.{2,}$": {
|
||||
"title": "Language",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"title": "Modification",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"title": "ModificationSet",
|
||||
"properties": {
|
||||
"modification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "set"
|
||||
},
|
||||
"path": {
|
||||
"$ref": "#/$defs/path"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/$defs/value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/$defs/description"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "ModificationDelete",
|
||||
"properties": {
|
||||
"modification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "delete"
|
||||
},
|
||||
"path": {
|
||||
"$ref": "#/$defs/path"
|
||||
},
|
||||
"value": {
|
||||
"$ref": "#/$defs/value"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/$defs/description"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "ModificationSwap",
|
||||
"properties": {
|
||||
"modification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "swap"
|
||||
},
|
||||
"path1": {
|
||||
"$ref": "#/$defs/path"
|
||||
},
|
||||
"path2": {
|
||||
"$ref": "#/$defs/path"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/$defs/description"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "ModificationSplice",
|
||||
"properties": {
|
||||
"modification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "splice"
|
||||
},
|
||||
"path": {
|
||||
"$ref": "#/$defs/path"
|
||||
},
|
||||
"start": {
|
||||
"type": "number"
|
||||
},
|
||||
"deleteCount": {
|
||||
"type": "number"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/$defs/description"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"title": "ModificationPush",
|
||||
"properties": {
|
||||
"modification": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string",
|
||||
"const": "push"
|
||||
},
|
||||
"path": {
|
||||
"$ref": "#/$defs/path"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/value"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"$ref": "#/$defs/description"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
340
vendor/yomitan/data/structured-content-style.json
vendored
Normal file
340
vendor/yomitan/data/structured-content-style.json
vendored
Normal file
@@ -0,0 +1,340 @@
|
||||
[
|
||||
{
|
||||
"selectors": [".gloss-image-container"],
|
||||
"styles": [
|
||||
["display", "inline-block"],
|
||||
["white-space", "nowrap"],
|
||||
["max-width", "100%"],
|
||||
["max-height", "100vh"],
|
||||
["position", "relative"],
|
||||
["vertical-align", "top"],
|
||||
["line-height", "0"],
|
||||
["overflow", "hidden"],
|
||||
["font-size", "1px"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link"],
|
||||
"styles": [
|
||||
["cursor", "inherit"],
|
||||
["display", "inline-block"],
|
||||
["position", "relative"],
|
||||
["line-height", "1"],
|
||||
["max-width", "100%"],
|
||||
["color", "inherit"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-container-overlay"],
|
||||
"styles": [
|
||||
["position", "absolute"],
|
||||
["left", "0"],
|
||||
["top", "0"],
|
||||
["width", "100%"],
|
||||
["height", "100%"],
|
||||
["font-size", "calc(1em * var(--font-size-no-units))"],
|
||||
["line-height", "var(--line-height)"],
|
||||
["display", "table"],
|
||||
["table-layout", "fixed"],
|
||||
["white-space", "normal"],
|
||||
["color", "var(--text-color-light3)"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-has-image=true][data-image-load-state=load-error] .gloss-image-container-overlay::after"],
|
||||
"styles": [
|
||||
["content", "'Image failed to load'"],
|
||||
["display", "table-cell"],
|
||||
["width", "100%"],
|
||||
["height", "100%"],
|
||||
["vertical-align", "middle"],
|
||||
["text-align", "center"],
|
||||
["padding", "0.25em"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-background"],
|
||||
"styles": [
|
||||
["--image", "none"],
|
||||
["position", "absolute"],
|
||||
["left", "0"],
|
||||
["top", "0"],
|
||||
["width", "100%"],
|
||||
["height", "100%"],
|
||||
["-webkit-mask-repeat", "no-repeat"],
|
||||
["-webkit-mask-position", "center center"],
|
||||
["-webkit-mask-mode", "alpha"],
|
||||
["-webkit-mask-size", "contain"],
|
||||
["-webkit-mask-image", "var(--image)"],
|
||||
["mask-repeat", "no-repeat"],
|
||||
["mask-position", "center center"],
|
||||
["mask-mode", "alpha"],
|
||||
["mask-size", "contain"],
|
||||
["mask-image", "var(--image)"],
|
||||
["background-color", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image"],
|
||||
"styles": [
|
||||
["display", "inline-block"],
|
||||
["vertical-align", "top"],
|
||||
["object-fit", "contain"],
|
||||
["border", "none"],
|
||||
["outline", "none"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-has-aspect-ratio=true] .gloss-image"],
|
||||
"styles": [
|
||||
["position", "absolute"],
|
||||
["left", "0"],
|
||||
["top", "0"],
|
||||
["width", "100%"],
|
||||
["height", "100%"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-image-rendering=pixelated] .gloss-image",
|
||||
".gloss-image-link[data-image-rendering=pixelated] .gloss-image-background"
|
||||
],
|
||||
"styles": [
|
||||
["image-rendering", "auto"],
|
||||
["image-rendering", "-moz-crisp-edges"],
|
||||
["image-rendering", "-webkit-optimize-contrast"],
|
||||
["image-rendering", "pixelated"],
|
||||
["image-rendering", "crisp-edges"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-image-rendering=crisp-edges] .gloss-image",
|
||||
".gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background"
|
||||
],
|
||||
"styles": [
|
||||
["image-rendering", "auto"],
|
||||
["image-rendering", "-moz-crisp-edges"],
|
||||
["image-rendering", "-webkit-optimize-contrast"],
|
||||
["image-rendering", "crisp-edges"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
":root[data-browser=firefox] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image",
|
||||
":root[data-browser=firefox] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background",
|
||||
":root[data-browser=firefox-mobile] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image",
|
||||
":root[data-browser=firefox-mobile] .gloss-image-link[data-image-rendering=crisp-edges] .gloss-image-background"
|
||||
],
|
||||
"styles": [
|
||||
["image-rendering", "auto"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-has-aspect-ratio=true] .gloss-image-sizer"],
|
||||
"styles": [
|
||||
["display", "inline-block"],
|
||||
["width", "0"],
|
||||
["vertical-align", "top"],
|
||||
["font-size", "0"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link-text"],
|
||||
"styles": [
|
||||
["display", "none"],
|
||||
["line-height", "var(--line-height)"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link-text::before"],
|
||||
"styles": [
|
||||
["content", "'['"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link-text::after"],
|
||||
"styles": [
|
||||
["content", "']'"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-description"],
|
||||
"styles": [
|
||||
["display", "block"],
|
||||
["white-space", "pre-line"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-appearance=monochrome] .gloss-image"],
|
||||
"styles": [
|
||||
["--shadow-settings", "0 0 0.01px var(--text-color)"],
|
||||
["filter", "grayscale(1) opacity(0.5) drop-shadow(var(--shadow-settings)) drop-shadow(var(--shadow-settings)) saturate(1000%) brightness(1000%)"],
|
||||
["opacity", "0"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-size-units=em] .gloss-image-container"],
|
||||
"styles": [
|
||||
["font-size", "1em"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=baseline]"],
|
||||
"styles": [
|
||||
["vertical-align", "baseline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=sub]"],
|
||||
"styles": [
|
||||
["vertical-align", "sub"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=super]"],
|
||||
"styles": [
|
||||
["vertical-align", "super"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=text-top]"],
|
||||
"styles": [
|
||||
["vertical-align", "top"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=text-bottom]"],
|
||||
"styles": [
|
||||
["vertical-align", "bottom"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=middle]"],
|
||||
"styles": [
|
||||
["vertical-align", "middle"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=top]"],
|
||||
"styles": [
|
||||
["vertical-align", "top"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link[data-vertical-align=bottom]"],
|
||||
"styles": [
|
||||
["vertical-align", "bottom"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-collapsed=true]",
|
||||
":root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true]"
|
||||
],
|
||||
"styles": [
|
||||
["vertical-align", "baseline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-collapsed=true] .gloss-image-container",
|
||||
":root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true] .gloss-image-container"
|
||||
],
|
||||
"styles": [
|
||||
["display", "none"],
|
||||
["position", "absolute"],
|
||||
["left", "0"],
|
||||
["top", "100%"],
|
||||
["z-index", "1"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-link[data-collapsed=true] .gloss-image-container",
|
||||
":root[data-glossary-layout-mode^=compact] .entry:nth-last-of-type(1):not(:nth-of-type(1)) .gloss-image-link[data-collapsible=true] .gloss-image-container",
|
||||
":root[data-glossary-layout-mode^=compact] .definition-item:nth-last-of-type(1) .gloss-image-link[data-collapsible=true] .gloss-image-container"
|
||||
],
|
||||
"styles": [
|
||||
["bottom", "100%"],
|
||||
["top", "auto"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-collapsed=true]:hover .gloss-image-container",
|
||||
".gloss-image-link[data-collapsed=true]:focus .gloss-image-container",
|
||||
":root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true]:hover .gloss-image-container",
|
||||
":root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true]:focus .gloss-image-container"
|
||||
],
|
||||
"styles": [
|
||||
["display", "block"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-collapsed=true] .gloss-image-link-text",
|
||||
":root[data-glossary-layout-mode^=compact] .gloss-image-link[data-collapsible=true] .gloss-image-link-text"
|
||||
],
|
||||
"styles": [
|
||||
["display", "inline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-image-link[data-collapsed=true]~.gloss-image-description",
|
||||
":root[data-glossary-layout-mode^=compact] .gloss-image-description"
|
||||
],
|
||||
"styles": [
|
||||
["display", "inline"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-link-external-icon"],
|
||||
"styles": [
|
||||
["display", "none"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-sc-table-container"],
|
||||
"styles": [
|
||||
["display", "block"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-sc-table"],
|
||||
"styles": [
|
||||
["table-layout", "auto"],
|
||||
["border-collapse", "collapse"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-sc-thead",
|
||||
".gloss-sc-tfoot",
|
||||
".gloss-sc-th"
|
||||
],
|
||||
"styles": [
|
||||
["font-weight", "bold"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [
|
||||
".gloss-sc-th",
|
||||
".gloss-sc-td"
|
||||
],
|
||||
"styles": [
|
||||
["border-style", "solid"],
|
||||
["padding", "0.25em"],
|
||||
["vertical-align", "top"],
|
||||
["border-width", "1px"],
|
||||
["border-color", "currentColor"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"selectors": [".gloss-image-link:not([data-appearance=monochrome]) .gloss-image-background"],
|
||||
"styles": [
|
||||
["display", "none"]
|
||||
]
|
||||
}
|
||||
]
|
||||
30
vendor/yomitan/data/templates/anki-field-templates-upgrade-v10.handlebars
vendored
Normal file
30
vendor/yomitan/data/templates/anki-field-templates-upgrade-v10.handlebars
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{{#*inline "part-of-speech-pretty"}}
|
||||
{{~#if (op "===" . "v1")~}}Ichidan verb
|
||||
{{~else if (op "===" . "v5")~}}Godan verb
|
||||
{{~else if (op "===" . "vk")~}}Kuru verb
|
||||
{{~else if (op "===" . "vs")~}}Suru verb
|
||||
{{~else if (op "===" . "vz")~}}Zuru verb
|
||||
{{~else if (op "===" . "adj-i")~}}I-adjective
|
||||
{{~else if (op "===" . "n")~}}Noun
|
||||
{{~else~}}{{.}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "part-of-speech"}}
|
||||
{{~#scope~}}
|
||||
{{~#if (op "!==" definition.type "kanji")~}}
|
||||
{{~#set "first" true}}{{/set~}}
|
||||
{{~#each definition.expressions~}}
|
||||
{{~#each wordClasses~}}
|
||||
{{~#unless (get (concat "used_" .))~}}
|
||||
{{~> part-of-speech-pretty . ~}}
|
||||
{{~#unless (get "first")}}, {{/unless~}}
|
||||
{{~#set (concat "used_" .) true~}}{{~/set~}}
|
||||
{{~#set "first" false~}}{{~/set~}}
|
||||
{{~/unless~}}
|
||||
{{~/each~}}
|
||||
{{~/each~}}
|
||||
{{~#if (get "first")~}}Unknown{{~/if~}}
|
||||
{{~/if~}}
|
||||
{{~/scope~}}
|
||||
{{/inline}}
|
||||
3
vendor/yomitan/data/templates/anki-field-templates-upgrade-v12.handlebars
vendored
Normal file
3
vendor/yomitan/data/templates/anki-field-templates-upgrade-v12.handlebars
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{{#*inline "search-query"}}
|
||||
{{~#multiLine}}{{context.fullQuery}}{{/multiLine~}}
|
||||
{{/inline}}
|
||||
148
vendor/yomitan/data/templates/anki-field-templates-upgrade-v13.handlebars
vendored
Normal file
148
vendor/yomitan/data/templates/anki-field-templates-upgrade-v13.handlebars
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
{{#*inline "selection-text"}}
|
||||
{{~#if (hasMedia "selectionText")}}{{#getMedia "selectionText"}}{{/getMedia}}{{/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "sentence-furigana"}}
|
||||
{{~#if definition.cloze~}}
|
||||
{{~#if (hasMedia "textFurigana" definition.cloze.sentence)~}}
|
||||
{{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}}
|
||||
{{~else~}}
|
||||
{{definition.cloze.sentence}}
|
||||
{{~/if~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#each glossary}}{{#multiLine}}{{.}}{{/multiLine}}{{/each}}
|
||||
{{=======}}
|
||||
{{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#each glossary}}{{#multiLine}}{{.}}{{/multiLine}}{{#unless @last}} | {{/unless}}{{/each}}
|
||||
{{=======}}
|
||||
{{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{#unless @last}} | {{/unless}}{{/each}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#each glossary}}<li>{{#multiLine}}{{.}}{{/multiLine}}</li>{{/each}}
|
||||
{{=======}}
|
||||
{{#each glossary}}<li>{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}</li>{{/each}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#if definition.audioFileName~}}
|
||||
[sound:{{definition.audioFileName}}]
|
||||
{{~/if~}}
|
||||
{{=======}}
|
||||
{{~#if (hasMedia "audio")~}}
|
||||
[sound:{{#getMedia "audio"}}{{/getMedia}}]
|
||||
{{~/if~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
<img src="{{definition.screenshotFileName}}" />
|
||||
{{=======}}
|
||||
{{~#if (hasMedia "screenshot")~}}
|
||||
<img src="{{#getMedia "screenshot"}}{{/getMedia}}" />
|
||||
{{~/if~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#if definition.clipboardImageFileName~}}
|
||||
<img src="{{definition.clipboardImageFileName}}" />
|
||||
{{~/if~}}
|
||||
{{=======}}
|
||||
{{~#if (hasMedia "clipboardImage")~}}
|
||||
<img src="{{#getMedia "clipboardImage"}}{{/getMedia}}" />
|
||||
{{~/if~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#if definition.clipboardText~}}{{definition.clipboardText}}{{~/if~}}
|
||||
{{=======}}
|
||||
{{~#if (hasMedia "clipboardText")}}{{#getMedia "clipboardText"}}{{/getMedia}}{{/if~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#*inline "pitch-accent-item-downstep-notation"}}
|
||||
{{~#scope~}}
|
||||
<span>
|
||||
{{~#set "style1a"~}}display:inline-block;position:relative;{{~/set~}}
|
||||
{{~#set "style1b"~}}padding-right:0.1em;margin-right:0.1em;{{~/set~}}
|
||||
{{~#set "style2a"~}}display:block;user-select:none;pointer-events:none;position:absolute;top:0.1em;left:0;right:0;height:0;border-top:0.1em solid;{{~/set~}}
|
||||
{{~#set "style2b"~}}right:-0.1em;height:0.4em;border-right:0.1em solid;{{~/set~}}
|
||||
{{~#each (getKanaMorae reading)~}}
|
||||
{{~#set "style1"}}{{#get "style1a"}}{{/get}}{{/set~}}
|
||||
{{~#set "style2"}}{{/set~}}
|
||||
{{~#if (isMoraPitchHigh @index ../position)}}
|
||||
{{~#set "style2"}}{{#get "style2a"}}{{/get}}{{/set~}}
|
||||
{{~#if (op "!" (isMoraPitchHigh (op "+" @index 1) ../position))~}}
|
||||
{{~#set "style1" (op "+" (get "style1") (get "style1b"))}}{{/set~}}
|
||||
{{~#set "style2" (op "+" (get "style2") (get "style2b"))}}{{/set~}}
|
||||
{{~/if~}}
|
||||
{{~/if~}}
|
||||
<span style="{{#get "style1"}}{{/get}}">{{{.}}}<span style="{{#get "style2"}}{{/get}}"></span></span>
|
||||
{{~/each~}}
|
||||
</span>
|
||||
{{~/scope~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item-graph-position-x"}}{{#op "+" 25 (op "*" index 50)}}{{/op}}{{/inline}}
|
||||
{{#*inline "pitch-accent-item-graph-position-y"}}{{#op "+" 25 (op "?:" (isMoraPitchHigh index position) 0 50)}}{{/op}}{{/inline}}
|
||||
{{#*inline "pitch-accent-item-graph-position"}}{{> pitch-accent-item-graph-position-x index=index position=position}} {{> pitch-accent-item-graph-position-y index=index position=position}}{{/inline}}
|
||||
{{#*inline "pitch-accent-item-graph"}}
|
||||
{{~#scope~}}
|
||||
{{~#set "morae" (getKanaMorae reading)}}{{/set~}}
|
||||
{{~#set "morae-count" (property (get "morae") "length")}}{{/set~}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {{#op "+" 50 (op "*" 50 (get "morae-count"))}}{{/op}} 100" style="display:inline-block;height:2em;">
|
||||
<defs>
|
||||
<g id="term-pitch-accent-graph-dot"><circle cx="0" cy="0" r="15" style="fill:#000;stroke:#000;stroke-width:5;" /></g>
|
||||
<g id="term-pitch-accent-graph-dot-downstep"><circle cx="0" cy="0" r="15" style="fill:none;stroke:#000;stroke-width:5;" /><circle cx="0" cy="0" r="5" style="fill:none;stroke:#000;stroke-width:5;" /></g>
|
||||
<g id="term-pitch-accent-graph-triangle"><path d="M0 13 L15 -13 L-15 -13 Z" style="fill:none;stroke:#000;stroke-width:5;" /></g>
|
||||
</defs>
|
||||
<path style="fill:none;stroke:#000;stroke-width:5;" d="
|
||||
{{~#set "cmd" "M"}}{{/set~}}
|
||||
{{~#each (get "morae")~}}
|
||||
{{~#get "cmd"}}{{/get~}}
|
||||
{{~> pitch-accent-item-graph-position index=@index position=../position~}}
|
||||
{{~#set "cmd" "L"}}{{/set~}}
|
||||
{{~/each~}}
|
||||
"></path>
|
||||
<path style="fill:none;stroke:#000;stroke-width:5;stroke-dasharray:5 5;" d="M{{> pitch-accent-item-graph-position index=(op "-" (get "morae-count") 1) position=position}} L{{> pitch-accent-item-graph-position index=(get "morae-count") position=position}}"></path>
|
||||
{{#each (get "morae")}}
|
||||
<use href="{{#if (op "&&" (isMoraPitchHigh @index ../position) (op "!" (isMoraPitchHigh (op "+" @index 1) ../position)))}}#term-pitch-accent-graph-dot-downstep{{else}}#term-pitch-accent-graph-dot{{/if}}" x="{{> pitch-accent-item-graph-position-x index=@index position=../position}}" y="{{> pitch-accent-item-graph-position-y index=@index position=../position}}"></use>
|
||||
{{/each}}
|
||||
<use href="#term-pitch-accent-graph-triangle" x="{{> pitch-accent-item-graph-position-x index=(get "morae-count") position=position}}" y="{{> pitch-accent-item-graph-position-y index=(get "morae-count") position=position}}"></use>
|
||||
</svg>
|
||||
{{~/scope~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item-position"~}}
|
||||
<span>[{{position}}]</span>
|
||||
{{~/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item"}}
|
||||
{{~#if (op "==" format "downstep-notation")~}}
|
||||
{{~> pitch-accent-item-downstep-notation~}}
|
||||
{{~else if (op "==" format "graph")~}}
|
||||
{{~> pitch-accent-item-graph~}}
|
||||
{{~else if (op "==" format "position")~}}
|
||||
{{~> pitch-accent-item-position~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
{{=======}}
|
||||
{{#*inline "pitch-accent-item"}}
|
||||
{{~#pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}}{{~/pronunciation~}}
|
||||
{{/inline}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#*inline "pitch-accents"}}
|
||||
{{~> pitch-accent-list format='downstep-notation'~}}
|
||||
{{/inline}}
|
||||
{{=======}}
|
||||
{{#*inline "pitch-accents"}}
|
||||
{{~> pitch-accent-list format='text'~}}
|
||||
{{/inline}}
|
||||
{{>>>>>>>}}
|
||||
109
vendor/yomitan/data/templates/anki-field-templates-upgrade-v2.handlebars
vendored
Normal file
109
vendor/yomitan/data/templates/anki-field-templates-upgrade-v2.handlebars
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
{{! Pitch Accents }}
|
||||
{{#*inline "pitch-accent-item-downstep-notation"}}
|
||||
{{~#scope~}}
|
||||
<span>
|
||||
{{~#set "style1a"~}}display:inline-block;position:relative;{{~/set~}}
|
||||
{{~#set "style1b"~}}padding-right:0.1em;margin-right:0.1em;{{~/set~}}
|
||||
{{~#set "style2a"~}}display:block;user-select:none;pointer-events:none;position:absolute;top:0.1em;left:0;right:0;height:0;border-top:0.1em solid;{{~/set~}}
|
||||
{{~#set "style2b"~}}right:-0.1em;height:0.4em;border-right:0.1em solid;{{~/set~}}
|
||||
{{~#each (getKanaMorae reading)~}}
|
||||
{{~#set "style1"}}{{#get "style1a"}}{{/get}}{{/set~}}
|
||||
{{~#set "style2"}}{{/set~}}
|
||||
{{~#if (isMoraPitchHigh @index ../position)}}
|
||||
{{~#set "style2"}}{{#get "style2a"}}{{/get}}{{/set~}}
|
||||
{{~#if (op "!" (isMoraPitchHigh (op "+" @index 1) ../position))~}}
|
||||
{{~#set "style1" (op "+" (get "style1") (get "style1b"))}}{{/set~}}
|
||||
{{~#set "style2" (op "+" (get "style2") (get "style2b"))}}{{/set~}}
|
||||
{{~/if~}}
|
||||
{{~/if~}}
|
||||
<span style="{{#get "style1"}}{{/get}}">{{{.}}}<span style="{{#get "style2"}}{{/get}}"></span></span>
|
||||
{{~/each~}}
|
||||
</span>
|
||||
{{~/scope~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item-graph-position-x"}}{{#op "+" 25 (op "*" index 50)}}{{/op}}{{/inline}}
|
||||
{{#*inline "pitch-accent-item-graph-position-y"}}{{#op "+" 25 (op "?:" (isMoraPitchHigh index position) 0 50)}}{{/op}}{{/inline}}
|
||||
{{#*inline "pitch-accent-item-graph-position"}}{{> pitch-accent-item-graph-position-x index=index position=position}} {{> pitch-accent-item-graph-position-y index=index position=position}}{{/inline}}
|
||||
{{#*inline "pitch-accent-item-graph"}}
|
||||
{{~#scope~}}
|
||||
{{~#set "morae" (getKanaMorae reading)}}{{/set~}}
|
||||
{{~#set "morae-count" (property (get "morae") "length")}}{{/set~}}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {{#op "+" 50 (op "*" 50 (get "morae-count"))}}{{/op}} 100" style="display:inline-block;height:2em;">
|
||||
<defs>
|
||||
<g id="term-pitch-accent-graph-dot"><circle cx="0" cy="0" r="15" style="fill:#000;stroke:#000;stroke-width:5;" /></g>
|
||||
<g id="term-pitch-accent-graph-dot-downstep"><circle cx="0" cy="0" r="15" style="fill:none;stroke:#000;stroke-width:5;" /><circle cx="0" cy="0" r="5" style="fill:none;stroke:#000;stroke-width:5;" /></g>
|
||||
<g id="term-pitch-accent-graph-triangle"><path d="M0 13 L15 -13 L-15 -13 Z" style="fill:none;stroke:#000;stroke-width:5;" /></g>
|
||||
</defs>
|
||||
<path style="fill:none;stroke:#000;stroke-width:5;" d="
|
||||
{{~#set "cmd" "M"}}{{/set~}}
|
||||
{{~#each (get "morae")~}}
|
||||
{{~#get "cmd"}}{{/get~}}
|
||||
{{~> pitch-accent-item-graph-position index=@index position=../position~}}
|
||||
{{~#set "cmd" "L"}}{{/set~}}
|
||||
{{~/each~}}
|
||||
"></path>
|
||||
<path style="fill:none;stroke:#000;stroke-width:5;stroke-dasharray:5 5;" d="M{{> pitch-accent-item-graph-position index=(op "-" (get "morae-count") 1) position=position}} L{{> pitch-accent-item-graph-position index=(get "morae-count") position=position}}"></path>
|
||||
{{#each (get "morae")}}
|
||||
<use href="{{#if (op "&&" (isMoraPitchHigh @index ../position) (op "!" (isMoraPitchHigh (op "+" @index 1) ../position)))}}#term-pitch-accent-graph-dot-downstep{{else}}#term-pitch-accent-graph-dot{{/if}}" x="{{> pitch-accent-item-graph-position-x index=@index position=../position}}" y="{{> pitch-accent-item-graph-position-y index=@index position=../position}}"></use>
|
||||
{{/each}}
|
||||
<use href="#term-pitch-accent-graph-triangle" x="{{> pitch-accent-item-graph-position-x index=(get "morae-count") position=position}}" y="{{> pitch-accent-item-graph-position-y index=(get "morae-count") position=position}}"></use>
|
||||
</svg>
|
||||
{{~/scope~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item-position"~}}
|
||||
<span>[{{position}}]</span>
|
||||
{{~/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item"}}
|
||||
{{~#if (op "==" format "downstep-notation")~}}
|
||||
{{~> pitch-accent-item-downstep-notation~}}
|
||||
{{~else if (op "==" format "graph")~}}
|
||||
{{~> pitch-accent-item-graph~}}
|
||||
{{~else if (op "==" format "position")~}}
|
||||
{{~> pitch-accent-item-position~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-item-disambiguation"}}
|
||||
{{~#scope~}}
|
||||
{{~#set "exclusive" (spread exclusiveExpressions exclusiveReadings)}}{{/set~}}
|
||||
{{~#if (op ">" (property (get "exclusive") "length") 0)~}}
|
||||
{{~#set "separator" ""~}}{{/set~}}
|
||||
<em>({{#each (get "exclusive")~}}
|
||||
{{~#get "separator"}}{{/get~}}{{{.}}}
|
||||
{{~/each}} only) </em>
|
||||
{{~/if~}}
|
||||
{{~/scope~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-list"}}
|
||||
{{~#if (op ">" pitchCount 0)~}}
|
||||
{{~#if (op ">" pitchCount 1)~}}<ol>{{~/if~}}
|
||||
{{~#each pitches~}}
|
||||
{{~#each pitches~}}
|
||||
{{~#if (op ">" ../../pitchCount 1)~}}<li>{{~/if~}}
|
||||
{{~> pitch-accent-item-disambiguation~}}
|
||||
{{~> pitch-accent-item format=../../format~}}
|
||||
{{~#if (op ">" ../../pitchCount 1)~}}</li>{{~/if~}}
|
||||
{{~/each~}}
|
||||
{{~/each~}}
|
||||
{{~#if (op ">" pitchCount 1)~}}</ol>{{~/if~}}
|
||||
{{~else~}}
|
||||
No pitch accent data
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accents"}}
|
||||
{{~> pitch-accent-list format='downstep-notation'~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-graphs"}}
|
||||
{{~> pitch-accent-list format='graph'~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "pitch-accent-positions"}}
|
||||
{{~> pitch-accent-list format='position'~}}
|
||||
{{/inline}}
|
||||
{{! End Pitch Accents }}
|
||||
161
vendor/yomitan/data/templates/anki-field-templates-upgrade-v21.handlebars
vendored
Normal file
161
vendor/yomitan/data/templates/anki-field-templates-upgrade-v21.handlebars
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
{{<<<<<<<}}
|
||||
{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}
|
||||
{{=======}}
|
||||
{{formatGlossary ../dictionary .}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#furigana}}{{{.}}}{{/furigana~}}
|
||||
{{=======}}
|
||||
{{~furigana .~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#furigana}}{{{definition}}}{{/furigana}}
|
||||
{{=======}}
|
||||
{{furigana definition}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#furigana expression reading~}}{{~/furigana~}}
|
||||
{{=======}}
|
||||
{{~furigana expression reading~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#furigana expression reading}}{{/furigana~}}
|
||||
{{=======}}
|
||||
{{~furigana expression reading~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}}
|
||||
{{=======}}
|
||||
{{~furiganaPlain .~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}}
|
||||
{{=======}}
|
||||
{{furiganaPlain definition}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#furiganaPlain expression reading~}}{{~/furiganaPlain~}}
|
||||
{{=======}}
|
||||
{{~furiganaPlain expression reading~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#furiganaPlain expression reading}}{{/furiganaPlain~}}
|
||||
{{=======}}
|
||||
{{~furiganaPlain expression reading~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#getMedia "audio"}}{{/getMedia}}
|
||||
{{=======}}
|
||||
{{getMedia "audio"}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#getMedia "screenshot"}}{{/getMedia}}
|
||||
{{=======}}
|
||||
{{getMedia "screenshot"}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#getMedia "clipboardImage"}}{{/getMedia}}
|
||||
{{=======}}
|
||||
{{getMedia "clipboardImage"}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#getMedia "clipboardText"}}{{/getMedia}}
|
||||
{{=======}}
|
||||
{{getMedia "clipboardText"}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#getMedia "selectionText"}}{{/getMedia}}
|
||||
{{=======}}
|
||||
{{getMedia "selectionText"}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}}
|
||||
{{=======}}
|
||||
{{getMedia "textFurigana" definition.cloze.sentence escape=false}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}}{{~/pronunciation~}}
|
||||
{{=======}}
|
||||
{{~pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "any" false}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "any" false~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "any" true}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "any" true~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "previousDictionary" dictionary~}}{{~/set~}}
|
||||
{{=======}}
|
||||
{{~set "previousDictionary" dictionary~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "exclusive" (spread exclusiveExpressions exclusiveReadings)}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "exclusive" (spread exclusiveExpressions exclusiveReadings)~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "separator" ""~}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "separator" ""~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#get "separator"}}{{/get~}}
|
||||
{{=======}}
|
||||
{{~get "separator"~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "found" false}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "found" false~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "found" true}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "found" true~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "first" true}}{{/set~}}
|
||||
{{=======}}
|
||||
{{~set "first" true~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set "first" false~}}{{~/set~}}
|
||||
{{=======}}
|
||||
{{~set "first" false~}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{~#set (concat "used_" .) true~}}{{~/set~}}
|
||||
{{=======}}
|
||||
{{~set (concat "used_" .) true~}}
|
||||
{{>>>>>>>}}
|
||||
92
vendor/yomitan/data/templates/anki-field-templates-upgrade-v24.handlebars
vendored
Normal file
92
vendor/yomitan/data/templates/anki-field-templates-upgrade-v24.handlebars
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
{{#*inline "cloze-body-kana"}}
|
||||
{{~#if definition.cloze}}{{definition.cloze.bodyKana}}{{/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "phonetic-transcriptions"}}
|
||||
{{~#if (op ">" definition.phoneticTranscriptions.length 0)~}}
|
||||
<ul>
|
||||
{{~#each definition.phoneticTranscriptions~}}
|
||||
{{~#each phoneticTranscriptions~}}
|
||||
<li>
|
||||
{{~set "any" false~}}
|
||||
{{~#each tags~}}
|
||||
{{~#if (get "any")}}, {{else}}<i>({{/if~}}
|
||||
{{name}}
|
||||
{{~set "any" true~}}
|
||||
{{~/each~}}
|
||||
{{~#if (get "any")}})</i> {{/if~}}
|
||||
{{ipa~}}
|
||||
</li>
|
||||
{{~/each~}}
|
||||
{{~/each~}}
|
||||
</ul>
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{<<<<<<<}}
|
||||
{{#*inline "conjugation"}}
|
||||
{{~#if definition.reasons~}}
|
||||
{{~#each definition.reasons~}}
|
||||
{{~#if (op ">" @index 0)}} « {{/if~}}
|
||||
{{.}}
|
||||
{{~/each~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
{{=======}}
|
||||
{{#*inline "conjugation"}}
|
||||
{{~#if (op ">" definition.inflectionRuleChainCandidates.length 0)~}}
|
||||
{{~set "multiple" false~}}
|
||||
{{~#if (op ">" definition.inflectionRuleChainCandidates.length 1)~}}
|
||||
{{~set "multiple" true~}}
|
||||
{{~/if~}}
|
||||
{{~#if (get "multiple")~}}<ul>{{/if~}}
|
||||
{{~#each definition.inflectionRuleChainCandidates~}}
|
||||
{{~#if (op ">" inflectionRules.length 0)~}}
|
||||
{{~#if (get "multiple")~}}<li>{{/if~}}
|
||||
{{~#each inflectionRules~}}
|
||||
{{~#if (op ">" @index 0)}} « {{/if~}}
|
||||
{{.}}
|
||||
{{~/each~}}
|
||||
{{~#if (get "multiple")~}}</li>{{/if~}}
|
||||
{{~/if~}}
|
||||
{{~/each~}}
|
||||
{{~#if (get "multiple")~}}</ul>{{/if~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
{{>>>>>>>}}
|
||||
|
||||
{{#*inline "frequency-harmonic-rank"}}
|
||||
{{~#if (op "===" definition.frequencyHarmonic -1) ~}}
|
||||
9999999
|
||||
{{~else ~}}
|
||||
{{definition.frequencyHarmonic}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "frequency-harmonic-occurrence"}}
|
||||
{{~#if (op "===" definition.frequencyHarmonic -1) ~}}
|
||||
0
|
||||
{{~else ~}}
|
||||
{{definition.frequencyHarmonic}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "frequency-average-rank"}}
|
||||
{{~#if (op "===" definition.frequencyAverage -1) ~}}
|
||||
9999999
|
||||
{{~else ~}}
|
||||
{{definition.frequencyAverage}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{#*inline "frequency-average-occurrence"}}
|
||||
{{~#if (op "===" definition.frequencyAverage -1) ~}}
|
||||
0
|
||||
{{~else ~}}
|
||||
{{definition.frequencyAverage}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
|
||||
{{~#*inline "pitch-accent-categories"~}}
|
||||
{{~#each (pitchCategories @root)~}}{{~.~}}{{~#unless @last~}},{{~/unless~}}{{~/each~}}
|
||||
{{~/inline~}}
|
||||
21
vendor/yomitan/data/templates/anki-field-templates-upgrade-v27.handlebars
vendored
Normal file
21
vendor/yomitan/data/templates/anki-field-templates-upgrade-v27.handlebars
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{{<<<<<<<}}
|
||||
{{#*inline "sentence-furigana"}}
|
||||
{{~#if definition.cloze~}}
|
||||
{{~#if (hasMedia "textFurigana" definition.cloze.sentence)~}}
|
||||
{{getMedia "textFurigana" definition.cloze.sentence escape=false}}
|
||||
{{~else~}}
|
||||
{{definition.cloze.sentence}}
|
||||
{{~/if~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
{{=======}}
|
||||
{{#*inline "sentence-furigana"}}
|
||||
{{~#if definition.cloze~}}
|
||||
{{~#if (hasMedia "textFurigana" definition.cloze.sentence)~}}
|
||||
{{{getMedia "textFurigana" definition.cloze.sentence escape=false}}}
|
||||
{{~else~}}
|
||||
{{{definition.cloze.sentence}}}
|
||||
{{~/if~}}
|
||||
{{~/if~}}
|
||||
{{/inline}}
|
||||
{{>>>>>>>}}
|
||||
9
vendor/yomitan/data/templates/anki-field-templates-upgrade-v28.handlebars
vendored
Normal file
9
vendor/yomitan/data/templates/anki-field-templates-upgrade-v28.handlebars
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{{<<<<<<<}}
|
||||
{{#*inline "url"}}
|
||||
<a href="{{definition.url}}">{{definition.url}}</a>
|
||||
{{/inline}}
|
||||
{{=======}}
|
||||
{{~#*inline "url"~}}
|
||||
<a href="{{definition.url}}">{{definition.url}}</a>
|
||||
{{~/inline~}}
|
||||
{{>>>>>>>}}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user