Showing preview only (325K chars total). Download the full file or copy to clipboard to get everything.
Repository: yonatanmgr/mathberet
Branch: master
Commit: 818c54c51df9
Files: 101
Total size: 294.4 KB
Directory structure:
gitextract_iwhcz0fy/
├── .eslintrc
├── .gitattributes
├── .github/
│ └── ISSUE_TEMPLATE/
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .hintrc
├── .prettierrc
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── assets/
│ ├── icons/
│ │ └── uicons.css
│ └── webfonts/
│ └── OFL.txt
├── misc/
│ └── window/
│ ├── LICENSE
│ ├── components/
│ │ ├── ControlButton.tsx
│ │ ├── Titlebar.less
│ │ ├── Titlebar.tsx
│ │ ├── WindowControls.tsx
│ │ └── WindowFrame.tsx
│ ├── titlebarContext.ts
│ ├── titlebarContextApi.ts
│ ├── titlebarIPC.ts
│ ├── titlebarMenus.ts
│ └── windowPreload.ts
├── package.json
├── src/
│ ├── common/
│ │ ├── helpers.ts
│ │ ├── i18n.ts
│ │ ├── keybindings.ts
│ │ ├── locals/
│ │ │ ├── ar.ts
│ │ │ ├── en.ts
│ │ │ ├── es.ts
│ │ │ ├── fr.ts
│ │ │ ├── he.ts
│ │ │ ├── hi.ts
│ │ │ ├── ru.ts
│ │ │ └── zh.ts
│ │ └── shortcuts.ts
│ ├── main/
│ │ ├── Onboarding.js
│ │ ├── app.ts
│ │ └── appWindow.ts
│ ├── renderer/
│ │ ├── app.html
│ │ ├── appPreload.tsx
│ │ ├── appRenderer.tsx
│ │ ├── common/
│ │ │ └── types.ts
│ │ ├── components/
│ │ │ ├── Application.scss
│ │ │ ├── Application.tsx
│ │ │ ├── CommandBar/
│ │ │ │ ├── CommandBar.scss
│ │ │ │ └── CommandBar.tsx
│ │ │ ├── FilesSidebar/
│ │ │ │ ├── FileSystem.scss
│ │ │ │ ├── FileSystem.tsx
│ │ │ │ ├── FileSystemHelpers.ts
│ │ │ │ ├── FilesSidebar.scss
│ │ │ │ ├── FilesSidebar.tsx
│ │ │ │ ├── SidebarButton.tsx
│ │ │ │ └── types.ts
│ │ │ ├── Fonts.css
│ │ │ ├── GeneralContext.tsx
│ │ │ ├── Header/
│ │ │ │ ├── AddTag.tsx
│ │ │ │ ├── FilePath.tsx
│ │ │ │ ├── Header.scss
│ │ │ │ ├── Header.tsx
│ │ │ │ └── Tag.tsx
│ │ │ ├── Icons.tsx
│ │ │ ├── MathSidebar/
│ │ │ │ ├── ActionsGroup.tsx
│ │ │ │ ├── MathSidebar.scss
│ │ │ │ └── MathSidebar.tsx
│ │ │ ├── Page/
│ │ │ │ ├── Grid/
│ │ │ │ │ ├── Blocks/
│ │ │ │ │ │ ├── Blocks.scss
│ │ │ │ │ │ ├── DrawBlock.tsx
│ │ │ │ │ │ ├── GraphBlock.tsx
│ │ │ │ │ │ ├── MathBlock.tsx
│ │ │ │ │ │ └── TextBlock.tsx
│ │ │ │ │ ├── Grid.scss
│ │ │ │ │ ├── Grid.tsx
│ │ │ │ │ └── GridElement.tsx
│ │ │ │ ├── Page.scss
│ │ │ │ ├── Page.tsx
│ │ │ │ ├── PagePlaceholder.tsx
│ │ │ │ └── ToolsPanel/
│ │ │ │ ├── Tool.tsx
│ │ │ │ ├── ToolsPanel.scss
│ │ │ │ └── ToolsPanel.tsx
│ │ │ ├── Theme.scss
│ │ │ └── common/
│ │ │ ├── Modals/
│ │ │ │ ├── ConfirmModal.scss
│ │ │ │ ├── ConfirmModal.tsx
│ │ │ │ ├── ErrorModal.scss
│ │ │ │ └── ErrorModal.tsx
│ │ │ ├── Notification.scss
│ │ │ ├── Notification.tsx
│ │ │ └── Shortcut.tsx
│ │ └── hooks/
│ │ ├── useAddBlock.tsx
│ │ ├── useDialog.tsx
│ │ ├── useFileSaveLoad.tsx
│ │ └── useSettings.tsx
│ └── typings/
│ └── index.d.ts
├── tools/
│ ├── forge/
│ │ └── forge.config.js
│ └── webpack/
│ ├── webpack.aliases.js
│ ├── webpack.helpers.js
│ ├── webpack.main.js
│ ├── webpack.plugins.js
│ ├── webpack.renderer.js
│ └── webpack.rules.js
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc
================================================
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:import/errors",
"plugin:import/warnings"
],
"parser": "@typescript-eslint/parser",
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
},
"alias": {
"map": [
["@renderer", "./src/renderer"],
["@components", "./src/renderer/components"],
["@common", "./src/common"],
["@main", "./src/main"],
["@src", "./src"],
["@misc", "./misc"],
["@assets", "./assets"]
],
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
},
"react": {
"version": "latest"
}
},
"rules": {
"react/prop-types": "off",
"@typescript-eslint/no-var-requires": "off"
}
}
================================================
FILE: .gitattributes
================================================
*.scss linguist-detectable=false
*.sass linguist-detectable=false
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Windows, macOS, Linux]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
.DS_Store
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Webpack
.webpack/
# Electron-Forge
out/
================================================
FILE: .hintrc
================================================
{
"extends": [
"development"
],
"hints": {
"axe/text-alternatives": [
"default",
{
"image-alt": "off"
}
],
"meta-viewport": "off",
"no-inline-styles": "off",
"axe/name-role-value": [
"default",
{
"button-name": "off"
}
],
"typescript-config/strict": "off"
},
"browserslist": [
"defaults",
"not ie 11",
"not and_ff <= 107",
"not firefox <= 109",
"not ios_saf <= 16.2",
"not safari <= 16.2"
]
}
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true,
"trailingComma": "all",
"jsxSingleQuote": true
}
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
Repository Discussions.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Mathberet
Thank you for investing your time in contributing to our project!
Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
<br>
## How to Contribute?
You can contribute to our project by providing `features/bugfixes/improvements` related Pull Requests.
<br>
Just make sure to test all the changes you provide before submission anything into this project.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2023 Mathberet
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.
================================================
FILE: README.md
================================================
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/yonatanmgr/mathberet/assets/31913495/380ecf5e-5449-4646-ab4d-ac305bc96286">
<source media="(prefers-color-scheme: light)" srcset="https://github.com/yonatanmgr/mathberet/assets/31913495/557554da-7617-4b1b-b34b-79d4e34b4c78">
<img width=500 src="https://github.com/yonatanmgr/mathberet/assets/31913495/380ecf5e-5449-4646-ab4d-ac305bc96286" alt="mathberet logo">
</picture>
<p><b>📝 Mathberet (Hebrew: מַתְבֶּרֶת)</b> - A self-hosted digital mathematics notebook, written in React and built with Electron</p>
<p><b>🚧 In active development, open for contributions! 🚧</b></p>
</div>
---
> Currently works in Hebrew, English, Arabic, Russian and Spanish, localized using [i18next](https://github.com/i18next/i18next). Still buggy.
## :white_check_mark: Features
- [x] Block based drag-n-drop editor
- [x] Text, Math, Graph and Drawing blocks are currently available
- [x] LaTeX shortcuts and snippets
- [x] Local files can be saved and loaded from the file system
- [x] File tags (currently useless)
- [x] Command bar (currently only used for user preferences)
- [x] 6 color themes and light/dark theme
- [ ] Customize LaTeX shortcuts
- [ ] Shortcuts help menu
- [ ] Searching from command bar
- [ ] Adding points and polygons to graph blocks
- [ ] Math memory sidebar (for variable assignments and quick functions)
- [ ] Archive
## :camera_flash: Screenshots
### Hebrew

</details>
### English
<details><summary><b>Dark theme and purple accent color</b></summary>

</details>
<details><summary><b>Light theme and green accent color</b></summary>

</details>
<details><summary><b>Command bar (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>)</b></summary>

</details>
## :bricks: Built With
- [ERWT](https://github.com/codesbiome/electron-react-webpack-typescript-2023): Electron + React apps boilerplate
- [react-grid-layout](https://github.com/react-grid-layout/react-grid-layout): Grid layout for the blocks
- [slate](https://github.com/ianstormtaylor/slate): Text block component
- [MathLive](https://cortexjs.io/mathlive/) ([react-math-view](https://github.com/arnog/react-mathlive)): Math block component
- [Mafs](https://mafs.dev/): Graph block component
- [tldraw](https://github.com/tldraw/tldraw): Drawing block component
- [kbar](https://kbar.vercel.app/): Command bar
- [react-complex-tree](https://rct.lukasbach.com/): Used for displaying the file system
- [UIcons](https://github.com/freepik-company/flaticon-uicons): App icons
## :building_construction: Building from source
1. Clone the repository to a folder on your machine:
```bash
git clone https://github.com/yonatanmgr/mathberet.git
```
2. Run `npm install` in the project root folder
3. Run `npm start` in the project root folder
## :handshake: Contributing
We welcome any positive contribution towards our project's growth! Whether you choose to work on a [listed feature](https://github.com/yonatanmgr/mathberet#white_check_mark-features) or create a new one, your help is appreciated. Simply submit a Pull Request after adding your code. To ensure a smooth process, please review our `CODE OF CONDUCT` and read the `CONTRIBUTING` guidelines for further details on submitting pull requests.
Make sure to visit Mathberet's [project](https://github.com/users/yonatanmgr/projects/2) to view our roadmap and plans, and our [wiki](https://github.com/yonatanmgr/mathberet/wiki/%F0%9F%8F%A0-Home) to read the documentation!
## :balance_scale: Liscense
This project is licensed under the MIT License - see the `LICENSE` file for details.
## :technologist: Contributors
<table>
<tbody>
<tr>
<td align="center"><a href="https://github.com/yonatanmgr"><img src="https://avatars.githubusercontent.com/u/31913495?v=3?s=100" width="100px;" alt="Yonatan Magier"/><br /><sub><b>Yonatan Magier</b></sub></a><br />
<span title="Ideas & Planning">🤔</span>
<a href="https://github.com/yonatanmgr/mathberet/commits?author=yonatanmgr" title="Code">💻</a>
<a href="https://github.com/yonatanmgr/mathberet/commits?author=yonatanmgr" title="Maintenance">🚧</a>
<a href="https://github.com/yonatanmgr/mathberet/tree/master/src/common/locals" title="Translation">🌍</a>
<span title="Design">🎨</span>
</td>
<td align="center"><a href="https://github.com/ErezBiren"><img src="https://avatars.githubusercontent.com/u/7828909?v=3?s=100" width="100px;" alt="Erez Birenholz"/><br /><sub><b>Erez Birenholz</b></sub></a><br />
<span title="Mentoring">🧑🏫</span>
<a href="https://github.com/yonatanmgr/mathberet/commits?author=ErezBiren" title="Code">💻</a>
<a href="https://github.com/yonatanmgr/mathberet/commits?author=ErezBiren" title="Maintenance">🚧</a>
<a href="https://github.com/yonatanmgr/mathberet/tree/master/src/common/locals" title="Translation">🌍</a>
</td>
<td align="center"><a href="https://github.com/Nadav0077"><img src="https://avatars.githubusercontent.com/u/18245584?v=3?s=100" width="100px;" alt="Nadav Magier"/><br /><sub><b>Nadav Magier</b></sub></a><br />
<a href="https://github.com/yonatanmgr/mathberet/commits?author=Nadav0077" title="Code">💻</a>
<a href="https://github.com/yonatanmgr/mathberet/commits?author=Nadav0077" title="Maintenance">🚧</a>
<a href="https://github.com/yonatanmgr/mathberet/tree/master/src/common/locals" title="Translation">🌍</a>
<span title="Security">🛡️</span>
</td>
<td align="center"><a href="https://github.com/zivnadel"><img src="https://avatars.githubusercontent.com/u/52624380?v=3?s=100" width="100px;" alt="Ziv Nadel"/><br /><sub><b>Ziv Nadel</b></sub></a><br />
<a href="https://github.com/yonatanmgr/mathberet/commits?author=zivnadel" title="Code">💻</a>
<a href="https://github.com/yonatanmgr/mathberet/commits?author=zivnadel" title="Maintenance">🚧</a>
</td>
</tr>
</tbody>
</table>
================================================
FILE: assets/icons/uicons.css
================================================
@font-face{font-family:uicons-regular-rounded;src:url(../webfonts/uicons-regular-rounded-BG3GDTFR.eot) format("embedded-opentype"),url(../webfonts/uicons-regular-rounded-3OJX2N3K.woff2) format("woff2"),url(../webfonts/uicons-regular-rounded-ATYWIXGY.woff) format("woff")}i[class^=fi-rr-]:before,i[class*=" fi-rr-"]:before,span[class^=fi-rr-]:before,span[class*=fi-rr-]:before{font-family:uicons-regular-rounded!important;font-style:normal;font-weight:400!important;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fi-rr-0:before{content:"\f101"}.fi-rr-1:before{content:"\f102"}.fi-rr-2:before{content:"\f103"}.fi-rr-3:before{content:"\f104"}.fi-rr-4:before{content:"\f105"}.fi-rr-5:before{content:"\f106"}.fi-rr-6:before{content:"\f107"}.fi-rr-7:before{content:"\f108"}.fi-rr-8:before{content:"\f109"}.fi-rr-9:before{content:"\f10a"}.fi-rr-a:before{content:"\f10b"}.fi-rr-acorn:before{content:"\f10c"}.fi-rr-ad:before{content:"\f10d"}.fi-rr-add-document:before{content:"\f10e"}.fi-rr-add-folder:before{content:"\f10f"}.fi-rr-add:before{content:"\f110"}.fi-rr-address-book:before{content:"\f111"}.fi-rr-air-conditioner:before{content:"\f112"}.fi-rr-air-freshener:before{content:"\f113"}.fi-rr-alarm-clock:before{content:"\f114"}.fi-rr-alarm-exclamation:before{content:"\f115"}.fi-rr-alarm-plus:before{content:"\f116"}.fi-rr-alarm-snooze:before{content:"\f117"}.fi-rr-album-circle-plus:before{content:"\f118"}.fi-rr-album-circle-user:before{content:"\f119"}.fi-rr-album-collection:before{content:"\f11a"}.fi-rr-album:before{content:"\f11b"}.fi-rr-align-justify:before{content:"\f11c"}.fi-rr-align-left:before{content:"\f11d"}.fi-rr-ambulance:before{content:"\f11e"}.fi-rr-angle-circle-down:before{content:"\f11f"}.fi-rr-angle-circle-left:before{content:"\f120"}.fi-rr-angle-circle-right:before{content:"\f121"}.fi-rr-angle-circle-up:before{content:"\f122"}.fi-rr-angle-double-left:before{content:"\f123"}.fi-rr-angle-double-right:before{content:"\f124"}.fi-rr-angle-double-small-down:before{content:"\f125"}.fi-rr-angle-double-small-left:before{content:"\f126"}.fi-rr-angle-double-small-right:before{content:"\f127"}.fi-rr-angle-double-small-up:before{content:"\f128"}.fi-rr-angle-down:before{content:"\f129"}.fi-rr-angle-left:before{content:"\f12a"}.fi-rr-angle-right:before{content:"\f12b"}.fi-rr-angle-small-down:before{content:"\f12c"}.fi-rr-angle-small-left:before{content:"\f12d"}.fi-rr-angle-small-right:before{content:"\f12e"}.fi-rr-angle-small-up:before{content:"\f12f"}.fi-rr-angle-square-down:before{content:"\f130"}.fi-rr-angle-square-left:before{content:"\f131"}.fi-rr-angle-square-right:before{content:"\f132"}.fi-rr-angle-square-up:before{content:"\f133"}.fi-rr-angle-up:before{content:"\f134"}.fi-rr-angry:before{content:"\f135"}.fi-rr-animated-icon:before{content:"\f136"}.fi-rr-apartment:before{content:"\f137"}.fi-rr-api:before{content:"\f138"}.fi-rr-apple-crate:before{content:"\f139"}.fi-rr-apple-whole:before{content:"\f13a"}.fi-rr-apps-add:before{content:"\f13b"}.fi-rr-apps-delete:before{content:"\f13c"}.fi-rr-apps-sort:before{content:"\f13d"}.fi-rr-apps:before{content:"\f13e"}.fi-rr-archive:before{content:"\f13f"}.fi-rr-archway:before{content:"\f140"}.fi-rr-arrow-alt-circle-down:before{content:"\f141"}.fi-rr-arrow-alt-circle-left:before{content:"\f142"}.fi-rr-arrow-alt-circle-right:before{content:"\f143"}.fi-rr-arrow-alt-circle-up:before{content:"\f144"}.fi-rr-arrow-alt-down:before{content:"\f145"}.fi-rr-arrow-alt-from-bottom:before{content:"\f146"}.fi-rr-arrow-alt-from-left:before{content:"\f147"}.fi-rr-arrow-alt-from-right:before{content:"\f148"}.fi-rr-arrow-alt-from-top:before{content:"\f149"}.fi-rr-arrow-alt-left:before{content:"\f14a"}.fi-rr-arrow-alt-right:before{content:"\f14b"}.fi-rr-arrow-alt-square-down:before{content:"\f14c"}.fi-rr-arrow-alt-square-left:before{content:"\f14d"}.fi-rr-arrow-alt-square-right:before{content:"\f14e"}.fi-rr-arrow-alt-square-up:before{content:"\f14f"}.fi-rr-arrow-alt-to-bottom:before{content:"\f150"}.fi-rr-arrow-alt-to-left:before{content:"\f151"}.fi-rr-arrow-alt-to-right:before{content:"\f152"}.fi-rr-arrow-alt-to-top:before{content:"\f153"}.fi-rr-arrow-alt-up:before{content:"\f154"}.fi-rr-arrow-circle-down:before{content:"\f155"}.fi-rr-arrow-circle-left:before{content:"\f156"}.fi-rr-arrow-circle-right:before{content:"\f157"}.fi-rr-arrow-circle-up:before{content:"\f158"}.fi-rr-arrow-down-from-dotted-line:before{content:"\f159"}.fi-rr-arrow-down-small-big:before{content:"\f15a"}.fi-rr-arrow-down-to-dotted-line:before{content:"\f15b"}.fi-rr-arrow-down-to-square:before{content:"\f15c"}.fi-rr-arrow-down-triangle-square:before{content:"\f15d"}.fi-rr-arrow-down:before{content:"\f15e"}.fi-rr-arrow-from-bottom:before{content:"\f15f"}.fi-rr-arrow-from-left:before{content:"\f160"}.fi-rr-arrow-from-right:before{content:"\f161"}.fi-rr-arrow-from-top:before{content:"\f162"}.fi-rr-arrow-left-from-line:before{content:"\f163"}.fi-rr-arrow-left:before{content:"\f164"}.fi-rr-arrow-right-to-bracket:before{content:"\f165"}.fi-rr-arrow-right:before{content:"\f166"}.fi-rr-arrow-small-down:before{content:"\f167"}.fi-rr-arrow-small-left:before{content:"\f168"}.fi-rr-arrow-small-right:before{content:"\f169"}.fi-rr-arrow-small-up:before{content:"\f16a"}.fi-rr-arrow-square-down:before{content:"\f16b"}.fi-rr-arrow-square-left:before{content:"\f16c"}.fi-rr-arrow-square-right:before{content:"\f16d"}.fi-rr-arrow-square-up:before{content:"\f16e"}.fi-rr-arrow-to-bottom:before{content:"\f16f"}.fi-rr-arrow-to-left:before{content:"\f170"}.fi-rr-arrow-to-right:before{content:"\f171"}.fi-rr-arrow-to-top:before{content:"\f172"}.fi-rr-arrow-trend-down:before{content:"\f173"}.fi-rr-arrow-trend-up:before{content:"\f174"}.fi-rr-arrow-turn-down-left:before{content:"\f175"}.fi-rr-arrow-turn-down-right:before{content:"\f176"}.fi-rr-arrow-up-from-dotted-line:before{content:"\f177"}.fi-rr-arrow-up-from-square:before{content:"\f178"}.fi-rr-arrow-up-left-from-circle:before{content:"\f179"}.fi-rr-arrow-up-left:before{content:"\f17a"}.fi-rr-arrow-up-right-and-arrow-down-left-from-center:before{content:"\f17b"}.fi-rr-arrow-up-right-from-square:before{content:"\f17c"}.fi-rr-arrow-up-right:before{content:"\f17d"}.fi-rr-arrow-up-small-big:before{content:"\f17e"}.fi-rr-arrow-up-square-triangle:before{content:"\f17f"}.fi-rr-arrow-up-to-dotted-line:before{content:"\f180"}.fi-rr-arrow-up:before{content:"\f181"}.fi-rr-arrows-alt-h:before{content:"\f182"}.fi-rr-arrows-alt-v:before{content:"\f183"}.fi-rr-arrows-alt:before{content:"\f184"}.fi-rr-arrows-cross:before{content:"\f185"}.fi-rr-arrows-from-dotted-line:before{content:"\f186"}.fi-rr-arrows-from-line:before{content:"\f187"}.fi-rr-arrows-h-copy:before{content:"\f188"}.fi-rr-arrows-h:before{content:"\f189"}.fi-rr-arrows-repeat-1:before{content:"\f18a"}.fi-rr-arrows-repeat:before{content:"\f18b"}.fi-rr-arrows-retweet:before{content:"\f18c"}.fi-rr-arrows-to-dotted-line:before{content:"\f18d"}.fi-rr-arrows-to-line:before{content:"\f18e"}.fi-rr-arrows:before{content:"\f18f"}.fi-rr-assept-document:before{content:"\f190"}.fi-rr-assistive-listening-systems:before{content:"\f191"}.fi-rr-asterik:before{content:"\f192"}.fi-rr-at:before{content:"\f193"}.fi-rr-attribution-pen:before{content:"\f194"}.fi-rr-attribution-pencil:before{content:"\f195"}.fi-rr-aubergine:before{content:"\f196"}.fi-rr-audio-description-slash:before{content:"\f197"}.fi-rr-avocado:before{content:"\f198"}.fi-rr-b:before{content:"\f199"}.fi-rr-baby-carriage:before{content:"\f19a"}.fi-rr-background:before{content:"\f19b"}.fi-rr-backpack:before{content:"\f19c"}.fi-rr-bacon:before{content:"\f19d"}.fi-rr-badge-check:before{content:"\f19e"}.fi-rr-badge-dollar:before{content:"\f19f"}.fi-rr-badge-percent:before{content:"\f1a0"}.fi-rr-badge-sheriff:before{content:"\f1a1"}.fi-rr-badge:before{content:"\f1a2"}.fi-rr-bags-shopping:before{content:"\f1a3"}.fi-rr-bahai:before{content:"\f1a4"}.fi-rr-balance-scale-left:before{content:"\f1a5"}.fi-rr-balance-scale-right:before{content:"\f1a6"}.fi-rr-ball:before{content:"\f1a7"}.fi-rr-balloons:before{content:"\f1a8"}.fi-rr-ballot:before{content:"\f1a9"}.fi-rr-ban-bug:before{content:"\f1aa"}.fi-rr-ban:before{content:"\f1ab"}.fi-rr-band-aid:before{content:"\f1ac"}.fi-rr-bank:before{content:"\f1ad"}.fi-rr-barber-shop:before{content:"\f1ae"}.fi-rr-barcode-read:before{content:"\f1af"}.fi-rr-barcode-scan:before{content:"\f1b0"}.fi-rr-barcode:before{content:"\f1b1"}.fi-rr-bars-filter:before{content:"\f1b2"}.fi-rr-bars-progress:before{content:"\f1b3"}.fi-rr-bars-sort:before{content:"\f1b4"}.fi-rr-baseball-alt:before{content:"\f1b5"}.fi-rr-baseball:before{content:"\f1b6"}.fi-rr-basket:before{content:"\f1b7"}.fi-rr-basketball:before{content:"\f1b8"}.fi-rr-battery-bolt:before{content:"\f1b9"}.fi-rr-battery-empty:before{content:"\f1ba"}.fi-rr-battery-full:before{content:"\f1bb"}.fi-rr-battery-half:before{content:"\f1bc"}.fi-rr-battery-quarter:before{content:"\f1bd"}.fi-rr-battery-slash:before{content:"\f1be"}.fi-rr-battery-three-quarters:before{content:"\f1bf"}.fi-rr-beacon:before{content:"\f1c0"}.fi-rr-bed-alt:before{content:"\f1c1"}.fi-rr-bed:before{content:"\f1c2"}.fi-rr-beer:before{content:"\f1c3"}.fi-rr-bell-ring:before{content:"\f1c4"}.fi-rr-bell-school:before{content:"\f1c5"}.fi-rr-bell:before{content:"\f1c6"}.fi-rr-bells:before{content:"\f1c7"}.fi-rr-bench-tree:before{content:"\f1c8"}.fi-rr-betamax:before{content:"\f1c9"}.fi-rr-bike:before{content:"\f1ca"}.fi-rr-biking-mountain:before{content:"\f1cb"}.fi-rr-biking:before{content:"\f1cc"}.fi-rr-billiard:before{content:"\f1cd"}.fi-rr-binary-circle-check:before{content:"\f1ce"}.fi-rr-binary-lock:before{content:"\f1cf"}.fi-rr-binary-slash:before{content:"\f1d0"}.fi-rr-binary:before{content:"\f1d1"}.fi-rr-binoculars:before{content:"\f1d2"}.fi-rr-blinds-open:before{content:"\f1d3"}.fi-rr-blinds-raised:before{content:"\f1d4"}.fi-rr-blinds:before{content:"\f1d5"}.fi-rr-block-brick:before{content:"\f1d6"}.fi-rr-block:before{content:"\f1d7"}.fi-rr-blog-pencil:before{content:"\f1d8"}.fi-rr-blog-text:before{content:"\f1d9"}.fi-rr-bold:before{content:"\f1da"}.fi-rr-bolt:before{content:"\f1db"}.fi-rr-bomb:before{content:"\f1dc"}.fi-rr-bone:before{content:"\f1dd"}.fi-rr-book-alt:before{content:"\f1de"}.fi-rr-book-arrow-right:before{content:"\f1df"}.fi-rr-book-arrow-up:before{content:"\f1e0"}.fi-rr-book-atlas:before{content:"\f1e1"}.fi-rr-book-bookmark:before{content:"\f1e2"}.fi-rr-book-font:before{content:"\f1e3"}.fi-rr-book-open-cover:before{content:"\f1e4"}.fi-rr-book-open-reader:before{content:"\f1e5"}.fi-rr-book:before{content:"\f1e6"}.fi-rr-bookmark:before{content:"\f1e7"}.fi-rr-books:before{content:"\f1e8"}.fi-rr-border-all:before{content:"\f1e9"}.fi-rr-border-bottom:before{content:"\f1ea"}.fi-rr-border-center-h:before{content:"\f1eb"}.fi-rr-border-center-v:before{content:"\f1ec"}.fi-rr-border-inner:before{content:"\f1ed"}.fi-rr-border-left:before{content:"\f1ee"}.fi-rr-border-none:before{content:"\f1ef"}.fi-rr-border-outer:before{content:"\f1f0"}.fi-rr-border-right:before{content:"\f1f1"}.fi-rr-border-style-alt:before{content:"\f1f2"}.fi-rr-border-style:before{content:"\f1f3"}.fi-rr-border-top:before{content:"\f1f4"}.fi-rr-bottle:before{content:"\f1f5"}.fi-rr-bow-arrow:before{content:"\f1f6"}.fi-rr-bowling-ball:before{content:"\f1f7"}.fi-rr-bowling-pins:before{content:"\f1f8"}.fi-rr-bowling:before{content:"\f1f9"}.fi-rr-box-alt:before{content:"\f1fa"}.fi-rr-box-ballot:before{content:"\f1fb"}.fi-rr-box-check:before{content:"\f1fc"}.fi-rr-box-fragile:before{content:"\f1fd"}.fi-rr-box-open-full:before{content:"\f1fe"}.fi-rr-box-open:before{content:"\f1ff"}.fi-rr-box-tissue:before{content:"\f200"}.fi-rr-box-up:before{content:"\f201"}.fi-rr-box:before{content:"\f202"}.fi-rr-boxes:before{content:"\f203"}.fi-rr-boxing-glove:before{content:"\f204"}.fi-rr-bracket-curly-right:before{content:"\f205"}.fi-rr-bracket-curly:before{content:"\f206"}.fi-rr-bracket-round-right:before{content:"\f207"}.fi-rr-bracket-round:before{content:"\f208"}.fi-rr-bracket-square-right:before{content:"\f209"}.fi-rr-bracket-square:before{content:"\f20a"}.fi-rr-brackets-curly:before{content:"\f20b"}.fi-rr-brackets-round:before{content:"\f20c"}.fi-rr-brackets-square:before{content:"\f20d"}.fi-rr-braille:before{content:"\f20e"}.fi-rr-brain-circuit:before{content:"\f20f"}.fi-rr-brain:before{content:"\f210"}.fi-rr-bread-loaf:before{content:"\f211"}.fi-rr-bread-slice:before{content:"\f212"}.fi-rr-bread:before{content:"\f213"}.fi-rr-briefcase:before{content:"\f214"}.fi-rr-brightness-low:before{content:"\f215"}.fi-rr-brightness:before{content:"\f216"}.fi-rr-bring-forward:before{content:"\f217"}.fi-rr-bring-front:before{content:"\f218"}.fi-rr-broccoli:before{content:"\f219"}.fi-rr-broken-image:before{content:"\f21a"}.fi-rr-broom:before{content:"\f21b"}.fi-rr-browser:before{content:"\f21c"}.fi-rr-browsers:before{content:"\f21d"}.fi-rr-brush:before{content:"\f21e"}.fi-rr-bug-slash:before{content:"\f21f"}.fi-rr-bug:before{content:"\f220"}.fi-rr-building:before{content:"\f221"}.fi-rr-bulb:before{content:"\f222"}.fi-rr-bullet:before{content:"\f223"}.fi-rr-bullseye-pointer:before{content:"\f224"}.fi-rr-bullseye:before{content:"\f225"}.fi-rr-burger-alt:before{content:"\f226"}.fi-rr-burger-fries:before{content:"\f227"}.fi-rr-burger-glass:before{content:"\f228"}.fi-rr-burrito:before{content:"\f229"}.fi-rr-bus-alt:before{content:"\f22a"}.fi-rr-bus:before{content:"\f22b"}.fi-rr-business-time:before{content:"\f22c"}.fi-rr-butterfly:before{content:"\f22d"}.fi-rr-c:before{content:"\f22e"}.fi-rr-cabin:before{content:"\f22f"}.fi-rr-cake-birthday:before{content:"\f230"}.fi-rr-cake-wedding:before{content:"\f231"}.fi-rr-calculator:before{content:"\f232"}.fi-rr-calendar-check:before{content:"\f233"}.fi-rr-calendar-clock:before{content:"\f234"}.fi-rr-calendar-exclamation:before{content:"\f235"}.fi-rr-calendar-lines-pen:before{content:"\f236"}.fi-rr-calendar-lines:before{content:"\f237"}.fi-rr-calendar-minus:before{content:"\f238"}.fi-rr-calendar-pen:before{content:"\f239"}.fi-rr-calendar-plus:before{content:"\f23a"}.fi-rr-calendar:before{content:"\f23b"}.fi-rr-calendars:before{content:"\f23c"}.fi-rr-call-history:before{content:"\f23d"}.fi-rr-call-incoming:before{content:"\f23e"}.fi-rr-call-missed:before{content:"\f23f"}.fi-rr-call-outgoing:before{content:"\f240"}.fi-rr-camcorder:before{content:"\f241"}.fi-rr-camera:before{content:"\f242"}.fi-rr-camping:before{content:"\f243"}.fi-rr-candy-alt:before{content:"\f244"}.fi-rr-candy-cane:before{content:"\f245"}.fi-rr-candy-corn:before{content:"\f246"}.fi-rr-candy:before{content:"\f247"}.fi-rr-canned-food:before{content:"\f248"}.fi-rr-car-alt:before{content:"\f249"}.fi-rr-car-battery:before{content:"\f24a"}.fi-rr-car-bolt:before{content:"\f24b"}.fi-rr-car-building:before{content:"\f24c"}.fi-rr-car-bump:before{content:"\f24d"}.fi-rr-car-bus:before{content:"\f24e"}.fi-rr-car-circle-bolt:before{content:"\f24f"}.fi-rr-car-crash:before{content:"\f250"}.fi-rr-car-garage:before{content:"\f251"}.fi-rr-car-mechanic:before{content:"\f252"}.fi-rr-car-side-bolt:before{content:"\f253"}.fi-rr-car-side:before{content:"\f254"}.fi-rr-car-tilt:before{content:"\f255"}.fi-rr-car-wash:before{content:"\f256"}.fi-rr-car:before{content:"\f257"}.fi-rr-caravan-alt:before{content:"\f258"}.fi-rr-caravan:before{content:"\f259"}.fi-rr-caret-circle-down:before{content:"\f25a"}.fi-rr-caret-circle-right:before{content:"\f25b"}.fi-rr-caret-circle-up:before{content:"\f25c"}.fi-rr-caret-down:before{content:"\f25d"}.fi-rr-caret-left:before{content:"\f25e"}.fi-rr-caret-quare-up:before{content:"\f25f"}.fi-rr-caret-right:before{content:"\f260"}.fi-rr-caret-square-down:before{content:"\f261"}.fi-rr-caret-square-left_1:before{content:"\f262"}.fi-rr-caret-square-left:before{content:"\f263"}.fi-rr-caret-square-right:before{content:"\f264"}.fi-rr-caret-up:before{content:"\f265"}.fi-rr-carrot:before{content:"\f266"}.fi-rr-cars:before{content:"\f267"}.fi-rr-cash-register:before{content:"\f268"}.fi-rr-cassette-tape:before{content:"\f269"}.fi-rr-cassette-vhs:before{content:"\f26a"}.fi-rr-castle:before{content:"\f26b"}.fi-rr-chair-office:before{content:"\f26c"}.fi-rr-chair:before{content:"\f26d"}.fi-rr-charging-station:before{content:"\f26e"}.fi-rr-chart-area:before{content:"\f26f"}.fi-rr-chart-bullet:before{content:"\f270"}.fi-rr-chart-candlestick:before{content:"\f271"}.fi-rr-chart-connected:before{content:"\f272"}.fi-rr-chart-gantt:before{content:"\f273"}.fi-rr-chart-histogram:before{content:"\f274"}.fi-rr-chart-line-up:before{content:"\f275"}.fi-rr-chart-mixed:before{content:"\f276"}.fi-rr-chart-network:before{content:"\f277"}.fi-rr-chart-pie-alt:before{content:"\f278"}.fi-rr-chart-pie:before{content:"\f279"}.fi-rr-chart-pyramid:before{content:"\f27a"}.fi-rr-chart-radar:before{content:"\f27b"}.fi-rr-chart-scatter-3d:before{content:"\f27c"}.fi-rr-chart-scatter-bubble:before{content:"\f27d"}.fi-rr-chart-scatter:before{content:"\f27e"}.fi-rr-chart-set-theory:before{content:"\f27f"}.fi-rr-chart-tree:before{content:"\f280"}.fi-rr-chart-waterfall:before{content:"\f281"}.fi-rr-chat-arrow-down:before{content:"\f282"}.fi-rr-chat-arrow-grow:before{content:"\f283"}.fi-rr-check:before{content:"\f284"}.fi-rr-checkbox:before{content:"\f285"}.fi-rr-cheese-alt:before{content:"\f286"}.fi-rr-cheese:before{content:"\f287"}.fi-rr-cherry:before{content:"\f288"}.fi-rr-chess-bishop:before{content:"\f289"}.fi-rr-chess-board:before{content:"\f28a"}.fi-rr-chess-clock-alt:before{content:"\f28b"}.fi-rr-chess-clock:before{content:"\f28c"}.fi-rr-chess-king-alt:before{content:"\f28d"}.fi-rr-chess-king:before{content:"\f28e"}.fi-rr-chess-knight-alt:before{content:"\f28f"}.fi-rr-chess-knight:before{content:"\f290"}.fi-rr-chess-pawn-alt:before{content:"\f291"}.fi-rr-chess-piece:before{content:"\f292"}.fi-rr-chess-queen-alt:before{content:"\f293"}.fi-rr-chess-queen:before{content:"\f294"}.fi-rr-chess-rook-alt:before{content:"\f295"}.fi-rr-chess-rook:before{content:"\f296"}.fi-rr-chess:before{content:"\f297"}.fi-rr-chevron-double-down:before{content:"\f298"}.fi-rr-chevron-double-up:before{content:"\f299"}.fi-rr-child-head:before{content:"\f29a"}.fi-rr-chocolate:before{content:"\f29b"}.fi-rr-circle-0:before{content:"\f29c"}.fi-rr-circle-1:before{content:"\f29d"}.fi-rr-circle-2:before{content:"\f29e"}.fi-rr-circle-3:before{content:"\f29f"}.fi-rr-circle-4:before{content:"\f2a0"}.fi-rr-circle-5:before{content:"\f2a1"}.fi-rr-circle-6:before{content:"\f2a2"}.fi-rr-circle-7:before{content:"\f2a3"}.fi-rr-circle-8:before{content:"\f2a4"}.fi-rr-circle-9:before{content:"\f2a5"}.fi-rr-circle-dashed:before{content:"\f2a6"}.fi-rr-circle-envelope:before{content:"\f2a7"}.fi-rr-circle-half-stroke:before{content:"\f2a8"}.fi-rr-circle-heart:before{content:"\f2a9"}.fi-rr-circle-phone-flip:before{content:"\f2aa"}.fi-rr-circle-phone-hangup:before{content:"\f2ab"}.fi-rr-circle-phone:before{content:"\f2ac"}.fi-rr-circle-small:before{content:"\f2ad"}.fi-rr-circle:before{content:"\f2ae"}.fi-rr-city:before{content:"\f2af"}.fi-rr-clip:before{content:"\f2b0"}.fi-rr-clipboard-list-check:before{content:"\f2b1"}.fi-rr-clipboard-list:before{content:"\f2b2"}.fi-rr-clock-eight-thirty:before{content:"\f2b3"}.fi-rr-clock-eleven-thirty:before{content:"\f2b4"}.fi-rr-clock-eleven:before{content:"\f2b5"}.fi-rr-clock-five-thirty:before{content:"\f2b6"}.fi-rr-clock-five:before{content:"\f2b7"}.fi-rr-clock-four-thirty:before{content:"\f2b8"}.fi-rr-clock-nine-thirty:before{content:"\f2b9"}.fi-rr-clock-nine:before{content:"\f2ba"}.fi-rr-clock-one-thirty:before{content:"\f2bb"}.fi-rr-clock-one:before{content:"\f2bc"}.fi-rr-clock-seven-thirty:before{content:"\f2bd"}.fi-rr-clock-seven:before{content:"\f2be"}.fi-rr-clock-six-thirty:before{content:"\f2bf"}.fi-rr-clock-six:before{content:"\f2c0"}.fi-rr-clock-ten-thirty:before{content:"\f2c1"}.fi-rr-clock-ten:before{content:"\f2c2"}.fi-rr-clock-three-thirty:before{content:"\f2c3"}.fi-rr-clock-three:before{content:"\f2c4"}.fi-rr-clock-twelve-thirty:before{content:"\f2c5"}.fi-rr-clock-twelve:before{content:"\f2c6"}.fi-rr-clock-two-thirty:before{content:"\f2c7"}.fi-rr-clock-two:before{content:"\f2c8"}.fi-rr-clock:before{content:"\f2c9"}.fi-rr-closed-captioning-slash:before{content:"\f2ca"}.fi-rr-cloud-check:before{content:"\f2cb"}.fi-rr-cloud-disabled:before{content:"\f2cc"}.fi-rr-cloud-download-alt:before{content:"\f2cd"}.fi-rr-cloud-download:before{content:"\f2ce"}.fi-rr-cloud-drizzle:before{content:"\f2cf"}.fi-rr-cloud-hail-mixed:before{content:"\f2d0"}.fi-rr-cloud-hail:before{content:"\f2d1"}.fi-rr-cloud-moon-rain:before{content:"\f2d2"}.fi-rr-cloud-moon:before{content:"\f2d3"}.fi-rr-cloud-rain:before{content:"\f2d4"}.fi-rr-cloud-rainbow:before{content:"\f2d5"}.fi-rr-cloud-share:before{content:"\f2d6"}.fi-rr-cloud-showers-heavy:before{content:"\f2d7"}.fi-rr-cloud-showers:before{content:"\f2d8"}.fi-rr-cloud-sleet:before{content:"\f2d9"}.fi-rr-cloud-snow:before{content:"\f2da"}.fi-rr-cloud-sun-rain:before{content:"\f2db"}.fi-rr-cloud-sun:before{content:"\f2dc"}.fi-rr-cloud-upload-alt:before{content:"\f2dd"}.fi-rr-cloud-upload:before{content:"\f2de"}.fi-rr-cloud:before{content:"\f2df"}.fi-rr-clouds-moon:before{content:"\f2e0"}.fi-rr-clouds-sun:before{content:"\f2e1"}.fi-rr-clouds:before{content:"\f2e2"}.fi-rr-club:before{content:"\f2e3"}.fi-rr-cocktail-alt:before{content:"\f2e4"}.fi-rr-cocktail:before{content:"\f2e5"}.fi-rr-code-branch:before{content:"\f2e6"}.fi-rr-code-commit:before{content:"\f2e7"}.fi-rr-code-compare:before{content:"\f2e8"}.fi-rr-code-fork:before{content:"\f2e9"}.fi-rr-code-merge:before{content:"\f2ea"}.fi-rr-code-pull-request-closed:before{content:"\f2eb"}.fi-rr-code-pull-request-draft:before{content:"\f2ec"}.fi-rr-code-pull-request:before{content:"\f2ed"}.fi-rr-code-simple:before{content:"\f2ee"}.fi-rr-coffee-pot:before{content:"\f2ef"}.fi-rr-coffee:before{content:"\f2f0"}.fi-rr-coin:before{content:"\f2f1"}.fi-rr-coins:before{content:"\f2f2"}.fi-rr-comet:before{content:"\f2f3"}.fi-rr-comment-alt-middle-top:before{content:"\f2f4"}.fi-rr-comment-alt-middle:before{content:"\f2f5"}.fi-rr-comment-alt:before{content:"\f2f6"}.fi-rr-comment-arrow-down:before{content:"\f2f7"}.fi-rr-comment-arrow-up-right:before{content:"\f2f8"}.fi-rr-comment-arrow-up:before{content:"\f2f9"}.fi-rr-comment-check:before{content:"\f2fa"}.fi-rr-comment-code:before{content:"\f2fb"}.fi-rr-comment-dollar:before{content:"\f2fc"}.fi-rr-comment-exclamation:before{content:"\f2fd"}.fi-rr-comment-heart:before{content:"\f2fe"}.fi-rr-comment-image:before{content:"\f2ff"}.fi-rr-comment-info:before{content:"\f300"}.fi-rr-comment-pen:before{content:"\f301"}.fi-rr-comment-question:before{content:"\f302"}.fi-rr-comment-quote:before{content:"\f303"}.fi-rr-comment-slash:before{content:"\f304"}.fi-rr-comment-sms:before{content:"\f305"}.fi-rr-comment-text:before{content:"\f306"}.fi-rr-comment-user:before{content:"\f307"}.fi-rr-comment-xmark:before{content:"\f308"}.fi-rr-comment:before{content:"\f309"}.fi-rr-comments-dollar:before{content:"\f30a"}.fi-rr-comments-question-check:before{content:"\f30b"}.fi-rr-comments-question:before{content:"\f30c"}.fi-rr-comments:before{content:"\f30d"}.fi-rr-compress-alt:before{content:"\f30e"}.fi-rr-compress:before{content:"\f30f"}.fi-rr-computer:before{content:"\f310"}.fi-rr-concierge-bell:before{content:"\f311"}.fi-rr-confetti:before{content:"\f312"}.fi-rr-cookie:before{content:"\f313"}.fi-rr-copy-alt:before{content:"\f314"}.fi-rr-copy-image:before{content:"\f315"}.fi-rr-copy:before{content:"\f316"}.fi-rr-copyright:before{content:"\f317"}.fi-rr-corn:before{content:"\f318"}.fi-rr-cow:before{content:"\f319"}.fi-rr-cowbell-more:before{content:"\f31a"}.fi-rr-cowbell:before{content:"\f31b"}.fi-rr-cream:before{content:"\f31c"}.fi-rr-credit-card:before{content:"\f31d"}.fi-rr-cricket:before{content:"\f31e"}.fi-rr-croissant:before{content:"\f31f"}.fi-rr-cross-circle:before{content:"\f320"}.fi-rr-cross-religion:before{content:"\f321"}.fi-rr-cross-small:before{content:"\f322"}.fi-rr-cross:before{content:"\f323"}.fi-rr-crown:before{content:"\f324"}.fi-rr-crystal-ball:before{content:"\f325"}.fi-rr-cube:before{content:"\f326"}.fi-rr-cubes:before{content:"\f327"}.fi-rr-cupcake:before{content:"\f328"}.fi-rr-curling:before{content:"\f329"}.fi-rr-cursor-finger:before{content:"\f32a"}.fi-rr-cursor-plus:before{content:"\f32b"}.fi-rr-cursor-text-alt:before{content:"\f32c"}.fi-rr-cursor-text:before{content:"\f32d"}.fi-rr-cursor:before{content:"\f32e"}.fi-rr-d:before{content:"\f32f"}.fi-rr-dart:before{content:"\f330"}.fi-rr-dashboard:before{content:"\f331"}.fi-rr-data-transfer:before{content:"\f332"}.fi-rr-database:before{content:"\f333"}.fi-rr-delete-document:before{content:"\f334"}.fi-rr-delete-user:before{content:"\f335"}.fi-rr-delete:before{content:"\f336"}.fi-rr-democrat:before{content:"\f337"}.fi-rr-desktop-wallpaper:before{content:"\f338"}.fi-rr-devices:before{content:"\f339"}.fi-rr-dewpoint:before{content:"\f33a"}.fi-rr-diagram-cells:before{content:"\f33b"}.fi-rr-diagram-lean-canvas:before{content:"\f33c"}.fi-rr-diagram-nested:before{content:"\f33d"}.fi-rr-diagram-next:before{content:"\f33e"}.fi-rr-diagram-predecessor:before{content:"\f33f"}.fi-rr-diagram-previous:before{content:"\f340"}.fi-rr-diagram-project:before{content:"\f341"}.fi-rr-diagram-sankey:before{content:"\f342"}.fi-rr-diagram-subtask:before{content:"\f343"}.fi-rr-diagram-successor:before{content:"\f344"}.fi-rr-diamond-turn-right:before{content:"\f345"}.fi-rr-diamond:before{content:"\f346"}.fi-rr-dice-alt:before{content:"\f347"}.fi-rr-dice-d10:before{content:"\f348"}.fi-rr-dice-d12:before{content:"\f349"}.fi-rr-dice-d20:before{content:"\f34a"}.fi-rr-dice-d4:before{content:"\f34b"}.fi-rr-dice-d6:before{content:"\f34c"}.fi-rr-dice-d8:before{content:"\f34d"}.fi-rr-dice-four:before{content:"\f34e"}.fi-rr-dice-one:before{content:"\f34f"}.fi-rr-dice-six:before{content:"\f350"}.fi-rr-dice-three:before{content:"\f351"}.fi-rr-dice-two:before{content:"\f352"}.fi-rr-dice:before{content:"\f353"}.fi-rr-diploma:before{content:"\f354"}.fi-rr-disco-ball:before{content:"\f355"}.fi-rr-disk:before{content:"\f356"}.fi-rr-display-code:before{content:"\f357"}.fi-rr-distribute-spacing-horizontal:before{content:"\f358"}.fi-rr-distribute-spacing-vertical:before{content:"\f359"}.fi-rr-dizzy:before{content:"\f35a"}.fi-rr-doctor:before{content:"\f35b"}.fi-rr-document-signed:before{content:"\f35c"}.fi-rr-document:before{content:"\f35d"}.fi-rr-dollar:before{content:"\f35e"}.fi-rr-donate:before{content:"\f35f"}.fi-rr-door-closed:before{content:"\f360"}.fi-rr-door-open:before{content:"\f361"}.fi-rr-down-left-and-up-right-to-center:before{content:"\f362"}.fi-rr-down-left:before{content:"\f363"}.fi-rr-down-right:before{content:"\f364"}.fi-rr-down-to-line:before{content:"\f365"}.fi-rr-down:before{content:"\f366"}.fi-rr-download:before{content:"\f367"}.fi-rr-drafting-compass:before{content:"\f368"}.fi-rr-dreidel:before{content:"\f369"}.fi-rr-drink-alt:before{content:"\f36a"}.fi-rr-drumstick:before{content:"\f36b"}.fi-rr-dungeon:before{content:"\f36c"}.fi-rr-duplicate:before{content:"\f36d"}.fi-rr-e-learning:before{content:"\f36e"}.fi-rr-e:before{content:"\f36f"}.fi-rr-ear-deaf:before{content:"\f370"}.fi-rr-earnings:before{content:"\f371"}.fi-rr-eclipse-alt:before{content:"\f372"}.fi-rr-eclipse:before{content:"\f373"}.fi-rr-edit-alt:before{content:"\f374"}.fi-rr-edit:before{content:"\f375"}.fi-rr-egg-fried:before{content:"\f376"}.fi-rr-egg:before{content:"\f377"}.fi-rr-engine-warning:before{content:"\f378"}.fi-rr-enter:before{content:"\f379"}.fi-rr-envelope-ban:before{content:"\f37a"}.fi-rr-envelope-bulk:before{content:"\f37b"}.fi-rr-envelope-download:before{content:"\f37c"}.fi-rr-envelope-marker:before{content:"\f37d"}.fi-rr-envelope-open-dollar:before{content:"\f37e"}.fi-rr-envelope-open-text:before{content:"\f37f"}.fi-rr-envelope-open:before{content:"\f380"}.fi-rr-envelope-plus:before{content:"\f381"}.fi-rr-envelope:before{content:"\f382"}.fi-rr-equality:before{content:"\f383"}.fi-rr-euro:before{content:"\f384"}.fi-rr-exchange-alt:before{content:"\f385"}.fi-rr-exchange:before{content:"\f386"}.fi-rr-exclamation:before{content:"\f387"}.fi-rr-exit:before{content:"\f388"}.fi-rr-expand-arrows-alt:before{content:"\f389"}.fi-rr-expand-arrows:before{content:"\f38a"}.fi-rr-expand:before{content:"\f38b"}.fi-rr-eye-crossed:before{content:"\f38c"}.fi-rr-eye-dropper:before{content:"\f38d"}.fi-rr-eye:before{content:"\f38e"}.fi-rr-f:before{content:"\f38f"}.fi-rr-face-awesome:before{content:"\f390"}.fi-rr-face-head-bandage:before{content:"\f391"}.fi-rr-farm:before{content:"\f392"}.fi-rr-feather:before{content:"\f393"}.fi-rr-fence:before{content:"\f394"}.fi-rr-ferris-wheel:before{content:"\f395"}.fi-rr-fighter-jet:before{content:"\f396"}.fi-rr-file-ai:before{content:"\f397"}.fi-rr-file-binary:before{content:"\f398"}.fi-rr-file-chart-line:before{content:"\f399"}.fi-rr-file-chart-pie:before{content:"\f39a"}.fi-rr-file-code:before{content:"\f39b"}.fi-rr-file-eps:before{content:"\f39c"}.fi-rr-file-excel:before{content:"\f39d"}.fi-rr-file-export:before{content:"\f39e"}.fi-rr-file-invoice-dollar:before{content:"\f39f"}.fi-rr-file-invoice:before{content:"\f3a0"}.fi-rr-file-pdf:before{content:"\f3a1"}.fi-rr-file-powerpoint:before{content:"\f3a2"}.fi-rr-file-psd:before{content:"\f3a3"}.fi-rr-file-spreadsheet:before{content:"\f3a4"}.fi-rr-file-video:before{content:"\f3a5"}.fi-rr-file-word:before{content:"\f3a6"}.fi-rr-file:before{content:"\f3a7"}.fi-rr-fill:before{content:"\f3a8"}.fi-rr-film-slash:before{content:"\f3a9"}.fi-rr-film:before{content:"\f3aa"}.fi-rr-filter-slash:before{content:"\f3ab"}.fi-rr-filter:before{content:"\f3ac"}.fi-rr-filters:before{content:"\f3ad"}.fi-rr-fingerprint:before{content:"\f3ae"}.fi-rr-fire-flame-curved:before{content:"\f3af"}.fi-rr-fire-smoke:before{content:"\f3b0"}.fi-rr-fish:before{content:"\f3b1"}.fi-rr-fishing-rod:before{content:"\f3b2"}.fi-rr-flag-alt:before{content:"\f3b3"}.fi-rr-flag-checkered:before{content:"\f3b4"}.fi-rr-flag-usa:before{content:"\f3b5"}.fi-rr-flag:before{content:"\f3b6"}.fi-rr-flame:before{content:"\f3b7"}.fi-rr-flip-horizontal:before{content:"\f3b8"}.fi-rr-flower-bouquet:before{content:"\f3b9"}.fi-rr-flower-tulip:before{content:"\f3ba"}.fi-rr-flower:before{content:"\f3bb"}.fi-rr-flushed:before{content:"\f3bc"}.fi-rr-fog:before{content:"\f3bd"}.fi-rr-folder-download:before{content:"\f3be"}.fi-rr-folder-minus:before{content:"\f3bf"}.fi-rr-folder-times:before{content:"\f3c0"}.fi-rr-folder-tree:before{content:"\f3c1"}.fi-rr-folder-upload:before{content:"\f3c2"}.fi-rr-folder:before{content:"\f3c3"}.fi-rr-folders:before{content:"\f3c4"}.fi-rr-follow-folder:before{content:"\f3c5"}.fi-rr-followcollection:before{content:"\f3c6"}.fi-rr-following:before{content:"\f3c7"}.fi-rr-football:before{content:"\f3c8"}.fi-rr-fork:before{content:"\f3c9"}.fi-rr-form:before{content:"\f3ca"}.fi-rr-fort:before{content:"\f3cb"}.fi-rr-forward:before{content:"\f3cc"}.fi-rr-fox:before{content:"\f3cd"}.fi-rr-french-fries:before{content:"\f3ce"}.fi-rr-frown:before{content:"\f3cf"}.fi-rr-ftp:before{content:"\f3d0"}.fi-rr-funnel-dollar:before{content:"\f3d1"}.fi-rr-g:before{content:"\f3d2"}.fi-rr-gallery-thumbnails:before{content:"\f3d3"}.fi-rr-gallery:before{content:"\f3d4"}.fi-rr-game-board-alt:before{content:"\f3d5"}.fi-rr-gamepad:before{content:"\f3d6"}.fi-rr-garage-car:before{content:"\f3d7"}.fi-rr-garage-open:before{content:"\f3d8"}.fi-rr-garage:before{content:"\f3d9"}.fi-rr-garlic:before{content:"\f3da"}.fi-rr-gas-pump-alt:before{content:"\f3db"}.fi-rr-gas-pump-slash:before{content:"\f3dc"}.fi-rr-gas-pump:before{content:"\f3dd"}.fi-rr-gavel:before{content:"\f3de"}.fi-rr-gears:before{content:"\f3df"}.fi-rr-gem:before{content:"\f3e0"}.fi-rr-gif:before{content:"\f3e1"}.fi-rr-gift-card:before{content:"\f3e2"}.fi-rr-gift:before{content:"\f3e3"}.fi-rr-gifts:before{content:"\f3e4"}.fi-rr-gingerbread-man:before{content:"\f3e5"}.fi-rr-glass-cheers:before{content:"\f3e6"}.fi-rr-glass:before{content:"\f3e7"}.fi-rr-glasses:before{content:"\f3e8"}.fi-rr-globe-alt:before{content:"\f3e9"}.fi-rr-globe:before{content:"\f3ea"}.fi-rr-golf-ball:before{content:"\f3eb"}.fi-rr-golf:before{content:"\f3ec"}.fi-rr-graduation-cap:before{content:"\f3ed"}.fi-rr-grape:before{content:"\f3ee"}.fi-rr-graphic-style:before{content:"\f3ef"}.fi-rr-graphic-tablet:before{content:"\f3f0"}.fi-rr-grid-alt:before{content:"\f3f1"}.fi-rr-grid-dividers:before{content:"\f3f2"}.fi-rr-grid:before{content:"\f3f3"}.fi-rr-grill:before{content:"\f3f4"}.fi-rr-grimace:before{content:"\f3f5"}.fi-rr-grin-alt:before{content:"\f3f6"}.fi-rr-grin-beam-sweat:before{content:"\f3f7"}.fi-rr-grin-beam:before{content:"\f3f8"}.fi-rr-grin-hearts:before{content:"\f3f9"}.fi-rr-grin-squint-tears:before{content:"\f3fa"}.fi-rr-grin-squint:before{content:"\f3fb"}.fi-rr-grin-stars:before{content:"\f3fc"}.fi-rr-grin-tears:before{content:"\f3fd"}.fi-rr-grin-tongue-squint:before{content:"\f3fe"}.fi-rr-grin-tongue-wink:before{content:"\f3ff"}.fi-rr-grin-tongue:before{content:"\f400"}.fi-rr-grin-wink:before{content:"\f401"}.fi-rr-grin:before{content:"\f402"}.fi-rr-guitar:before{content:"\f403"}.fi-rr-gym:before{content:"\f404"}.fi-rr-h:before{content:"\f405"}.fi-rr-hamburger-soda:before{content:"\f406"}.fi-rr-hamburger:before{content:"\f407"}.fi-rr-hammer-crash:before{content:"\f408"}.fi-rr-hammer-war:before{content:"\f409"}.fi-rr-hammer:before{content:"\f40a"}.fi-rr-hand-holding-box:before{content:"\f40b"}.fi-rr-hand-holding-heart:before{content:"\f40c"}.fi-rr-hand-holding-seeding:before{content:"\f40d"}.fi-rr-hand-horns:before{content:"\f40e"}.fi-rr-hand-lizard:before{content:"\f40f"}.fi-rr-hand-peace:before{content:"\f410"}.fi-rr-hand:before{content:"\f411"}.fi-rr-hands-clapping:before{content:"\f412"}.fi-rr-handshake-angle:before{content:"\f413"}.fi-rr-handshake:before{content:"\f414"}.fi-rr-hastag:before{content:"\f415"}.fi-rr-hat-birthday:before{content:"\f416"}.fi-rr-hat-chef:before{content:"\f417"}.fi-rr-hdd:before{content:"\f418"}.fi-rr-head-side-brain:before{content:"\f419"}.fi-rr-head-side-cough-slash:before{content:"\f41a"}.fi-rr-head-side-cough:before{content:"\f41b"}.fi-rr-head-side-heart:before{content:"\f41c"}.fi-rr-head-side-mask:before{content:"\f41d"}.fi-rr-head-side-medical:before{content:"\f41e"}.fi-rr-head-side-thinking:before{content:"\f41f"}.fi-rr-head-side-virus:before{content:"\f420"}.fi-rr-head-side:before{content:"\f421"}.fi-rr-head-vr:before{content:"\f422"}.fi-rr-headphones:before{content:"\f423"}.fi-rr-headset:before{content:"\f424"}.fi-rr-heart-arrow:before{content:"\f425"}.fi-rr-heart-crack:before{content:"\f426"}.fi-rr-heart:before{content:"\f427"}.fi-rr-heat:before{content:"\f428"}.fi-rr-helicopter-side:before{content:"\f429"}.fi-rr-highlighter-line:before{content:"\f42a"}.fi-rr-highlighter:before{content:"\f42b"}.fi-rr-hiking:before{content:"\f42c"}.fi-rr-hockey-puck:before{content:"\f42d"}.fi-rr-hockey-sticks:before{content:"\f42e"}.fi-rr-home-location-alt:before{content:"\f42f"}.fi-rr-home-location:before{content:"\f430"}.fi-rr-home:before{content:"\f431"}.fi-rr-horizontal-rule:before{content:"\f432"}.fi-rr-hot-tub:before{content:"\f433"}.fi-rr-hotdog:before{content:"\f434"}.fi-rr-hotel:before{content:"\f435"}.fi-rr-hourglass-end:before{content:"\f436"}.fi-rr-hourglass:before{content:"\f437"}.fi-rr-house-blank:before{content:"\f438"}.fi-rr-house-building:before{content:"\f439"}.fi-rr-house-chimney-blank:before{content:"\f43a"}.fi-rr-house-chimney-crack:before{content:"\f43b"}.fi-rr-house-chimney-medical:before{content:"\f43c"}.fi-rr-house-chimney-window:before{content:"\f43d"}.fi-rr-house-chimney:before{content:"\f43e"}.fi-rr-house-crack:before{content:"\f43f"}.fi-rr-house-flood:before{content:"\f440"}.fi-rr-house-medical:before{content:"\f441"}.fi-rr-house-tree:before{content:"\f442"}.fi-rr-house-turret:before{content:"\f443"}.fi-rr-house-window:before{content:"\f444"}.fi-rr-hryvnia:before{content:"\f445"}.fi-rr-humidity:before{content:"\f446"}.fi-rr-hurricane:before{content:"\f447"}.fi-rr-i:before{content:"\f448"}.fi-rr-ice-cream:before{content:"\f449"}.fi-rr-ice-skate:before{content:"\f44a"}.fi-rr-icon-star:before{content:"\f44b"}.fi-rr-id-badge:before{content:"\f44c"}.fi-rr-igloo:before{content:"\f44d"}.fi-rr-images:before{content:"\f44e"}.fi-rr-inbox-in:before{content:"\f44f"}.fi-rr-inbox-out:before{content:"\f450"}.fi-rr-inbox:before{content:"\f451"}.fi-rr-incognito:before{content:"\f452"}.fi-rr-indent:before{content:"\f453"}.fi-rr-industry-windows:before{content:"\f454"}.fi-rr-infinity:before{content:"\f455"}.fi-rr-info:before{content:"\f456"}.fi-rr-interactive:before{content:"\f457"}.fi-rr-interlining:before{content:"\f458"}.fi-rr-interrogation:before{content:"\f459"}.fi-rr-island-tropical:before{content:"\f45a"}.fi-rr-italic:before{content:"\f45b"}.fi-rr-j:before{content:"\f45c"}.fi-rr-jam:before{content:"\f45d"}.fi-rr-jpg:before{content:"\f45e"}.fi-rr-jug:before{content:"\f45f"}.fi-rr-k:before{content:"\f460"}.fi-rr-kerning:before{content:"\f461"}.fi-rr-key-skeleton-left-right:before{content:"\f462"}.fi-rr-key:before{content:"\f463"}.fi-rr-keyboard-brightness-low:before{content:"\f464"}.fi-rr-keyboard-brightness:before{content:"\f465"}.fi-rr-keyboard:before{content:"\f466"}.fi-rr-keynote:before{content:"\f467"}.fi-rr-kiss-beam:before{content:"\f468"}.fi-rr-kiss-wink-heart:before{content:"\f469"}.fi-rr-kiss:before{content:"\f46a"}.fi-rr-kite:before{content:"\f46b"}.fi-rr-knife:before{content:"\f46c"}.fi-rr-l:before{content:"\f46d"}.fi-rr-label:before{content:"\f46e"}.fi-rr-landmark-alt:before{content:"\f46f"}.fi-rr-laptop-code:before{content:"\f470"}.fi-rr-laptop-mobile:before{content:"\f471"}.fi-rr-laptop:before{content:"\f472"}.fi-rr-lasso-sparkles:before{content:"\f473"}.fi-rr-lasso:before{content:"\f474"}.fi-rr-laugh-beam:before{content:"\f475"}.fi-rr-laugh-squint:before{content:"\f476"}.fi-rr-laugh-wink:before{content:"\f477"}.fi-rr-laugh:before{content:"\f478"}.fi-rr-layer-minus:before{content:"\f479"}.fi-rr-layer-plus:before{content:"\f47a"}.fi-rr-layers:before{content:"\f47b"}.fi-rr-layout-fluid:before{content:"\f47c"}.fi-rr-leaf:before{content:"\f47d"}.fi-rr-lemon:before{content:"\f47e"}.fi-rr-letter-case:before{content:"\f47f"}.fi-rr-lettuce:before{content:"\f480"}.fi-rr-level-down-alt:before{content:"\f481"}.fi-rr-level-down:before{content:"\f482"}.fi-rr-level-up-alt:before{content:"\f483"}.fi-rr-level-up:before{content:"\f484"}.fi-rr-license:before{content:"\f485"}.fi-rr-life-ring:before{content:"\f486"}.fi-rr-light-switch-off:before{content:"\f487"}.fi-rr-light-switch-on:before{content:"\f488"}.fi-rr-light-switch:before{content:"\f489"}.fi-rr-lightbulb-dollar:before{content:"\f48a"}.fi-rr-line-width:before{content:"\f48b"}.fi-rr-link-alt:before{content:"\f48c"}.fi-rr-link-horizontal-slash:before{content:"\f48d"}.fi-rr-link-horizontal:before{content:"\f48e"}.fi-rr-link-slash-alt:before{content:"\f48f"}.fi-rr-link-slash:before{content:"\f490"}.fi-rr-link:before{content:"\f491"}.fi-rr-lipstick:before{content:"\f492"}.fi-rr-lira-sign:before{content:"\f493"}.fi-rr-list-check:before{content:"\f494"}.fi-rr-list:before{content:"\f495"}.fi-rr-loading:before{content:"\f496"}.fi-rr-location-alt:before{content:"\f497"}.fi-rr-location-crosshairs-slash:before{content:"\f498"}.fi-rr-location-crosshairs:before{content:"\f499"}.fi-rr-location-dot-slash:before{content:"\f49a"}.fi-rr-lock-alt:before{content:"\f49b"}.fi-rr-lock:before{content:"\f49c"}.fi-rr-luchador:before{content:"\f49d"}.fi-rr-luggage-cart:before{content:"\f49e"}.fi-rr-luggage-rolling:before{content:"\f49f"}.fi-rr-m:before{content:"\f4a0"}.fi-rr-magic-wand:before{content:"\f4a1"}.fi-rr-mailbox:before{content:"\f4a2"}.fi-rr-makeup-brush:before{content:"\f4a3"}.fi-rr-man-head:before{content:"\f4a4"}.fi-rr-map-marker-check:before{content:"\f4a5"}.fi-rr-map-marker-cross:before{content:"\f4a6"}.fi-rr-map-marker-edit:before{content:"\f4a7"}.fi-rr-map-marker-home:before{content:"\f4a8"}.fi-rr-map-marker-minus:before{content:"\f4a9"}.fi-rr-map-marker-plus:before{content:"\f4aa"}.fi-rr-map-marker-question:before{content:"\f4ab"}.fi-rr-map-marker-slash:before{content:"\f4ac"}.fi-rr-map-marker-smile:before{content:"\f4ad"}.fi-rr-map-marker:before{content:"\f4ae"}.fi-rr-map-pin:before{content:"\f4af"}.fi-rr-map:before{content:"\f4b0"}.fi-rr-marker-time:before{content:"\f4b1"}.fi-rr-marker:before{content:"\f4b2"}.fi-rr-mars-double:before{content:"\f4b3"}.fi-rr-mars:before{content:"\f4b4"}.fi-rr-mask-carnival:before{content:"\f4b5"}.fi-rr-mask:before{content:"\f4b6"}.fi-rr-medicine:before{content:"\f4b7"}.fi-rr-megaphone:before{content:"\f4b8"}.fi-rr-meh-blank:before{content:"\f4b9"}.fi-rr-meh-rolling-eyes:before{content:"\f4ba"}.fi-rr-meh:before{content:"\f4bb"}.fi-rr-melon:before{content:"\f4bc"}.fi-rr-memory:before{content:"\f4bd"}.fi-rr-menu-burger:before{content:"\f4be"}.fi-rr-menu-dots-vertical:before{content:"\f4bf"}.fi-rr-menu-dots:before{content:"\f4c0"}.fi-rr-message-code:before{content:"\f4c1"}.fi-rr-meteor:before{content:"\f4c2"}.fi-rr-microchip:before{content:"\f4c3"}.fi-rr-microphone-alt:before{content:"\f4c4"}.fi-rr-microphone:before{content:"\f4c5"}.fi-rr-mind-share:before{content:"\f4c6"}.fi-rr-minus-small:before{content:"\f4c7"}.fi-rr-minus:before{content:"\f4c8"}.fi-rr-mobile-button:before{content:"\f4c9"}.fi-rr-mobile-notch:before{content:"\f4ca"}.fi-rr-mobile:before{content:"\f4cb"}.fi-rr-mockup:before{content:"\f4cc"}.fi-rr-mode-landscape:before{content:"\f4cd"}.fi-rr-mode-portrait:before{content:"\f4ce"}.fi-rr-money-bill-wave-alt:before{content:"\f4cf"}.fi-rr-money-bill-wave:before{content:"\f4d0"}.fi-rr-money-check-edit-alt:before{content:"\f4d1"}.fi-rr-money-check-edit:before{content:"\f4d2"}.fi-rr-money-check:before{content:"\f4d3"}.fi-rr-money:before{content:"\f4d4"}.fi-rr-monument:before{content:"\f4d5"}.fi-rr-moon-stars:before{content:"\f4d6"}.fi-rr-moon:before{content:"\f4d7"}.fi-rr-motorcycle:before{content:"\f4d8"}.fi-rr-mountains:before{content:"\f4d9"}.fi-rr-mouse:before{content:"\f4da"}.fi-rr-move-to-folder-2:before{content:"\f4db"}.fi-rr-move-to-folder:before{content:"\f4dc"}.fi-rr-mug-alt:before{content:"\f4dd"}.fi-rr-mug-hot-alt:before{content:"\f4de"}.fi-rr-mug-hot:before{content:"\f4df"}.fi-rr-mug-tea:before{content:"\f4e0"}.fi-rr-mug:before{content:"\f4e1"}.fi-rr-mushroom:before{content:"\f4e2"}.fi-rr-music-alt:before{content:"\f4e3"}.fi-rr-music-file:before{content:"\f4e4"}.fi-rr-music:before{content:"\f4e5"}.fi-rr-n:before{content:"\f4e6"}.fi-rr-navigation:before{content:"\f4e7"}.fi-rr-network-cloud:before{content:"\f4e8"}.fi-rr-network:before{content:"\f4e9"}.fi-rr-no-people:before{content:"\f4ea"}.fi-rr-noodles:before{content:"\f4eb"}.fi-rr-notdef:before{content:"\f4ec"}.fi-rr-notebook:before{content:"\f4ed"}.fi-rr-o:before{content:"\f4ee"}.fi-rr-object-exclude:before{content:"\f4ef"}.fi-rr-object-intersect:before{content:"\f4f0"}.fi-rr-object-subtract:before{content:"\f4f1"}.fi-rr-object-union:before{content:"\f4f2"}.fi-rr-octagon:before{content:"\f4f3"}.fi-rr-oil-can:before{content:"\f4f4"}.fi-rr-oil-temp:before{content:"\f4f5"}.fi-rr-olive-oil:before{content:"\f4f6"}.fi-rr-olives:before{content:"\f4f7"}.fi-rr-onion:before{content:"\f4f8"}.fi-rr-opacity:before{content:"\f4f9"}.fi-rr-overline:before{content:"\f4fa"}.fi-rr-p:before{content:"\f4fb"}.fi-rr-package:before{content:"\f4fc"}.fi-rr-page-break:before{content:"\f4fd"}.fi-rr-paint-brush:before{content:"\f4fe"}.fi-rr-paint-roller:before{content:"\f4ff"}.fi-rr-palette:before{content:"\f500"}.fi-rr-pan:before{content:"\f501"}.fi-rr-paper-plane:before{content:"\f502"}.fi-rr-parking-circle-slash:before{content:"\f503"}.fi-rr-parking-circle:before{content:"\f504"}.fi-rr-parking-slash:before{content:"\f505"}.fi-rr-parking:before{content:"\f506"}.fi-rr-passport:before{content:"\f507"}.fi-rr-password:before{content:"\f508"}.fi-rr-paste:before{content:"\f509"}.fi-rr-pattern:before{content:"\f50a"}.fi-rr-pause:before{content:"\f50b"}.fi-rr-paw:before{content:"\f50c"}.fi-rr-peach:before{content:"\f50d"}.fi-rr-pencil-ruler:before{content:"\f50e"}.fi-rr-pencil:before{content:"\f50f"}.fi-rr-pennant:before{content:"\f510"}.fi-rr-people-arrows-left-right:before{content:"\f511"}.fi-rr-people-carry-box:before{content:"\f512"}.fi-rr-people-dress:before{content:"\f513"}.fi-rr-people-pants:before{content:"\f514"}.fi-rr-people-poll:before{content:"\f515"}.fi-rr-people:before{content:"\f516"}.fi-rr-pepper-hot:before{content:"\f517"}.fi-rr-pepper:before{content:"\f518"}.fi-rr-percentage:before{content:"\f519"}.fi-rr-person-walking-with-cane:before{content:"\f51a"}.fi-rr-pharmacy:before{content:"\f51b"}.fi-rr-phone-call:before{content:"\f51c"}.fi-rr-phone-cross:before{content:"\f51d"}.fi-rr-phone-office:before{content:"\f51e"}.fi-rr-phone-pause:before{content:"\f51f"}.fi-rr-phone-slash:before{content:"\f520"}.fi-rr-photo-film-music:before{content:"\f521"}.fi-rr-photo-video:before{content:"\f522"}.fi-rr-physics:before{content:"\f523"}.fi-rr-picnic:before{content:"\f524"}.fi-rr-picpeople-filled:before{content:"\f525"}.fi-rr-picpeople:before{content:"\f526"}.fi-rr-picture:before{content:"\f527"}.fi-rr-pie:before{content:"\f528"}.fi-rr-piece:before{content:"\f529"}.fi-rr-piggy-bank:before{content:"\f52a"}.fi-rr-pineapple:before{content:"\f52b"}.fi-rr-ping-pong:before{content:"\f52c"}.fi-rr-pizza-slice:before{content:"\f52d"}.fi-rr-plane-alt:before{content:"\f52e"}.fi-rr-plane-arrival:before{content:"\f52f"}.fi-rr-plane-departure:before{content:"\f530"}.fi-rr-plane-prop:before{content:"\f531"}.fi-rr-plane-tail:before{content:"\f532"}.fi-rr-plane:before{content:"\f533"}.fi-rr-plate:before{content:"\f534"}.fi-rr-play-alt:before{content:"\f535"}.fi-rr-play-pause:before{content:"\f536"}.fi-rr-play:before{content:"\f537"}.fi-rr-playing-cards:before{content:"\f538"}.fi-rr-plus-small:before{content:"\f539"}.fi-rr-plus:before{content:"\f53a"}.fi-rr-podium-star:before{content:"\f53b"}.fi-rr-podium:before{content:"\f53c"}.fi-rr-poker-chip:before{content:"\f53d"}.fi-rr-poo:before{content:"\f53e"}.fi-rr-popcorn:before{content:"\f53f"}.fi-rr-portrait:before{content:"\f540"}.fi-rr-pot:before{content:"\f541"}.fi-rr-pound:before{content:"\f542"}.fi-rr-power:before{content:"\f543"}.fi-rr-presentation:before{content:"\f544"}.fi-rr-print:before{content:"\f545"}.fi-rr-projector:before{content:"\f546"}.fi-rr-protractor:before{content:"\f547"}.fi-rr-pulse:before{content:"\f548"}.fi-rr-pumpkin:before{content:"\f549"}.fi-rr-puzzle:before{content:"\f54a"}.fi-rr-pyramid:before{content:"\f54b"}.fi-rr-q:before{content:"\f54c"}.fi-rr-qrcode:before{content:"\f54d"}.fi-rr-question-square:before{content:"\f54e"}.fi-rr-question:before{content:"\f54f"}.fi-rr-quote-right:before{content:"\f550"}.fi-rr-r:before{content:"\f551"}.fi-rr-racquet:before{content:"\f552"}.fi-rr-radish:before{content:"\f553"}.fi-rr-rainbow:before{content:"\f554"}.fi-rr-raindrops:before{content:"\f555"}.fi-rr-ramp-loading:before{content:"\f556"}.fi-rr-rec:before{content:"\f557"}.fi-rr-receipt:before{content:"\f558"}.fi-rr-record-vinyl:before{content:"\f559"}.fi-rr-rectabgle-vertical:before{content:"\f55a"}.fi-rr-rectangle-barcode:before{content:"\f55b"}.fi-rr-rectangle-code:before{content:"\f55c"}.fi-rr-rectangle-horizontal:before{content:"\f55d"}.fi-rr-rectangle-panoramic:before{content:"\f55e"}.fi-rr-rectangle-xmark:before{content:"\f55f"}.fi-rr-recycle:before{content:"\f560"}.fi-rr-redo-alt:before{content:"\f561"}.fi-rr-redo:before{content:"\f562"}.fi-rr-reflect-horizontal:before{content:"\f563"}.fi-rr-reflect-vertical:before{content:"\f564"}.fi-rr-reflect:before{content:"\f565"}.fi-rr-refresh:before{content:"\f566"}.fi-rr-registered:before{content:"\f567"}.fi-rr-remove-folder:before{content:"\f568"}.fi-rr-remove-user:before{content:"\f569"}.fi-rr-replace:before{content:"\f56a"}.fi-rr-reply-all:before{content:"\f56b"}.fi-rr-republican:before{content:"\f56c"}.fi-rr-resize:before{content:"\f56d"}.fi-rr-resources:before{content:"\f56e"}.fi-rr-restaurant:before{content:"\f56f"}.fi-rr-rewind:before{content:"\f570"}.fi-rr-rhombus:before{content:"\f571"}.fi-rr-rings-wedding:before{content:"\f572"}.fi-rr-road:before{content:"\f573"}.fi-rr-rocket-lunch:before{content:"\f574"}.fi-rr-rocket:before{content:"\f575"}.fi-rr-roller-coaster:before{content:"\f576"}.fi-rr-room-service:before{content:"\f577"}.fi-rr-rotate-left:before{content:"\f578"}.fi-rr-rotate-right:before{content:"\f579"}.fi-rr-route-highway:before{content:"\f57a"}.fi-rr-route-interstate:before{content:"\f57b"}.fi-rr-route:before{content:"\f57c"}.fi-rr-ruble-sign:before{content:"\f57d"}.fi-rr-rugby:before{content:"\f57e"}.fi-rr-ruler-combined:before{content:"\f57f"}.fi-rr-ruler-horizontal:before{content:"\f580"}.fi-rr-ruler-triangle:before{content:"\f581"}.fi-rr-ruler-vertical:before{content:"\f582"}.fi-rr-running:before{content:"\f583"}.fi-rr-rupee-sign:before{content:"\f584"}.fi-rr-rv:before{content:"\f585"}.fi-rr-s:before{content:"\f586"}.fi-rr-sack-dollar:before{content:"\f587"}.fi-rr-sack:before{content:"\f588"}.fi-rr-sad-cry:before{content:"\f589"}.fi-rr-sad-tear:before{content:"\f58a"}.fi-rr-sad:before{content:"\f58b"}.fi-rr-salad:before{content:"\f58c"}.fi-rr-salt-pepper:before{content:"\f58d"}.fi-rr-sandwich:before{content:"\f58e"}.fi-rr-sauce:before{content:"\f58f"}.fi-rr-sausage:before{content:"\f590"}.fi-rr-scale:before{content:"\f591"}.fi-rr-school-bus:before{content:"\f592"}.fi-rr-school:before{content:"\f593"}.fi-rr-scissors:before{content:"\f594"}.fi-rr-screen:before{content:"\f595"}.fi-rr-search-alt:before{content:"\f596"}.fi-rr-search-dollar:before{content:"\f597"}.fi-rr-search-heart:before{content:"\f598"}.fi-rr-search-location:before{content:"\f599"}.fi-rr-search:before{content:"\f59a"}.fi-rr-seat-airline:before{content:"\f59b"}.fi-rr-security:before{content:"\f59c"}.fi-rr-sensor-alert:before{content:"\f59d"}.fi-rr-sensor-fire:before{content:"\f59e"}.fi-rr-sensor-on:before{content:"\f59f"}.fi-rr-sensor-smoke:before{content:"\f5a0"}.fi-rr-sensor:before{content:"\f5a1"}.fi-rr-settings-sliders:before{content:"\f5a2"}.fi-rr-settings:before{content:"\f5a3"}.fi-rr-share:before{content:"\f5a4"}.fi-rr-shekel-sign:before{content:"\f5a5"}.fi-rr-shield-check:before{content:"\f5a6"}.fi-rr-shield-exclamation:before{content:"\f5a7"}.fi-rr-shield-interrogation:before{content:"\f5a8"}.fi-rr-shield-plus:before{content:"\f5a9"}.fi-rr-shield:before{content:"\f5aa"}.fi-rr-ship-side:before{content:"\f5ab"}.fi-rr-ship:before{content:"\f5ac"}.fi-rr-shoe-prints:before{content:"\f5ad"}.fi-rr-shop-lock:before{content:"\f5ae"}.fi-rr-shop:before{content:"\f5af"}.fi-rr-shopping-bag-add:before{content:"\f5b0"}.fi-rr-shopping-bag:before{content:"\f5b1"}.fi-rr-shopping-basket:before{content:"\f5b2"}.fi-rr-shopping-cart-add:before{content:"\f5b3"}.fi-rr-shopping-cart-check:before{content:"\f5b4"}.fi-rr-shopping-cart:before{content:"\f5b5"}.fi-rr-shrimp:before{content:"\f5b6"}.fi-rr-shuffle:before{content:"\f5b7"}.fi-rr-shuttle-van:before{content:"\f5b8"}.fi-rr-shuttlecock:before{content:"\f5b9"}.fi-rr-sidebar-flip:before{content:"\f5ba"}.fi-rr-sidebar:before{content:"\f5bb"}.fi-rr-sign-hanging:before{content:"\f5bc"}.fi-rr-sign-in-alt:before{content:"\f5bd"}.fi-rr-sign-out-alt:before{content:"\f5be"}.fi-rr-signal-alt-1:before{content:"\f5bf"}.fi-rr-signal-alt-2:before{content:"\f5c0"}.fi-rr-signal-alt:before{content:"\f5c1"}.fi-rr-signal-stream-slash:before{content:"\f5c2"}.fi-rr-signal-stream:before{content:"\f5c3"}.fi-rr-sitemap:before{content:"\f5c4"}.fi-rr-skateboard:before{content:"\f5c5"}.fi-rr-skating:before{content:"\f5c6"}.fi-rr-skewer:before{content:"\f5c7"}.fi-rr-ski-jump:before{content:"\f5c8"}.fi-rr-ski-lift:before{content:"\f5c9"}.fi-rr-skiing-nordic:before{content:"\f5ca"}.fi-rr-skiing:before{content:"\f5cb"}.fi-rr-slash:before{content:"\f5cc"}.fi-rr-sledding:before{content:"\f5cd"}.fi-rr-sleigh:before{content:"\f5ce"}.fi-rr-smartphone:before{content:"\f5cf"}.fi-rr-smile-beam:before{content:"\f5d0"}.fi-rr-smile-wink:before{content:"\f5d1"}.fi-rr-smile:before{content:"\f5d2"}.fi-rr-smiley-comment-alt:before{content:"\f5d3"}.fi-rr-smog:before{content:"\f5d4"}.fi-rr-smoke:before{content:"\f5d5"}.fi-rr-snow-blowing:before{content:"\f5d6"}.fi-rr-snowboarding:before{content:"\f5d7"}.fi-rr-snowflake:before{content:"\f5d8"}.fi-rr-snowflakes:before{content:"\f5d9"}.fi-rr-snowmobile:before{content:"\f5da"}.fi-rr-snowplow:before{content:"\f5db"}.fi-rr-soap:before{content:"\f5dc"}.fi-rr-social-network:before{content:"\f5dd"}.fi-rr-sort-alpha-down-alt:before{content:"\f5de"}.fi-rr-sort-alpha-down:before{content:"\f5df"}.fi-rr-sort-alpha-up-alt:before{content:"\f5e0"}.fi-rr-sort-alpha-up:before{content:"\f5e1"}.fi-rr-sort-alt:before{content:"\f5e2"}.fi-rr-sort-amount-down-alt:before{content:"\f5e3"}.fi-rr-sort-amount-down:before{content:"\f5e4"}.fi-rr-sort-amount-up-alt:before{content:"\f5e5"}.fi-rr-sort-amount-up:before{content:"\f5e6"}.fi-rr-sort-down:before{content:"\f5e7"}.fi-rr-sort-numeric-down-alt:before{content:"\f5e8"}.fi-rr-sort-numeric-down:before{content:"\f5e9"}.fi-rr-sort-shapes-down:before{content:"\f5ea"}.fi-rr-sort-shapes-up:before{content:"\f5eb"}.fi-rr-sort-size-down:before{content:"\f5ec"}.fi-rr-sort-size-up:before{content:"\f5ed"}.fi-rr-sort:before{content:"\f5ee"}.fi-rr-soup:before{content:"\f5ef"}.fi-rr-spa:before{content:"\f5f0"}.fi-rr-space-shuttle:before{content:"\f5f1"}.fi-rr-spade:before{content:"\f5f2"}.fi-rr-sparkles:before{content:"\f5f3"}.fi-rr-speaker:before{content:"\f5f4"}.fi-rr-sphere:before{content:"\f5f5"}.fi-rr-spinner:before{content:"\f5f6"}.fi-rr-spoon:before{content:"\f5f7"}.fi-rr-sport:before{content:"\f5f8"}.fi-rr-square-0:before{content:"\f5f9"}.fi-rr-square-1:before{content:"\f5fa"}.fi-rr-square-2:before{content:"\f5fb"}.fi-rr-square-3:before{content:"\f5fc"}.fi-rr-square-4:before{content:"\f5fd"}.fi-rr-square-5:before{content:"\f5fe"}.fi-rr-square-6:before{content:"\f5ff"}.fi-rr-square-7:before{content:"\f600"}.fi-rr-square-8:before{content:"\f601"}.fi-rr-square-9:before{content:"\f602"}.fi-rr-square-code:before{content:"\f603"}.fi-rr-square-heart:before{content:"\f604"}.fi-rr-square-info:before{content:"\f605"}.fi-rr-square-plus:before{content:"\f606"}.fi-rr-square-root:before{content:"\f607"}.fi-rr-square-terminal:before{content:"\f608"}.fi-rr-square:before{content:"\f609"}.fi-rr-squircle:before{content:"\f60a"}.fi-rr-stamp:before{content:"\f60b"}.fi-rr-star-comment-alt:before{content:"\f60c"}.fi-rr-star-octogram:before{content:"\f60d"}.fi-rr-star:before{content:"\f60e"}.fi-rr-starfighter:before{content:"\f60f"}.fi-rr-stars:before{content:"\f610"}.fi-rr-stats:before{content:"\f611"}.fi-rr-steak:before{content:"\f612"}.fi-rr-steering-wheel:before{content:"\f613"}.fi-rr-stethoscope:before{content:"\f614"}.fi-rr-sticker:before{content:"\f615"}.fi-rr-stop:before{content:"\f616"}.fi-rr-stopwatch:before{content:"\f617"}.fi-rr-store-alt:before{content:"\f618"}.fi-rr-store-lock:before{content:"\f619"}.fi-rr-strawberry:before{content:"\f61a"}.fi-rr-street-view:before{content:"\f61b"}.fi-rr-subtitles:before{content:"\f61c"}.fi-rr-subway:before{content:"\f61d"}.fi-rr-suitcase-alt:before{content:"\f61e"}.fi-rr-summer:before{content:"\f61f"}.fi-rr-sun:before{content:"\f620"}.fi-rr-sunrise-alt:before{content:"\f621"}.fi-rr-sunrise:before{content:"\f622"}.fi-rr-sunset:before{content:"\f623"}.fi-rr-surfing:before{content:"\f624"}.fi-rr-surprise:before{content:"\f625"}.fi-rr-sushi:before{content:"\f626"}.fi-rr-swimmer:before{content:"\f627"}.fi-rr-sword:before{content:"\f628"}.fi-rr-symbol:before{content:"\f629"}.fi-rr-syringe:before{content:"\f62a"}.fi-rr-t:before{content:"\f62b"}.fi-rr-table-columns:before{content:"\f62c"}.fi-rr-table-layout:before{content:"\f62d"}.fi-rr-table-picnic:before{content:"\f62e"}.fi-rr-table-pivot:before{content:"\f62f"}.fi-rr-table-rows:before{content:"\f630"}.fi-rr-table-tree:before{content:"\f631"}.fi-rr-tablet:before{content:"\f632"}.fi-rr-tachometer-alt-average:before{content:"\f633"}.fi-rr-tachometer-alt-fastest:before{content:"\f634"}.fi-rr-tachometer-alt-slow:before{content:"\f635"}.fi-rr-tachometer-alt-slowest:before{content:"\f636"}.fi-rr-tachometer-average:before{content:"\f637"}.fi-rr-tachometer-fast:before{content:"\f638"}.fi-rr-tachometer-fastest:before{content:"\f639"}.fi-rr-tachometer-slow:before{content:"\f63a"}.fi-rr-tachometer-slowest:before{content:"\f63b"}.fi-rr-tachometer:before{content:"\f63c"}.fi-rr-taco:before{content:"\f63d"}.fi-rr-tags:before{content:"\f63e"}.fi-rr-tally:before{content:"\f63f"}.fi-rr-target:before{content:"\f640"}.fi-rr-taxi-bus:before{content:"\f641"}.fi-rr-taxi:before{content:"\f642"}.fi-rr-temperature-down:before{content:"\f643"}.fi-rr-temperature-frigid:before{content:"\f644"}.fi-rr-temperature-high:before{content:"\f645"}.fi-rr-temperature-low:before{content:"\f646"}.fi-rr-temperature-up:before{content:"\f647"}.fi-rr-template-alt:before{content:"\f648"}.fi-rr-template:before{content:"\f649"}.fi-rr-tenge:before{content:"\f64a"}.fi-rr-tennis:before{content:"\f64b"}.fi-rr-terminal:before{content:"\f64c"}.fi-rr-terrace:before{content:"\f64d"}.fi-rr-test-tube:before{content:"\f64e"}.fi-rr-test:before{content:"\f64f"}.fi-rr-text-check:before{content:"\f650"}.fi-rr-text-height:before{content:"\f651"}.fi-rr-text-shadow:before{content:"\f652"}.fi-rr-text-size:before{content:"\f653"}.fi-rr-text-slash:before{content:"\f654"}.fi-rr-text-width:before{content:"\f655"}.fi-rr-text:before{content:"\f656"}.fi-rr-thermometer-half:before{content:"\f657"}.fi-rr-thumbtack:before{content:"\f658"}.fi-rr-thunderstorm-moon:before{content:"\f659"}.fi-rr-thunderstorm-sun:before{content:"\f65a"}.fi-rr-thunderstorm:before{content:"\f65b"}.fi-rr-ticket-alt:before{content:"\f65c"}.fi-rr-ticket:before{content:"\f65d"}.fi-rr-time-add:before{content:"\f65e"}.fi-rr-time-check:before{content:"\f65f"}.fi-rr-time-delete:before{content:"\f660"}.fi-rr-time-fast:before{content:"\f661"}.fi-rr-time-forward-sixty:before{content:"\f662"}.fi-rr-time-forward-ten:before{content:"\f663"}.fi-rr-time-forward:before{content:"\f664"}.fi-rr-time-half-past:before{content:"\f665"}.fi-rr-time-oclock:before{content:"\f666"}.fi-rr-time-past:before{content:"\f667"}.fi-rr-time-quarter-past:before{content:"\f668"}.fi-rr-time-quarter-to:before{content:"\f669"}.fi-rr-time-twenty-four:before{content:"\f66a"}.fi-rr-tire-flat:before{content:"\f66b"}.fi-rr-tire-pressure-warning:before{content:"\f66c"}.fi-rr-tire-rugged:before{content:"\f66d"}.fi-rr-tire:before{content:"\f66e"}.fi-rr-tired:before{content:"\f66f"}.fi-rr-toilet-paper-blank:before{content:"\f670"}.fi-rr-tomato:before{content:"\f671"}.fi-rr-tool-box:before{content:"\f672"}.fi-rr-tool-crop:before{content:"\f673"}.fi-rr-tool-marquee:before{content:"\f674"}.fi-rr-tooth:before{content:"\f675"}.fi-rr-tornado:before{content:"\f676"}.fi-rr-tower-control:before{content:"\f677"}.fi-rr-tractor:before{content:"\f678"}.fi-rr-traffic-light-go:before{content:"\f679"}.fi-rr-traffic-light-slow:before{content:"\f67a"}.fi-rr-traffic-light-stop:before{content:"\f67b"}.fi-rr-traffic-light:before{content:"\f67c"}.fi-rr-trailer:before{content:"\f67d"}.fi-rr-train-side:before{content:"\f67e"}.fi-rr-train-subway-tunnel:before{content:"\f67f"}.fi-rr-train-tram:before{content:"\f680"}.fi-rr-train:before{content:"\f681"}.fi-rr-tram:before{content:"\f682"}.fi-rr-transform:before{content:"\f683"}.fi-rr-trash:before{content:"\f684"}.fi-rr-treasure-chest:before{content:"\f685"}.fi-rr-treatment:before{content:"\f686"}.fi-rr-tree-christmas:before{content:"\f687"}.fi-rr-tree-deciduous:before{content:"\f688"}.fi-rr-tree:before{content:"\f689"}.fi-rr-triangle-warning:before{content:"\f68a"}.fi-rr-triangle:before{content:"\f68b"}.fi-rr-trophy-star:before{content:"\f68c"}.fi-rr-trophy:before{content:"\f68d"}.fi-rr-truck-container:before{content:"\f68e"}.fi-rr-truck-couch:before{content:"\f68f"}.fi-rr-truck-loading:before{content:"\f690"}.fi-rr-truck-monster:before{content:"\f691"}.fi-rr-truck-moving:before{content:"\f692"}.fi-rr-truck-pickup:before{content:"\f693"}.fi-rr-truck-plow:before{content:"\f694"}.fi-rr-truck-ramp:before{content:"\f695"}.fi-rr-truck-side:before{content:"\f696"}.fi-rr-tty:before{content:"\f697"}.fi-rr-turkey:before{content:"\f698"}.fi-rr-tv-music:before{content:"\f699"}.fi-rr-typewriter:before{content:"\f69a"}.fi-rr-u:before{content:"\f69b"}.fi-rr-umbrella-beach:before{content:"\f69c"}.fi-rr-umbrella:before{content:"\f69d"}.fi-rr-underline:before{content:"\f69e"}.fi-rr-undo-alt:before{content:"\f69f"}.fi-rr-undo:before{content:"\f6a0"}.fi-rr-universal-access:before{content:"\f6a1"}.fi-rr-unlock:before{content:"\f6a2"}.fi-rr-up-left:before{content:"\f6a3"}.fi-rr-up-right:before{content:"\f6a4"}.fi-rr-up:before{content:"\f6a5"}.fi-rr-upload:before{content:"\f6a6"}.fi-rr-usb-pendrive:before{content:"\f6a7"}.fi-rr-usd-circle:before{content:"\f6a8"}.fi-rr-usd-square:before{content:"\f6a9"}.fi-rr-user-add:before{content:"\f6aa"}.fi-rr-user-time:before{content:"\f6ab"}.fi-rr-user:before{content:"\f6ac"}.fi-rr-users-alt:before{content:"\f6ad"}.fi-rr-users:before{content:"\f6ae"}.fi-rr-utensils:before{content:"\f6af"}.fi-rr-v:before{content:"\f6b0"}.fi-rr-vector-alt:before{content:"\f6b1"}.fi-rr-vector:before{content:"\f6b2"}.fi-rr-venus-double:before{content:"\f6b3"}.fi-rr-venus-mars:before{content:"\f6b4"}.fi-rr-venus:before{content:"\f6b5"}.fi-rr-vest-patches:before{content:"\f6b6"}.fi-rr-vest:before{content:"\f6b7"}.fi-rr-video-arrow-down-left:before{content:"\f6b8"}.fi-rr-video-arrow-up-right:before{content:"\f6b9"}.fi-rr-video-camera-alt:before{content:"\f6ba"}.fi-rr-video-camera:before{content:"\f6bb"}.fi-rr-video-plus:before{content:"\f6bc"}.fi-rr-video-slash:before{content:"\f6bd"}.fi-rr-volcano:before{content:"\f6be"}.fi-rr-volleyball:before{content:"\f6bf"}.fi-rr-volume:before{content:"\f6c0"}.fi-rr-w:before{content:"\f6c1"}.fi-rr-wagon-covered:before{content:"\f6c2"}.fi-rr-wallet:before{content:"\f6c3"}.fi-rr-warehouse-alt:before{content:"\f6c4"}.fi-rr-water-bottle:before{content:"\f6c5"}.fi-rr-water-lower:before{content:"\f6c6"}.fi-rr-water-rise:before{content:"\f6c7"}.fi-rr-water:before{content:"\f6c8"}.fi-rr-watermelon:before{content:"\f6c9"}.fi-rr-wheat:before{content:"\f6ca"}.fi-rr-wheelchair-move:before{content:"\f6cb"}.fi-rr-wheelchair:before{content:"\f6cc"}.fi-rr-whistle:before{content:"\f6cd"}.fi-rr-wifi-1:before{content:"\f6ce"}.fi-rr-wifi-2:before{content:"\f6cf"}.fi-rr-wifi-alt:before{content:"\f6d0"}.fi-rr-wifi-exclamation:before{content:"\f6d1"}.fi-rr-wifi-slash:before{content:"\f6d2"}.fi-rr-wifi:before{content:"\f6d3"}.fi-rr-wind-warning:before{content:"\f6d4"}.fi-rr-wind:before{content:"\f6d5"}.fi-rr-window-alt:before{content:"\f6d6"}.fi-rr-window-maximize:before{content:"\f6d7"}.fi-rr-window-minimize:before{content:"\f6d8"}.fi-rr-window-restore:before{content:"\f6d9"}.fi-rr-windsock:before{content:"\f6da"}.fi-rr-wine-glass-crack:before{content:"\f6db"}.fi-rr-woman-head:before{content:"\f6dc"}.fi-rr-world:before{content:"\f6dd"}.fi-rr-wrench-simple:before{content:"\f6de"}.fi-rr-x:before{content:"\f6df"}.fi-rr-y:before{content:"\f6e0"}.fi-rr-yen:before{content:"\f6e1"}.fi-rr-yin-yang:before{content:"\f6e2"}.fi-rr-z:before{content:"\f6e3"}.fi-rr-zoom-in:before{content:"\f6e4"}.fi-rr-zoom-out:before{content:"\f6e5"}
/*# sourceMappingURL=rounded.css.map */
================================================
FILE: assets/webfonts/OFL.txt
================================================
Copyright 2019 The Baloo 2 Project Authors (https://github.com/EkType/Baloo2)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
================================================
FILE: misc/window/LICENSE
================================================
Copyright (c) 2021-2022 Guasam
This software is provided "as-is", without any express or implied warranty. In no event
will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial
applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you
wrote the original software. If you use this software in a product, an acknowledgment
in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented
as being the original software.
3. This notice may not be removed or altered from any source distribution.
================================================
FILE: misc/window/components/ControlButton.tsx
================================================
import classNames from 'classnames';
import React from 'react';
interface IControlButtonProps {
readonly name: string;
readonly path: string;
readonly title: string;
}
const ControlButton: React.FC<
IControlButtonProps & React.HTMLAttributes<HTMLDivElement>
> = (props) => {
const { name, path, title, ...rest } = props;
const { onClick } = rest;
const className = classNames('control', name);
return (
<div
data-label={name}
className={className}
onClick={onClick}
title={title}
{...rest}
>
<svg aria-hidden='true' version='1.1' width='10' height='10'>
<path fill='currentColor' d={path} />
</svg>
</div>
);
};
export default ControlButton;
================================================
FILE: misc/window/components/Titlebar.less
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Components Stylesheet
*/
// @import '/src/renderer/components/Theme.scss';
@titlebar-baseSize: 16px;
@titlebar-height: 28px;
@titlebar-bg: #171b21;
@titlebar-iconSize: 16px;
@em: @titlebar-baseSize*1em;
//-----------------------------------------
// Mixins
//-----------------------------------------
.flex-strech() {
display: flex;
align-items: stretch;
}
.flex-align-center() {
display: flex;
align-items: center;
}
//-----------------------------------------
// Stylesheet
//-----------------------------------------
.window-content {
position: relative;
overflow: auto;
flex: 1;
}
.window-titlebar {
.flex-strech();
display: none;
font-size: @titlebar-baseSize;
height: @titlebar-height;
background: @titlebar-bg;
// -webkit-app-region: drag; // Draggable
user-select: none;
position: relative;
& > section {
.flex-align-center();
}
&-content {
flex: 1;
font-size: calc(@titlebar-baseSize - 3px);
color: #a9b0bb;
&.centered {
width: 100%;
height: 100%;
position: absolute;
justify-content: center;
}
}
// Titlebar icon
&-icon {
padding: 0 0.75em;
img {
width: @titlebar-iconSize;
height: @titlebar-iconSize;
}
}
// Titlebar Menu
&-menu {
flex: 1;
}
.menu {
&-item {
position: relative;
}
&-item.active {
.menu-title {
background: #3c4043;
color: #bfbfbf;
}
}
&-title {
padding: 4px 10px;
font-size: 0.8125rem;
text-shadow: 0px 1px 1px black;
-webkit-app-region: no-drag;
color: #97a0b1;
&:hover {
background-color: #1f252c;
}
}
&-popup {
display: none;
position: fixed;
background: #292a2d;
min-width: 70px;
border: 1px solid #3c4043;
padding: 0.25rem 0;
box-shadow: 2px 1px 4px hsla(0, 0%, 0%, 0.5);
z-index: 10000;
&.active {
display: block;
}
&-item {
display: flex;
justify-content: space-between;
font-size: 0.8125rem;
text-shadow: 0px 1px 1px black;
padding: 0.375rem 1rem;
&:hover {
background: #1761cb;
.popup-item-shortcut {
color: #8cbbff;
}
}
}
}
}
.popup-item {
&-name {
padding-right: 2rem;
color: #d8d8d8;
}
&-shortcut {
color: #73757c;
text-shadow: none;
}
&-separator {
height: 1px;
background: #3c4043;
margin: 4px 0;
}
}
// Titlebar controls
&-controls {
.flex-strech();
position: absolute;
right: 0;
top: 0;
bottom: 0;
color: hsla(var(--app-text-color), 0.5);
&.type-windows {
.control {
padding: 0 1.15em;
font-size: 0.875em;
display: flex;
height: 100%;
align-items: center;
-webkit-app-region: no-drag;
}
}
&.type-mac {
display: none !important;
.control {
width: 16px;
height: 16px;
background: #0e0e0e99;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.675rem;
color: transparent;
-webkit-app-region: no-drag;
opacity: 0.8;
&:hover {
opacity: 1;
}
}
.control.close {
background: #f46d60;
}
.control.maximize {
background: #59ca56;
}
.control.minimize {
background: #f9c04e;
}
}
}
}
================================================
FILE: misc/window/components/Titlebar.tsx
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Titlebar (Component)
*/
import React, { createRef, useContext, useEffect, useRef, useState } from 'react';
import titlebarMenus from '../titlebarMenus';
import classNames from 'classnames';
import WindowControls from './WindowControls';
import context from '../titlebarContextApi';
import { WindowContext } from './WindowFrame';
import './Titlebar.less';
type Props = {
title: string;
mode: 'centered-title';
icon?: string;
};
const Titlebar: React.FC<Props> = (props) => {
const activeMenuIndex = useRef<number | null>(null);
const menusRef = titlebarMenus.map(() => createRef<HTMLDivElement>());
const [menusVisible, setMenusVisible] = useState(true);
const windowContext = useContext(WindowContext);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.repeat) return; // Prevent repeatation of toggle when key holding
if (e.altKey && e.ctrlKey) {
// Hiding menus? close active menu popup
if (menusVisible) {
closeActiveMenu();
}
setMenusVisible(!menusVisible);
}
};
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [menusVisible, menusRef]);
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (activeMenuIndex.current != null) {
if (
menusRef[activeMenuIndex.current].current &&
!menusRef[activeMenuIndex.current].current?.contains(event.target as Node)
) {
// console.log('You clicked outside of me!');
closeActiveMenu();
}
}
}
if (activeMenuIndex != null) {
document.addEventListener('mousedown', handleClickOutside);
// console.log('added event');
}
return () => {
document.removeEventListener('mousedown', handleClickOutside);
// console.log('remove event');
};
}, [activeMenuIndex, menusRef]);
function showMenu(index: number, e: React.MouseEvent<HTMLDivElement>) {
e.stopPropagation();
e.preventDefault();
if (menusRef[index].current?.classList.contains('active')) {
// close..
closeActiveMenu();
} else {
// open..
menusRef[index].current?.classList.add('active');
activeMenuIndex.current = index;
menusRef[index].current?.parentElement?.classList.add('active');
}
}
function onMenuHover(index: number) {
if (activeMenuIndex.current != null) {
menusRef[activeMenuIndex.current].current?.classList.toggle('active');
menusRef[index].current?.classList.toggle('active');
menusRef[index].current?.parentElement?.classList.toggle('active');
menusRef[activeMenuIndex.current].current?.parentElement?.classList.toggle(
'active',
);
activeMenuIndex.current = index;
}
}
function closeActiveMenu() {
if (activeMenuIndex.current != null) {
menusRef[activeMenuIndex.current].current?.classList.remove('active');
menusRef[activeMenuIndex.current]?.current?.parentElement?.classList.remove('active');
activeMenuIndex.current = null;
}
}
function handleAction(action?: string, value?: string | number) {
closeActiveMenu();
const c: Record<string, CallableFunction> = context;
if (action) {
if (typeof c[action] === 'function') {
c[action](value);
} else {
console.log(`action [${action}] is not available in titlebar context`);
}
}
}
return (
<div className='window-titlebar'>
{props.icon ? (
<section className='window-titlebar-icon'>
<img src={props.icon} alt='titlebar icon' />
</section>
) : (
''
)}
<section
className={classNames('window-titlebar-content', {
centered: props.mode === 'centered-title',
})}
>
{menusVisible ? '' : <div className='window-title'>{props.title}</div>}
</section>
<section
className={classNames('window-titlebar-menu', {
hidden: !menusVisible,
})}
>
{titlebarMenus.map((item, menuIndex) => {
return (
<div className='menu-item' key={`menu_${menuIndex}`}>
<div
className='menu-title'
onClick={(e) => showMenu(menuIndex, e)}
onMouseEnter={() => onMenuHover(menuIndex)}
onMouseDown={(e) => e.preventDefault()}
>
{item.name}
</div>
<div className='menu-popup' ref={menusRef[menuIndex]}>
{item.items?.map((menuItem, menuItemIndex) => {
if (menuItem.name === '__') {
return (
<div
key={`menu_${menuIndex}_popup_item_${menuItemIndex}`}
className='popup-item-separator'
></div>
);
}
return (
<div
key={`menu_${menuIndex}_popup_item_${menuItemIndex}`}
className='menu-popup-item'
onClick={() =>
handleAction(menuItem.action, menuItem.value)
}
onMouseDown={(e) => e.preventDefault()}
>
<div className='popup-item-name'>{menuItem.name}</div>
<div className='popup-item-shortcut'>
{menuItem.shortcut}
</div>
</div>
);
})}
</div>
</div>
);
})}
</section>
<WindowControls platform={windowContext.platform} tooltips={true} />
</div>
);
};
export default Titlebar;
================================================
FILE: misc/window/components/WindowControls.tsx
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Controls - Close, Minimize, Maximize (Component)
*/
import classNames from 'classnames';
import React from 'react';
import context from '../titlebarContextApi';
import ControlButton from './ControlButton';
type Props = {
platform: string;
tooltips?: boolean;
};
const closePath =
'M 0,0 0,0.7 4.3,5 0,9.3 0,10 0.7,10 5,5.7 9.3,10 10,10 10,9.3 5.7,5 10,0.7 10,0 9.3,0 5,4.3 0.7,0 Z';
const maximizePath = 'M 0,0 0,10 10,10 10,0 Z M 1,1 9,1 9,9 1,9 Z';
const minimizePath = 'M 0,5 10,5 10,6 0,6 Z';
const WindowControls: React.FC<Props> = (props) => {
return (
<section
className={classNames(
'window-titlebar-controls',
`type-${props.platform}`,
)}
>
<ControlButton
name='minimize'
onClick={() => context.minimize()}
path={minimizePath}
title={props.tooltips ? 'Minimize' : null}
/>
<ControlButton
name='maximize'
onClick={() => context.toggle_maximize()}
path={maximizePath}
title={props.tooltips ? 'Maximize' : null}
/>
<ControlButton
name='close'
onClick={() => context.exit()}
path={closePath}
title={props.tooltips ? 'Close' : null}
/>
</section>
);
};
export default WindowControls;
================================================
FILE: misc/window/components/WindowFrame.tsx
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Window Frame (Component)
*/
import React, { useEffect, useRef } from 'react';
import Titlebar from './Titlebar';
const logo = require('@assets/images/logo.png')
type Props = {
title?: string;
borderColor?: string;
platform: 'windows' | 'mac';
children: React.ReactNode;
};
type Context = {
platform: 'windows' | 'mac';
};
export const WindowContext = React.createContext<Context>({
platform: 'windows',
});
const WindowFrame: React.FC<Props> = (props) => {
const itsRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const { parentElement } = itsRef.current;
parentElement.classList.add('has-electron-window');
parentElement.classList.add('has-border');
// Apply border color if prop given
if (props.borderColor) {
parentElement.style.borderColor = props.borderColor;
}
}, []);
return (
<WindowContext.Provider value={{ platform: props.platform }}>
{/* Reference creator */}
<div className='start-electron-window' ref={itsRef}></div>
{/* Window Titlebar */}
<Titlebar
title={props.title ?? 'Electron Window'}
mode='centered-title'
icon={logo}
/>
{/* Window Content (Application to render) */}
<div className='window-content'>{props.children}</div>
</WindowContext.Provider>
);
};
export default WindowFrame;
================================================
FILE: misc/window/titlebarContext.ts
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar IPC (Renderer Process)
*/
import { ipcRenderer } from 'electron';
const titlebarContext = {
exit() {
ipcRenderer.invoke('window-close');
},
undo() {
ipcRenderer.invoke('web-undo');
},
redo() {
ipcRenderer.invoke('web-redo');
},
cut() {
ipcRenderer.invoke('web-cut');
},
copy() {
ipcRenderer.invoke('web-copy');
},
paste() {
ipcRenderer.invoke('web-paste');
},
delete() {
ipcRenderer.invoke('web-delete');
},
select_all() {
ipcRenderer.invoke('web-select-all');
},
reload() {
ipcRenderer.invoke('web-reload');
},
force_reload() {
ipcRenderer.invoke('web-force-reload');
},
toggle_devtools() {
ipcRenderer.invoke('web-toggle-devtools');
},
actual_size() {
ipcRenderer.invoke('web-actual-size');
},
zoom_in() {
ipcRenderer.invoke('web-zoom-in');
},
zoom_out() {
ipcRenderer.invoke('web-zoom-out');
},
toggle_fullscreen() {
ipcRenderer.invoke('web-toggle-fullscreen');
},
minimize() {
ipcRenderer.invoke('window-minimize');
},
toggle_maximize() {
ipcRenderer.invoke('window-toggle-maximize');
},
open_url(url: string) {
ipcRenderer.invoke('open-url', url);
},
};
export type TitlebarContextApi = typeof titlebarContext;
export default titlebarContext;
================================================
FILE: misc/window/titlebarContextApi.ts
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar Context API
*/
import { TitlebarContextApi } from './titlebarContext';
const context: TitlebarContextApi = (window as any).api?.titlebar;
export default context;
================================================
FILE: misc/window/titlebarIPC.ts
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar IPC (Main Process)
*/
import { BrowserWindow, ipcMain, shell } from 'electron';
export const registerTitlebarIpc = (mainWindow: BrowserWindow) => {
ipcMain.handle('window-minimize', () => {
mainWindow.minimize();
});
ipcMain.handle('window-maximize', () => {
mainWindow.maximize();
});
ipcMain.handle('window-toggle-maximize', () => {
if (mainWindow.isMaximized()) {
mainWindow.unmaximize();
} else {
mainWindow.maximize();
}
});
ipcMain.handle('window-close', () => {
mainWindow.close();
});
ipcMain.handle('web-undo', () => {
mainWindow.webContents.undo();
});
ipcMain.handle('web-redo', () => {
mainWindow.webContents.redo();
});
ipcMain.handle('web-cut', () => {
mainWindow.webContents.cut();
});
ipcMain.handle('web-copy', () => {
mainWindow.webContents.copy();
});
ipcMain.handle('web-paste', () => {
mainWindow.webContents.paste();
});
ipcMain.handle('web-delete', () => {
mainWindow.webContents.delete();
});
ipcMain.handle('web-select-all', () => {
mainWindow.webContents.selectAll();
});
ipcMain.handle('web-reload', () => {
mainWindow.webContents.reload();
});
ipcMain.handle('web-force-reload', () => {
mainWindow.webContents.reloadIgnoringCache();
});
ipcMain.handle('web-toggle-devtools', () => {
mainWindow.webContents.toggleDevTools();
});
ipcMain.handle('web-actual-size', () => {
mainWindow.webContents.setZoomLevel(0);
});
ipcMain.handle('web-zoom-in', () => {
mainWindow.webContents.setZoomLevel(mainWindow.webContents.zoomLevel + 0.5);
});
ipcMain.handle('web-zoom-out', () => {
mainWindow.webContents.setZoomLevel(mainWindow.webContents.zoomLevel - 0.5);
});
ipcMain.handle('web-toggle-fullscreen', () => {
mainWindow.setFullScreen(!mainWindow.fullScreen);
});
ipcMain.handle('open-url', (e, url) => {
shell.openExternal(url);
});
};
================================================
FILE: misc/window/titlebarMenus.ts
================================================
/**
* Copyright (c) 2021, Guasam
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
* Read the LICENSE file for more details.
*
* @author : guasam
* @project : Electron Window
* @package : Titlebar Menu Items
*/
export type TitlebarMenuItem = {
name: string;
action?: string;
shortcut?: string;
value?: string | number;
items?: TitlebarMenuItem[];
};
export type TitlebarMenu = {
name: string;
items: TitlebarMenuItem[];
};
const titlebarMenus: TitlebarMenu[] = [
{
name: 'File',
items: [
{
name: 'Exit',
action: 'exit',
},
],
},
{
name: 'Edit',
items: [
{
name: 'Undo',
action: 'undo',
shortcut: 'Ctrl+Z',
},
{
name: 'Redo',
action: 'redo',
shortcut: 'Ctrl+Y',
},
{
name: '__',
},
{
name: 'Cut',
action: 'cut',
shortcut: 'Ctrl+X',
},
{
name: 'Copy',
action: 'copy',
shortcut: 'Ctrl+C',
},
{
name: 'Paste',
action: 'paste',
shortcut: 'Ctrl+V',
},
{
name: 'Delete',
action: 'delete',
},
{
name: '__',
},
{
name: 'Select All',
action: 'select_all',
shortcut: 'Ctrl+A',
},
],
},
{
name: 'View',
items: [
{
name: 'Reload',
action: 'reload',
shortcut: 'Ctrl+R',
},
{
name: 'Force Reload',
action: 'force_reload',
shortcut: 'Ctrl+Shift+R',
},
{
name: 'Toogle Developer Tools',
action: 'toggle_devtools',
shortcut: 'Ctrl+Shift+I',
},
{
name: '__',
},
{
name: 'Actual Size',
action: 'actual_size',
shortcut: 'Ctrl+0',
},
{
name: 'Zoom In',
action: 'zoom_in',
shortcut: 'Ctrl++',
},
{
name: 'Zoom Out',
action: 'zoom_out',
shortcut: 'Ctrl+-',
},
{
name: '__',
},
{
name: 'Toggle Fullscreen',
action: 'toggle_fullscreen',
shortcut: 'F11',
},
],
},
{
name: 'Window',
items: [
{
name: 'Minimize',
action: 'minimize',
shortcut: 'Ctrl+M',
},
{
name: 'Close',
action: 'exit',
shortcut: 'Ctrl+W',
},
],
},
{
name: 'Author',
items: [
{
name: 'Guasam',
action: 'open_url',
value: 'https://github.com/guasam',
shortcut: '@guasam',
},
],
},
];
export default titlebarMenus;
================================================
FILE: misc/window/windowPreload.ts
================================================
import { contextBridge, ipcRenderer } from 'electron';
import titlebarContext from './titlebarContext';
contextBridge.exposeInMainWorld('api', {
titlebar: titlebarContext,
send: (channel: string, data: string) => {
// whitelist channels
const validChannels = ['toMain'];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel: string, func: () => void) => {
const validChannels = [
'gotLoadedDataX',
'Home',
'Picture',
'gotAllPictures',
'gotPicture',
'Shortcuts',
'gotAllBlocks',
'openArchive',
'gotPageStyle',
'gotUserTheme',
'gotArchive',
'gotUserColor',
'gotOS',
'openFiles',
'newFile',
'Save',
'fromMain',
'Text',
'Graph',
'Math',
'Group',
'gotNotebooks',
'toggleNotebooks',
'Search',
];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...(args as [])));
}
},
getNotebooks: () => {
ipcRenderer.send('getNotebooks');
},
delete: (path: string, isFolder: boolean) => {
ipcRenderer.send('delete', path, isFolder);
},
newFile: (filePath: string) => {
ipcRenderer.send('newFile', filePath);
},
newFolder: (folderPath: string) => {
ipcRenderer.send('newFolder', folderPath);
},
openFiles: () => {
ipcRenderer.send('openFiles');
},
move: (oldPath: string, newPath: string) => {
ipcRenderer.send('move', oldPath, newPath);
},
save: (data: string, file: string, newName: string) => {
ipcRenderer.send('save', data, file, newName);
},
load: (file: string) => {
ipcRenderer.send('load', file);
},
saveX: (data: string, filePath: string) => {
ipcRenderer.send('saveX', data, filePath);
},
loadX: (filePath: string) => {
ipcRenderer.send('loadX',filePath);
},
getOS: () => {
ipcRenderer.send('getOS');
},
maximize: () => {
ipcRenderer.send('maximize');
},
unmaximize: () => {
ipcRenderer.send('unmaximize');
},
minimize: () => {
ipcRenderer.send('minimize');
},
close: () => {
ipcRenderer.send('close');
},
setUserColor: (color: string) => {
ipcRenderer.send('setUserColor', color);
},
setPageStyle: (style: string) => {
ipcRenderer.send('setPageStyle', style);
},
toggle: () => {
ipcRenderer.send('dark-mode');
},
getUserColor: () => {
ipcRenderer.send('getUserColor');
},
getPageStyle: () => {
ipcRenderer.send('getPageStyle');
},
getUserTheme: () => {
ipcRenderer.send('getUserTheme');
},
getPicture: (id: string) => {
ipcRenderer.send('getPicture', id);
},
getAllPictures: (path: string) => {
ipcRenderer.send('getAllPictures', path);
},
getArchive: () => {
ipcRenderer.send('getArchive');
},
startSearch: () => {
ipcRenderer.send('startSearch');
},
});
================================================
FILE: package.json
================================================
{
"name": "mathberet",
"productName": "Mathberet",
"version": "1.0.0",
"description": "Digital Mathematics Notebook",
"main": ".webpack/main",
"scripts": {
"start": "cross-env NODE_ENV=development electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "eslint src/ --ext .ts,.js,.tsx,.jsx"
},
"keywords": [
"react",
"javascript",
"typescript",
"math",
"mathematics",
"notebook",
"notes"
],
"author": {
"name": "yonatanmgr",
"url": "https://github.com/yonatanmgr"
},
"contributors": [
{
"name": "Erez Birenholz",
"url": "https://github.com/ErezBiren"
},
{
"name": "Ziv Nadel",
"url": "https://github.com/zivnadel"
},
{
"name": "Nadav Magier",
"url": "https://github.com/Nadav0077"
}
],
"repository": {
"type": "git",
"url": "https://github.com/yonatanmgr/mathberet"
},
"license": "MIT",
"config": {
"forge": "./tools/forge/forge.config.js"
},
"devDependencies": {
"@electron-forge/cli": "6.0.5",
"@electron-forge/maker-deb": "6.0.5",
"@electron-forge/maker-rpm": "6.0.5",
"@electron-forge/maker-squirrel": "6.0.5",
"@electron-forge/maker-zip": "6.0.5",
"@electron-forge/plugin-webpack": "6.0.5",
"@marshallofsound/webpack-asset-relocator-loader": "^0.5.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.10",
"@types/node": "^18.13.0",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/react-grid-layout": "^1.3.2",
"@types/webpack-env": "^1.18.0",
"@typescript-eslint/eslint-plugin": "^5.51.0",
"@typescript-eslint/parser": "^5.51.0",
"@vercel/webpack-asset-relocator-loader": "^1.7.3",
"classnames": "^2.3.2",
"cross-env": "^7.0.3",
"css-loader": "^6.7.3",
"electron": "^23.0.0",
"eslint": "^8.33.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-react": "^7.32.2",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^7.3.0",
"less": "^4.1.3",
"less-loader": "11.1.0",
"node-loader": "^2.0.0",
"react-refresh": "^0.14.0",
"sass": "^1.58.0",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"ts-loader": "9.4.2",
"typescript": "^4.9.5",
"webpack": "^5.75.0"
},
"dependencies": {
"@cortex-js/compute-engine": "^0.12.2",
"@flaticon/flaticon-uicons": "^2.0.1",
"@tldraw/tldraw": "^1.28.0",
"electron-squirrel-startup": "^1.0.0",
"electron-store": "^8.1.0",
"gridstack": "^7.2.3",
"i18next": "^22.4.11",
"kbar": "^0.1.0-beta.40",
"keyboard-css": "^1.2.4",
"mafs": "^0.15.2",
"mathjs": "^11.6.0",
"mathlive": "^0.87.1",
"react": "^18.2.0",
"react-complex-tree": "^2.1.1",
"react-dom": "^18.2.0",
"react-grid-layout": "^1.3.4",
"react-i18next": "^12.2.0",
"react-math-view": "^1.3.2",
"react-mathlive": "^3.0.5-preview.1",
"react-resizable": "^3.0.4",
"slate": "^0.91.4",
"slate-history": "^0.86.0",
"slate-react": "^0.91.8",
"tex-math-parser": "^2.0.4"
}
}
================================================
FILE: src/common/helpers.ts
================================================
/**
* Checks if process NODE_ENV in 'development' mode
*/
export function inDev(): boolean {
return process.env.NODE_ENV == 'development';
}
================================================
FILE: src/common/i18n.ts
================================================
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { HE_TRANSLATION } from './locals/he';
import { EN_TRANSLATION } from './locals/en';
import { RU_TRANSLATION } from './locals/ru';
import { AR_TRANSLATION } from './locals/ar';
import { ES_TRANSLATION } from './locals/es';
import { ZH_TRANSLATION } from './locals/zh';
import { FR_TRANSLATION } from './locals/fr';
import { HI_TRANSLATION } from './locals/hi';
const resources = {
ar: { translation: AR_TRANSLATION },
en: { translation: EN_TRANSLATION },
es: { translation: ES_TRANSLATION },
fr: { translation: FR_TRANSLATION },
he: { translation: HE_TRANSLATION },
hi: { translation: HI_TRANSLATION },
ru: { translation: RU_TRANSLATION },
zh: { translation: ZH_TRANSLATION },
};
i18n.use(initReactI18next).init({
resources,
lng: 'en',
fallbackLng: ['en', 'he'],
interpolation: {
escapeValue: false,
},
});
export default i18n;
================================================
FILE: src/common/keybindings.ts
================================================
import { Keybinding } from "mathlive"
const DEFAULT_KEYBINDINGS: Array<Keybinding> = [
{ key: "left", command: "moveToPreviousChar" },
{ key: "right", command: "moveToNextChar" },
{ key: "up", command: "moveUp" },
{ key: "down", command: "moveDown" },
{ key: "shift+[ArrowLeft]", command: "extendSelectionBackward" },
{ key: "shift+[ArrowRight]", command: "extendSelectionForward" },
{ key: "shift+[ArrowUp]", command: "extendSelectionUpward" },
{ key: "shift+[ArrowDown]", command: "extendSelectionDownward" },
{ key: "[Backspace]", command: "deleteBackward" },
{ key: "alt+[Delete]", command: "deleteBackward" },
{ key: "[Delete]", command: "deleteForward" },
{ key: "alt+[Backspace]", command: "deleteForward" },
{ key: "alt+[ArrowLeft]", command: "moveToPreviousWord" },
{ key: "alt+[ArrowRight]", command: "moveToNextWord" },
{ key: "shift+alt+[ArrowLeft]", command: "extendToPreviousWord" },
{ key: "shift+alt+[ArrowRight]", command: "extendToNextWord" },
{ key: "ctrl+[ArrowLeft]", command: "moveToGroupStart" },
{ key: "ctrl+[ArrowRight]", command: "moveToGroupEnd" },
{ key: "shift+ctrl+[ArrowLeft]", command: "extendToGroupStart" },
{ key: "shift+ctrl+[ArrowRight]", command: "extendToGroupEnd" },
{ key: "[Space]", ifMode: "math", command: "moveAfterParent" },
{ key: "shift+[Space]", ifMode: "math", command: "moveBeforeParent" },
{ key: "[Home]", command: "moveToMathfieldStart" },
{ key: "cmd+[ArrowLeft]", command: "moveToMathfieldStart" },
{ key: "shift+[Home]", command: "extendToMathFieldStart" },
{ key: "shift+cmd+[ArrowLeft]", command: "extendToMathFieldStart" },
{ key: "[End]", command: "moveToMathfieldEnd" },
{ key: "cmd+[ArrowRight]", command: "moveToMathfieldEnd" },
{ key: "shift+[End]", command: "extendToMathFieldEnd" },
{ key: "shift+cmd+[ArrowRight]", command: "extendToMathFieldEnd" },
{ key: "[Pageup]", command: "moveToGroupStart" },
{ key: "[Pagedown]", command: "moveToGroupEnd" },
{ key: "[Tab]", ifMode: "math", command: "moveToNextPlaceholder" },
{
key: "shift+[Tab]",
ifMode: "math",
command: "moveToPreviousPlaceholder"
},
{ key: "[Tab]", ifMode: "text", command: "moveToNextPlaceholder" },
{
key: "shift+[Tab]",
ifMode: "text",
command: "moveToPreviousPlaceholder"
},
{ key: "[Escape]", ifMode: "math", command: ["switchMode", "latex"] },
{ key: "[Escape]", ifMode: "text", command: ["switchMode", "latex"] },
{
key: "[Escape]",
ifMode: "latex",
command: ["complete", "complete", { selectItem: "true" }]
},
// Accept the entry (without the suggestion) and select
{
key: "\\",
ifMode: "math",
command: ["switchMode", "latex", "\\"]
},
// { key: '[Backslash]', ifMode: 'math', command: ['switchMode', 'latex'] },
{
key: "[IntlBackslash]",
ifMode: "math",
command: ["switchMode", "latex", "\\"]
},
// On UK QWERTY keyboards
{
key: "[Tab]",
ifMode: "latex",
command: ["complete", "accept-suggestion"]
},
// Complete the suggestion
{ key: "[Return]", ifMode: "latex", command: "complete" },
{ key: "[Enter]", ifMode: "latex", command: "complete" },
{
key: "shift+[Escape]",
ifMode: "latex",
command: ["complete", "reject"]
},
// Some keyboards can't generate
// this combination, for example in 60% keyboards it is mapped to ~
{ key: "[ArrowDown]", ifMode: "latex", command: "nextSuggestion" },
// { key: 'ios:command:[Tab]', ifMode: 'latex',command: 'nextSuggestion' },
{ key: "[ArrowUp]", ifMode: "latex", command: "previousSuggestion" },
{ key: "ctrl+a", ifPlatform: "!macos", command: "selectAll" },
{ key: "cmd+a", command: "selectAll" },
// Rare keys on some extended keyboards
{ key: "[Cut]", command: "cutToClipboard" },
{ key: "[Copy]", command: "copyToClipboard" },
{ key: "[Paste]", command: "pasteFromClipboard" },
{ key: "[Clear]", command: "deleteBackward" },
{ key: "ctrl+z", ifPlatform: "!macos", command: "undo" },
{ key: "cmd+z", command: "undo" },
{ key: "[Undo]", command: "undo" },
{ key: "ctrl+y", ifPlatform: "!macos", command: "redo" },
// ARIA recommendation
{ key: "shift+cmd+y", command: "redo" },
{ key: "shift+ctrl+z", ifPlatform: "!macos", command: "redo" },
{ key: "shift+cmd+z", command: "redo" },
{ key: "[Redo]", command: "redo" },
{ key: "[EraseEof]", command: "deleteToGroupEnd" },
// EMACS/MACOS BINDINGS
{ key: "ctrl+b", ifPlatform: "macos", command: "moveToPreviousChar" },
{ key: "ctrl+f", ifPlatform: "macos", command: "moveToNextChar" },
{ key: "ctrl+p", ifPlatform: "macos", command: "moveUp" },
{ key: "ctrl+n", ifPlatform: "macos", command: "moveDown" },
{ key: "ctrl+a", ifPlatform: "macos", command: "moveToMathfieldStart" },
{ key: "ctrl+e", ifPlatform: "macos", command: "moveToMathfieldEnd" },
{
key: "shift+ctrl+b",
ifPlatform: "macos",
command: "extendSelectionBackward"
},
{
key: "shift+ctrl+f",
ifPlatform: "macos",
command: "extendSelectionForward"
},
{
key: "shift+ctrl+p",
ifPlatform: "macos",
command: "extendSelectionUpward"
},
{
key: "shift+ctrl+n",
ifPlatform: "macos",
command: "extendSelectionDownward"
},
{
key: "shift+ctrl+a",
ifPlatform: "macos",
command: "extendToMathFieldStart"
},
{
key: "shift+ctrl+e",
ifPlatform: "macos",
command: "extendToMathFieldEnd"
},
{ key: "alt+ctrl+b", ifPlatform: "macos", command: "moveToPreviousWord" },
{ key: "alt+ctrl+f", ifPlatform: "macos", command: "moveToNextWord" },
{
key: "shift+alt+ctrl+b",
ifPlatform: "macos",
command: "extendToPreviousWord"
},
{
key: "shift+alt+ctrl+f",
ifPlatform: "macos",
command: "extendToNextWord"
},
{ key: "ctrl+h", ifPlatform: "macos", command: "deleteBackward" },
{ key: "ctrl+d", ifPlatform: "macos", command: "deleteForward" },
{ key: "ctrl+l", ifPlatform: "macos", command: "scrollIntoView" },
// { key: 'ctrl+t', ifPlatform: 'macos', command: 'transpose' },
// WOLFRAM MATHEMATICA BINDINGS
{
key: "ctrl+[Digit2]",
ifMode: "math",
command: ["insert", "\\sqrt{#0}"]
},
{ key: "ctrl+[Digit5]", ifMode: "math", command: "moveToOpposite" },
{ key: "ctrl+[Digit6]", ifMode: "math", command: "moveToSuperscript" },
{ key: "ctrl+[Return]", ifMode: "math", command: "addRowAfter" },
{ key: "ctrl+[Enter]", ifMode: "math", command: "addRowAfter" },
{ key: "cmd+[Return]", ifMode: "math", command: "addRowAfter" },
{ key: "cmd+[Enter]", ifMode: "math", command: "addRowAfter" },
// Excel keybindings:
// shift+space: select entire row, ctrl+space: select an entire column
// shift+ctrl++ or ctrl+numpad+
// ctrl+- to delete a row or columns
// MATHLIVE BINDINGS
// { key: 'alt+a', command: ['insert', '\\theta'] },
{ key: "alt+p", ifMode: "math", command: ["insert", "\\pi"] },
{ key: "alt+v", ifMode: "math", command: ["insert", "\\sqrt{#0}"] },
{
key: "alt+w",
ifMode: "math",
command: ["insert", "\\sum_{i=#?}^{#?}"]
},
{ key: "alt+b", command: ["insert", "\\int_{#?}^{#?}"] },
{ key: "alt+u", ifMode: "math", command: ["insert", "\\cup"] },
{ key: "alt+n", ifMode: "math", command: ["insert", "\\cap"] },
{ key: "alt+o", ifMode: "math", command: ["insert", "\\emptyset"] },
{
key: "alt+d",
ifMode: "math",
command: ["insert", "\\differentialD"]
},
{
key: "shift+alt+o",
ifMode: "math",
command: ["insert", "\\varnothing"]
},
{
key: "shift+alt+d",
ifMode: "math",
command: ["insert", "\\partial"]
},
{
key: "shift+alt+p",
ifMode: "math",
command: ["insert", "\\prod_{i=#?}^{#?}"]
},
{ key: "shift+alt+u", ifMode: "math", command: ["insert", "\\bigcup"] },
{ key: "shift+alt+n", ifMode: "math", command: ["insert", "\\bigcap"] },
{ key: "shift+alt+a", ifMode: "math", command: ["insert", "\\forall"] },
{ key: "shift+alt+e", ifMode: "math", command: ["insert", "\\exists"] },
{
key: "alt+[Backslash]",
ifMode: "math",
command: ["insert", "\\backslash"]
},
// "|" key} override command mode
{
key: "[NumpadDivide]",
ifMode: "math",
command: ["insert", "\\frac{#@}{#?}"]
},
// ??
{
key: "alt+[NumpadDivide]",
ifMode: "math",
command: ["insert", "\\frac{#?}{#@}"]
},
// ??
// Accessibility
{ key: "alt+k", command: "toggleVirtualKeyboard" },
// Note: On Mac OS (as of 10.12), there is a bug/behavior that causes
// a beep to be generated with certain command+control key combinations.
// The workaround is to create a default binding file to silence them.
// In ~/Library/KeyBindings/DefaultKeyBinding.dict add these entries:
//
// {
// "^@\UF701" = "noop:";
// "^@\UF702" = "noop:";
// "^@\UF703" = "noop:";
// }
// {
// key: "alt+ctrl+[ArrowUp]",
// command: ["speak", "all", { withHighlighting: false }]
// },
// {
// key: "alt+ctrl+[ArrowDown]",
// command: ["speak", "selection", { withHighlighting: false }]
// },
//
// Punctuations and some non-alpha key combinations
// only work with specific keyboard layouts
//
{
key: "alt+[Equal]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["applyStyle", { mode: "text" }]
},
{
key: "alt+[Equal]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "text",
command: ["applyStyle", { mode: "math" }]
},
{
key: "shift+[Quote]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["switchMode", "text", "", ""]
},
{
key: "shift+[Quote]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "text",
command: ["switchMode", "math", "", ""]
},
{
key: "/",
ifMode: "math",
command: ["insert", "\\frac{#@}{#?}"]
},
{
key: "alt+/",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "\\/"]
},
{
key: "alt+[BracketLeft]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "\\left\\lbrack #0 \\right\\rbrack"]
},
// ??
// {
// key: "ctrl+[Minus]",
// ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
// ifMode: "math",
// command: "moveToSubscript"
// },
// ??
{
key: "shift+alt+[BracketLeft]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "\\left\\lbrace #0 \\right\\rbrace"]
},
// ??
{
key: "ctrl+;",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addRowAfter"
},
{
key: "cmd+;",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addRowAfter"
},
{
key: "shift+ctrl+;",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addRowBefore"
},
{
key: "shift+cmd+;",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addRowBefore"
},
{
key: "ctrl+[Backspace]",
ifMode: "math",
command: "removeRow"
},
{
key: "cmd+[Backspace]",
ifMode: "math",
command: "removeRow"
},
{
key: "ctrl+[Comma]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addColumnAfter"
},
{
key: "cmd+[Comma]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addColumnAfter"
},
{
key: "shift+ctrl+[Comma]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addColumnBefore"
},
{
key: "shift+cmd+[Comma]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: "addColumnBefore"
},
{
key: "shift+[Backspace]",
ifMode: "math",
command: "removeColumn"
},
{
key: "alt+[Digit5]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "$\\infty"]
},
// "%" key
{
key: "alt+[Digit6]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "\\wedge"]
},
// "^" key
{
key: "shift+alt+[Digit6]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "\\vee"]
},
// "^" key
{
key: "alt+[Digit9]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "("]
},
// "(" key} override smartFence
{
key: "alt+[Digit0]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", ")"]
},
// ")" key} override smartFence
{
key: "alt+|",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "|"]
},
// "|" key} override smartFence
{
key: "shift+[Backquote]",
ifLayout: ["apple.en-intl", "windows.en-intl", "linux.en"],
ifMode: "math",
command: ["insert", "\\~"]
},
// ??
{
key: "[Backquote]",
ifLayout: ["windows.french", "linux.french"],
ifMode: "math",
command: ["insert", "^2"]
}
]
const CUSTOM_KEYBINDINGS: Array<Keybinding> = [
{
key: 'alt+[Equal]',
ifMode: 'math',
command: ['insert', '\\approx']
},
{
key: 'alt+[Comma]',
ifMode: 'math',
command: ['insert', '\\measuredangle']
},
{
key: 'alt+[Digit0]',
ifMode: 'math',
command: ['insert', '\\emptyset']
},
{
key: 'alt+[Enter]',
ifMode: 'math',
command: ['insert', '\\begin{gathered} {#?} \\end{gathered}']
},
{
key: 'alt+shift+c',
ifMode: 'math',
command: ['insert', '\\complement']
},
{
key: 'alt+shift+t',
ifMode: 'math',
command: ['insert', '\\triangle']
},
{
key: 'shift+[Enter]',
ifMode: 'math',
command: 'addRowAfter'
},
{
key: 'ctrl+[Equal]',
ifMode: 'math',
command: 'addColumnAfter'
},
{
key: 'ctrl+[Minus]',
ifMode: 'math',
command: 'removeColumn'
},
]
const ML_KEYBINDINGS = [DEFAULT_KEYBINDINGS, CUSTOM_KEYBINDINGS].flat()
export default ML_KEYBINDINGS
================================================
FILE: src/common/locals/ar.ts
================================================
export const AR_TRANSLATION = {
'My Notebooks': 'دفاتري',
'Command Bar': 'شريط الأوامر',
'Math Panel': 'لوحة الرياضيات',
Archive: 'الأرشيف',
'New Folder': 'مجلد جديد',
'New File': 'ملف جديد',
'Notebooks Tooltip': 'انقر مرتين لفتح الموقع',
Variables: 'متغيرات',
Functions: 'وظائف',
Prompt: 'اكتب أمرًا أو ابحث...',
Preferences: 'تفضيلات',
Theme: 'الوضع',
Color: 'لون التمييز',
Dark: 'مظلم',
Light: 'فاتح',
Language: 'اللغة 🌍',
Hebrew: 'العبرية - עברית',
Russian: 'الروسية - Русский',
'Mandarin Chinese': 'الصينية الماندرين - 中文普通话',
Hindi: 'هندي - हिंदी',
French: 'فرنسي - Française',
English: 'الإنجليزية - English',
Arabic: 'العربية',
Spanish: 'الأسبانية - Español',
Red: 'أحمر',
Blue: 'أزرق',
Green: 'أخضر',
Yellow: 'أصفر',
Purple: 'أرجواني',
Pink: 'وردي',
'Text Block': 'إضافة كتلة نصية',
'Math Block': 'إضافة كتلة رياضية',
'Graph Block': 'إضافة كتلة رسم بياني',
'Draw Block': 'إضافة كتلة رسم',
Divider: 'إضافة فاصل',
Clear: 'مسح الصفحة',
Save: 'حفظ',
'Add Tag': 'إضافة وسم',
'Placeholder 1': 'للبدء',
'Placeholder 2': 'انقر على رمز الدفتر على اليمين',
'Placeholder 3': 'وافتح / أنشئ ملفًا',
'Placeholder Or': 'أو',
'Modal 1': 'محو محتوى الصفحة؟',
'Modal 2': 'يوجد ملف جديد بالفعل',
'Modal 3': 'يوجد مجلد جديد بالفعل',
'Modal 4': 'هذا الاسم موجود بالفعل',
'Modal 5': 'لا يمكنك نقل هذا الملف هنا!',
Cancel: 'إلغاء',
OK: 'موافق',
Saved: 'تم حفظ الملف!',
'Save Error': 'خطأ أثناء حفظ الملف',
'Text Placeholder': 'إدراج نص...',
Press: 'اضغط على',
'Delete Item': 'على العنصر لحذفه',
'Rename Item': 'على العنصر لإعادة تسميته',
};
================================================
FILE: src/common/locals/en.ts
================================================
export const EN_TRANSLATION = {
'My Notebooks': 'Notebooks',
'Command Bar': 'Command Bar',
'Math Panel': 'Math Panel',
Archive: 'Archive',
'New Folder': 'New Folder',
'New File': 'New File',
'Notebooks Tooltip': 'Double click to open location',
Variables: 'Variables',
Functions: 'Functions',
Prompt: 'Type a command or search...',
Preferences: 'Preferences',
Theme: 'Theme',
Color: 'Accent Color',
Dark: 'Dark Theme',
Light: 'Light Theme',
Language: 'Language 🌍',
Hebrew: 'Hebrew - עברית',
Russian: 'Russian - Русский',
English: 'English',
Arabic: 'Arabic - العربية',
Spanish: 'Spanish - Español',
Hindi: 'Hindi - हिंदी',
'Mandarin Chinese': 'Mandarin Chinese - 中文普通话',
French: 'French - Française',
Red: 'Red',
Blue: 'Blue',
Green: 'Green',
Yellow: 'Yellow',
Purple: 'Purple',
Pink: 'Pink',
'Text Block': 'Add Text Block',
'Math Block': 'Add Math Block',
'Graph Block': 'Add Graph Block',
'Draw Block': 'Add Draw Block',
Divider: 'Add Divider',
Clear: 'Clear Page',
Save: 'Save',
'Add Tag': 'Add Tag',
'Placeholder 1': 'To begin',
'Placeholder 2': 'Click on the notebook icon on your left',
'Placeholder 3': 'and open/create a file',
'Placeholder Or': 'or',
'Modal 1': 'Clear page content?',
'Modal 2': 'A new file already exists',
'Modal 3': 'A new folder already exists',
'Modal 4': 'This name already exists',
'Modal 5': 'You cannot move this file here!',
Cancel: 'Cancel',
OK: 'OK',
Saved: 'File saved!',
'Save Error': 'Error while saving file',
'Text Placeholder': 'Insert text...',
Press: 'Press',
'Delete Item': 'on item to delete it',
'Rename Item': 'on item to rename it',
};
================================================
FILE: src/common/locals/es.ts
================================================
export const ES_TRANSLATION = {
'My Notebooks': 'Mis Cuadernos',
'Command Bar': 'Barra de Comandos',
'Math Panel': 'Panel de Matemáticas',
Archive: 'Archivo',
'New Folder': 'Nueva Carpeta',
'New File': 'Nuevo Archivo',
'Notebooks Tooltip': 'Haz doble clic para abrir la ubicación',
Variables: 'Variables',
Functions: 'Funciones',
Prompt: 'Escriba un comando o busque...',
Preferences: 'Preferencias',
Theme: 'Tema',
Color: 'Color de Acento',
Dark: 'Tema Oscuro',
Light: 'Tema Claro',
Language: 'Idioma 🌍',
Hebrew: 'Hebreo - עברית',
Russian: 'Ruso - Русский',
English: 'Inglés - English',
Arabic: 'Árabe - العربية',
Spanish: 'Español',
French: 'Francés - Française',
Hindi: 'hindi - हिंदी',
'Mandarin Chinese': 'Chino mandarín - 中文普通话',
Red: 'Rojo',
Blue: 'Azul',
Green: 'Verde',
Yellow: 'Amarillo',
Purple: 'Morado',
Pink: 'Rosado',
'Text Block': 'Agregar Bloque de Texto',
'Math Block': 'Agregar Bloque de Matemáticas',
'Graph Block': 'Agregar Bloque de Gráfico',
'Draw Block': 'Agregar Bloque de Dibujo',
Divider: 'Agregar Divisor',
Clear: 'Limpiar Página',
Save: 'Guardar',
'Add Tag': 'Agregar Etiqueta',
'Placeholder 1': 'Para comenzar',
'Placeholder 2': 'Haz clic en el icono del cuaderno a tu izquierda',
'Placeholder 3': 'y abre/crea un archivo',
'Placeholder Or': 'o',
'Modal 1': '¿Borrar contenido de la página?',
'Modal 2': 'Ya existe un nuevo archivo',
'Modal 3': 'Ya existe una nueva carpeta',
'Modal 4': 'Este nombre ya existe',
'Modal 5': '¡No puede mover este archivo aquí!',
Cancel: 'Cancelar',
OK: 'OK',
Saved: '¡Archivo guardado!',
'Save Error': 'Error al guardar archivo',
'Text Placeholder': 'Inserte texto...',
Press: 'Prensa',
'Delete Item': 'en el elemento para eliminarlo',
'Rename Item': 'en el elemento para cambiarle el nombre',
};
================================================
FILE: src/common/locals/fr.ts
================================================
export const FR_TRANSLATION = {
'My Notebooks': 'Mes carnets',
'Command Bar': 'Barre de commande',
'Math Panel': 'Panneau mathématique',
Archive: 'Archivo',
'New Folder': 'Nouveau dossier',
'New File': 'Nouveau fichier',
'Notebooks Tooltip': `Double-cliquez pour ouvrir l'emplacement`,
Variables: 'Variables',
Functions: 'Les fonctions',
Prompt: 'Tapez une commande ou recherchez...',
Preferences: 'Préférences',
Theme: 'Thème',
Color: `Couleur d'accentuation`,
Dark: 'Mode sombre',
Light: 'Mode lumière',
Language: 'Langue 🌍',
Hebrew: 'Hébreu - עברית',
Russian: 'Russe - Русский',
English: 'Anglaise - English',
Arabic: 'Arabe - العربية',
Hindi: 'hindi - हिंदी',
'Mandarin Chinese': 'Chinois Mandarin - 中文普通话',
French: 'Française',
Red: 'Rouge',
Blue: 'Bleu',
Green: 'Vert',
Yellow: 'Jaune',
Purple: 'Violet',
Pink: 'Rose',
'Text Block': 'Ajouter un bloc de texte',
'Math Block': 'Ajouter un bloc mathématique',
'Graph Block': 'Ajouter un bloc graphique',
'Draw Block': 'Ajouter un bloc de dessin',
Divider: 'Ajouter un diviseur',
Clear: 'Effacer la page',
Save: 'Enregistrer le fichier',
'Add Tag': 'Ajouter une étiquette',
'Placeholder 1': 'Pour commencer',
'Placeholder 2': `Cliquez sur l'icône du bloc-notes à votre gauche`,
'Placeholder 3': 'et ouvrir/créer un fichier',
'Placeholder Or': 'ou',
'Modal 1': 'Effacer le contenu de la page ?',
'Modal 2': 'Un nouveau fichier existe déjà',
'Modal 3': 'Un nouveau dossier existe déjà',
'Modal 4': 'Ce nom existe déjà',
'Modal 5': 'Vous ne pouvez pas déplacer ce fichier ici !',
Cancel: 'Annuler',
OK: 'OK',
Saved: 'Fichier enregistré !',
'Save Error': `Erreur lors de l'enregistrement du fichier`,
'Text Placeholder': 'Insérer du texte...',
Press: 'Appuyez',
'Delete Item': "sur l'élément pour le supprimer",
'Rename Item': "sur l'élément pour le renommer",
};
================================================
FILE: src/common/locals/he.ts
================================================
export const HE_TRANSLATION = {
'My Notebooks': 'המחברות שלי',
'Command Bar': 'חיפוש ופקודות',
'Math Panel': 'זיכרון מתמטי',
Archive: 'הארכיון שלי',
'New Folder': 'תיקייה חדשה',
'New File': 'קובץ חדש',
'Notebooks Tooltip': 'לחצו פעמיים כדי לפתוח את התיקייה',
Variables: 'משתנים',
Functions: 'פונקציות',
Prompt: 'הקלידו פקודה או חפשו...',
Preferences: 'העדפות משתמש',
Theme: 'ערכת נושא',
Color: 'צבע נושא',
Dark: 'מצב חושך',
Light: 'מצב אור',
Language: 'שפה 🌍',
Hebrew: 'עברית',
Russian: 'רוסית - Русский',
English: 'אנגלית - English',
Spanish: 'ספרדית - Español',
Arabic: 'ערבית - العربية',
Hindi: 'הינדי - हिंदी',
'Mandarin Chinese': 'סינית מנדרינית - 中文普通话',
French: 'צרפתית - Française',
Red: 'אדום',
Blue: 'כחול',
Green: 'ירוק',
Yellow: 'צהוב',
Purple: 'סגול',
Pink: 'ורוד',
'Text Block': 'הוספת בלוק טקסט',
'Math Block': 'הוספת בלוק מתמטי',
'Graph Block': 'הוספת בלוק גרפי',
'Draw Block': 'הוספת בלוק ציור',
Divider: 'הוספת קו מפריד',
Clear: 'ניקוי הדף',
Save: 'שמירה',
'Add Tag': 'הוספת תגית',
'Placeholder 1': 'כדי להתחיל',
'Placeholder 2': 'לחצו על כפתור המחברות בצד ימין',
'Placeholder 3': 'ובחרו/צרו קובץ',
'Placeholder Or': 'או',
'Modal 1': 'לנקות את כל תוכן הדף?',
'Modal 2': 'קובץ חדש כבר קיים',
'Modal 3': 'תיקייה חדשה כבר קיימת',
'Modal 4': 'השם הזה כבר קיים',
'Modal 5': 'לא ניתן לגרור קובץ זה לכאן!',
Cancel: 'ביטול',
OK: 'אישור',
Saved: 'הקובץ נשמר!',
'Save Error': 'התרחשה שגיאה בשמירת הקובץ',
'Text Placeholder': 'כתבו טקסט כאן...',
Press: 'לחצו',
'Delete Item': 'על פריט כדי למחוק אותו',
'Rename Item': 'על פריט כדי לשנות את שמו',
};
================================================
FILE: src/common/locals/hi.ts
================================================
export const HI_TRANSLATION = {
'My Notebooks': 'नोटबुक',
'Command Bar': 'कमांड बार',
'Math Panel': 'गणित पैनल',
Archive: 'आर्काइव',
'New Folder': 'नया फ़ोल्डर',
'New File': 'नया फ़ाइल',
'Notebooks Tooltip': 'जगह खोलने के लिए दोहराएँ क्लिक करें',
Variables: 'वेरिएबल्स',
Functions: 'फंक्शन्स',
Prompt: 'कमांड टाइप करें या खोजें...',
Preferences: 'प्राथमिकताएं',
Theme: 'थीम',
Color: 'एक्सेंट रंग',
Dark: 'डार्क थीम',
Light: 'लाइट थीम',
Language: 'भाषा 🌍',
Hebrew: 'हिब्रू - עברית',
Russian: 'रूसी - Русский',
English: 'अंग्रेज़ी - English',
Arabic: 'अरबी - العربية',
Spanish: 'स्पेनिश - Español',
Hindi: 'हिंदी',
'Mandarin Chinese': 'मंडारिन चाइनीज़ - 中文普通话',
French: 'फ़्रेंच - Française',
Red: 'लाल',
Blue: 'नीला',
Green: 'हरा',
Yellow: 'पीला',
Purple: 'बैंगनी',
Pink: 'गुलाबी',
'Text Block': 'टेक्स्ट ब्लॉक जोड़ें',
'Math Block': 'गणित ब्लॉक जोड़ें',
'Graph Block': 'ग्राफ़ ब्लॉक जोड़ें',
'Draw Block': 'ड्रॉ ब्लॉक जोड़ें',
Divider: 'डिवाइडर जोड़ें',
Clear: 'पृष्ठ साफ करें',
Save: 'सहेजें',
'Add Tag': 'टैग जोड़ें',
'Placeholder 1': 'शुरू करने के लिए',
'Placeholder 2': 'अपने बाएँ नोटबुक',
'Placeholder 3': 'और फ़ाइल खोलें/बनाएं',
'Placeholder Or': 'या',
'Modal 1': 'पृष्ठ साफ़ करें?',
'Modal 2': 'एक नया फ़ाइल पहले से ही मौजूद है',
'Modal 3': 'एक नया फ़ोल्डर पहले से ही मौजूद है',
'Modal 4': 'यह नाम पहले से ही मौजूद है',
'Modal 5': 'आप इस फाइल को यहां नहीं ले जा सकते!',
Cancel: 'रद्द करें',
OK: 'ठीक है',
Saved: 'फ़ाइल सहेजी गई!',
'Save Error': 'फ़ाइल सहेजते समय त्रुटि',
'Text Placeholder': 'टेक्स्ट डालें...',
Press: 'प्रेस',
'Delete Item': 'इसे हटाने के लिए आइटम पर',
'Rename Item': 'इसका नाम बदलने के लिए आइटम पर',
};
================================================
FILE: src/common/locals/ru.ts
================================================
export const RU_TRANSLATION = {
'My Notebooks': 'Мои блокноты',
'Command Bar': 'Поиск и команды',
'Math Panel': 'Математическая панель',
Archive: 'Архив',
'New Folder': 'Новая папка',
'New File': 'Новый файл',
'Notebooks Tooltip': 'Дважды щелкните, чтобы открыть папку',
Variables: 'Переменные',
Functions: 'Функции',
Prompt: 'Введите команду или искать...',
Preferences: 'Настройки пользователя',
Theme: 'Тема',
Color: 'Цвет темы',
Dark: 'Темный режим',
Light: 'Светлый режим',
Language: 'Язык 🌍',
Hebrew: 'Иврит - עברית',
English: 'Английский - English',
Russian: 'Русский',
Arabic: 'арабский - العربية',
Spanish: 'испанский - Español',
Hindi: 'хинди - हिंदी',
'Mandarin Chinese': 'Мандариновый китайский - 中文普通话',
French: 'Французский - Française',
Red: 'Красный',
Blue: 'Синий',
Green: 'Зеленый',
Yellow: 'Желтый',
Purple: 'Фиолетовый',
Pink: 'Розовый',
'Text Block': 'Добавить блок текста',
'Math Block': 'Добавить математический блок',
'Graph Block': 'Добавить блок графика',
'Draw Block': 'Добавить блок рисунка',
Divider: 'Добавить разделитель',
Clear: 'Очистить страницу',
Save: 'Сохранить',
'Add Tag': 'Добавить тег',
'Placeholder 1': 'Чтобы начать',
'Placeholder 2': 'Нажмите на кнопку блокнотов в правой панели',
'Placeholder 3': 'Выберите/создайте файл',
'Placeholder Or': 'или',
'Modal 1': 'Очистить всё содержимое страницы?',
'Modal 2': 'Такой файл уже существует',
'Modal 3': 'Такая папка уже существует',
'Modal 4': 'Это имя уже используется',
'Modal 5': 'Вы не можете переместить этот файл сюда!',
Cancel: 'Отмена',
OK: 'ОК',
Saved: 'Файл сохранен!',
'Save Error': 'Произошла ошибка при сохранении файла',
'Text Placeholder': 'Введите текст здесь...',
Press: 'Нажмите',
'Delete Item': 'на элементе, чтобы удалить его',
'Rename Item': 'на элементе, чтобы переименовать его',
};
================================================
FILE: src/common/locals/zh.ts
================================================
//Mandarin Chinese
export const ZH_TRANSLATION = {
'My Notebooks': '笔记本',
'Command Bar': '命令栏',
'Math Panel': '数学面板',
Archive: '存档',
'New Folder': '新建文件夹',
'New File': '新建文件',
'Notebooks Tooltip': '双击打开位置',
Variables: '变量',
Functions: '函数',
Prompt: '输入命令或搜索...',
Preferences: '首选项',
Theme: '主题',
Color: '强调颜色',
Dark: '暗色主题',
Light: '亮色主题',
Language: '语言 🌍',
Hebrew: '希伯来语 - עברית',
Russian: '俄语 - Русский',
English: '英语 - English',
Arabic: '阿拉伯语 - العربية',
Spanish: '西班牙语 - Español',
French: '法语 - Française',
'Mandarin Chinese': '中文普通话',
Hindi: '印地语 - हिंदी',
Red: '红色',
Blue: '蓝色',
Green: '绿色',
Yellow: '黄色',
Purple: '紫色',
Pink: '粉红色',
'Text Block': '添加文本块',
'Math Block': '添加数学块',
'Graph Block': '添加图表块',
'Draw Block': '添加绘图块',
Divider: '添加分隔线',
Clear: '清空页面',
Save: '保存',
'Add Tag': '添加标签',
'Placeholder 1': '开始',
'Placeholder 2': '单击左侧的笔记本图标',
'Placeholder 3': '并打开/创建文件',
'Placeholder Or': '或',
'Modal 1': '清空页面内容?',
'Modal 2': '一个新文件已经存在',
'Modal 3': '一个新文件夹已经存在',
'Modal 4': '此名称已经存在',
'Modal 5': '您不能在此处移动此文件',
Cancel: '取消',
OK: '确定',
Saved: '文件已保存!',
'Save Error': '保存文件时出错',
'Text Placeholder': '插入文本...',
Press: '按',
'Delete Item': '在项目上删除它',
'Rename Item': '在项目上重命名它',
};
================================================
FILE: src/common/shortcuts.ts
================================================
import { InlineShortcutDefinition } from "mathlive";
const ML_SHORTCUTS: Record<string, InlineShortcutDefinition> = {
'sr': {after: 'letter+digit', value: '^2'},
'cu': {after: 'letter+digit', value: '^3'},
'&': '\\&',
'%': '\\%',
'@': '\\degree',
'nCk': '\\binom',
'vec': '\\vec{#?}',
'gg': '\\hat{#?}',
'^^': '\\land',
'tbl': '\\begin{array}{|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|c|} {#?} & {#?} \\\\ {#?} & {#?} \\end{array}',
'mx': '\\begin{matrix} {#?} & {#?} \\\\ {#?} & {#?} \\end{matrix}',
'mx22': '\\begin{matrix} {#?} & {#?} \\\\ {#?} & {#?} \\end{matrix}',
'mx32': '\\begin{matrix} {#?} & {#?} \\\\ {#?} & {#?} \\\\ {#?} & {#?} \\end{matrix}',
'mx42': '\\begin{matrix} {#?} & {#?} \\\\ {#?} & {#?} \\\\ {#?} & {#?} \\\\ {#?} & {#?} \\end{matrix}',
'mx23': '\\begin{matrix} {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} \\end{matrix}',
'mx33': '\\begin{matrix} {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} \\end{matrix}',
'mx43': '\\begin{matrix} {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} \\end{matrix}',
'mx24': '\\begin{matrix} {#?} & {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} & {#?} \\end{matrix}',
'mx34': '\\begin{matrix} {#?} & {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} & {#?} \\end{matrix}',
'mx44': '\\begin{matrix} {#?} & {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} & {#?} \\\\ {#?} & {#?} & {#?} & {#?} \\end{matrix}',
'cas': '\\begin{cases} {#?} & {#?} \\\\ {#?} & {#?} \\end{cases}',
'mul': '\\begin{gather} {#?} \\end{gather}',
// Primes
"''": '^{\\doubleprime}',
'&a': '\\alpha',
'&b': '\\beta',
'&g': '\\gamma',
'&d': '\\delta',
'&e': '\\varepsilon',
'&z': '\\zeta',
'&et': '\\eta',
'&t': '\\theta',
'&i': '\\iota',
'&k': '\\kappa',
'&l': '\\lambda',
'&m': '\\mu',
'&n': '\\nu',
'&x': '\\xi',
'&o': '\\omicron',
'&p': '\\pi',
'&r': '\\rho',
'&s': '\\sigma',
'&ta': '\\tau',
'&u': '\\upsilon',
'&ph': '\\phi',
'&c': '\\chi',
'&ps': '\\psi',
'&om': '\\omega',
'&A': '\\Alpha',
'&B': '\\Beta',
'&G': '\\Gamma',
'&D': '\\Delta',
'&E': '\\Epsilon',
'&Z': '\\Zeta',
'&Et': '\\Eta',
'&T': '\\Theta',
'&I': '\\Iota',
'&K': '\\Kappa',
'&L': '\\Lambda',
'&M': '\\Mu',
'&N': '\\Nu',
'&X': '\\Xi',
'&O': '\\Omicron',
'&P': '\\Pi',
'&R': '\\Rho',
'&S': '\\Sigma',
'&Ta': '\\Tau',
'&U': '\\Upsilon',
'&Ph': '\\Phi',
'&C': '\\Chi',
'&Ps': '\\Psi',
'&Om': '\\Omega',
// Greek letters
'alpha': '\\alpha',
'delta': '\\delta',
'Delta': '\\Delta',
'pi': '\\pi',
'Pi': '\\Pi',
'theta': '\\theta',
'Theta': '\\Theta',
'0': {after: 'letter', value: '_0'},
'1': {after: 'letter', value: '_1'},
'2': {after: 'letter', value: '_2'},
'3': {after: 'letter', value: '_3'},
'4': {after: 'letter', value: '_4'},
'5': {after: 'letter', value: '_5'},
'6': {after: 'letter', value: '_6'},
'7': {after: 'letter', value: '_7'},
'8': {after: 'letter', value: '_8'},
'9': {after: 'letter', value: '_9'},
'x': {after: 'function', value: '(x)'},
'an': 'a_n',
'ann': '\\{ a_n \\} _{n=1}^{\\infty}',
// Letter-like
'ii': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\imaginaryI',
},
'jj': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\imaginaryJ',
},
'ee': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\exponentialE',
},
'nabla': '\\nabla',
'grad': '\\nabla',
'del': '\\partial',
'deg': {
after: 'digit+space',
value: '\\degree'
},
'infty': '\\infty',
'\u221E': '\\infty', // @TODO: doesn't work
// '∞': '\\infty',
// '∞': '\\infty',
'oo': {
after: 'nothing+digit+frac+surd+binop+relop+punct+array+openfence+closefence+space',
value: '\\infty',
},
// Big operators
'∑': '\\sum',
'abs': '||{#?}||',
'sum': '\\sum_{#?}^{#?}',
'intt': '\\int',
'int': '\\int_{#?}^{#?}',
'intfx': '\\int_{#?}^{#?} f(x) \\differentialD x =',
'intgx': '\\int_{#?}^{#?} g(x) \\differentialD x =',
'inthx': '\\int_{#?}^{#?} h(x) \\differentialD x =',
'prod': '\\prod_{#?}^{#?}',
'nv': '\\sqrt[#?]{#?}',
// '∫': '\\int', // There's a alt-B command for this
'∆': '\\differentialD', // @TODO: is \\diffD most common?
'∂': '\\differentialD',
// Functions
'arcsin': '\\arcsin',
'arccos': '\\arccos',
'arctan': '\\arctan',
'arcsec': '\\arcsec',
'arccsc': '\\arccsc',
'arsinh': '\\arsinh',
'arcosh': '\\arcosh',
'artanh': '\\artanh',
'arcsech': '\\arcsech',
'arccsch': '\\arccsch',
'arg': '\\arg',
'ch': '\\ch',
'cosec': '\\cosec',
'cosh': '\\cosh',
'cot': '\\cot',
'cotg': '\\cotg',
'coth': '\\coth',
'csc': '\\csc',
'ctg': '\\ctg',
'cth': '\\cth',
'sec': '\\sec',
'sinh': '\\sinh',
'sh': '\\sh',
'tanh': '\\tanh',
'tg': '\\tg',
'th': '\\th',
'sin': '\\sin',
'cos': '\\cos',
'tan': '\\tan',
'lg': '\\lg',
'lb': '\\lb',
'log': '\\log',
'ln': '\\ln',
'exp': '\\exp',
'lim': '\\lim_{#?}',
'limfx': '\\lim_{x \\to a} f(x)=',
'limgx': '\\lim_{x \\to a} g(x)=',
'limhx': '\\lim_{x \\to a} h(x)=',
// Differentials
// According to ISO31/XI (ISO 80000-2), differentials should be upright
'dx': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\differentialD x',
},
'dy': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\differentialD y',
},
'dt': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\differentialD t',
},
// Logic
'AA': '\\forall',
'EE': '\\exists',
'!EE': '\\nexists',
'&&': '\\land',
'VV': '\\lor',
// The shortcut for the greek letter "xi" is interfering with "x in"
'xin': {
after: 'nothing+text+relop+punct+openfence+space',
value: 'x \\in',
},
'in': {
after: 'nothing+letter+closefence',
value: '\\in',
},
'!in': '\\notin',
'sub': '\\subset',
'subb': '\\subseteq',
'set': '\\Set{ {#?} | {#?} }',
// Sets
'NN': '\\mathbb{N}', // Natural numbers
'ZZ': '\\Z', // Integers
'QQ': '\\Q', // Rational numbers
'RR': '\\R', // Real numbers
'CC': '\\C', // Complex numbers
// Operators
'xx': '\\times',
'+-': '\\pm',
'-+': '\\mp',
// Relational operators
'≠': '\\ne',
'!=': '\\ne',
'\u2265': '\\ge',
'>=': '\\ge',
'\u2264': '\\le',
'<=': '\\le',
'<<': '\\ll',
'>>': '\\gg',
'~~': '\\approx',
// More operators
'≈': '\\approx',
'?=': '\\questeq',
'÷': '\\div',
'¬': '\\neg',
'not': '\\neg',
':=': '\\coloneq',
'::': '\\coloneq',
'TT': '\\perp',
'II': '\\parallel',
// Fences
'(:': '\\langle',
':)': '\\rangle',
// More Greek letters
'beta': '\\beta',
'chi': '\\chi',
'eps': '\\epsilon',
'varepsilon': '\\varepsilon',
'eta': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\eta',
},
'gamma': '\\gamma',
'Gamma': '\\Gamma',
'iota': '\\iota',
'kappa': '\\kappa',
'lambda': '\\lambda',
'Lambda': '\\Lambda',
'mu': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\mu',
},
'nu': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\nu',
},
'µ': '\\mu', // @TODO: or micro?
'phi': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\phi',
},
'Phi': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\Phi',
},
'varphi': '\\varphi',
'psi': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\psi',
},
'Psi': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\Psi',
},
'rho': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\rho',
},
'sigma': '\\sigma',
'Sigma': '\\Sigma',
'tau': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\tau',
},
'vartheta': '\\vartheta',
'ups': '\\upsilon',
'xi': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space',
value: '\\xi',
},
'Xi': {
after: 'nothing+digit+function+frac+surd+binop+relop+punct+array+openfence+closefence+space+text',
value: '\\Xi',
},
'zeta': '\\zeta',
'omega': '\\omega',
'Omega': '\\Omega',
'Ω': '\\omega', // @TODO: or ohm?
// More Logic
'forall': '\\forall',
'exists': '\\exists',
'!exists': '\\nexists',
':.': '\\therefore',
'.:': '\\because',
// MORE FUNCTIONS
// 'arg': '\\arg',
'liminf': '\\liminf_{#?}',
'limsup': '\\limsup_{#?}',
'argmin': '\\operatorname*{arg~min}_{#?}',
'argmax': '\\operatorname*{arg~max}_{#?}',
'det': '\\det',
'mod': '\\mod',
'max': '\\max',
'min': '\\min',
'erf': '\\operatorname{erf}',
'erfc': '\\operatorname{erfc}',
'bessel': '\\operatorname{bessel}',
'mean': '\\operatorname{mean}',
'median': '\\operatorname{median}',
'fft': '\\operatorname{fft}',
'lcm': '\\operatorname{lcm}',
'gcd': '\\operatorname{gcd}',
'randomReal': '\\operatorname{randomReal}',
'randomInteger': '\\operatorname{randomInteger}',
'Re': '\\operatorname{Re}',
'Im': '\\operatorname{Im}',
// UNITS
'mm': {
after: 'nothing+digit+operator',
value: '\\operatorname{mm}', // Millimeter
},
'cm': {
after: 'nothing+digit+operator',
value: '\\operatorname{cm}', // Centimeter
},
'km': {
after: 'nothing+digit+operator',
value: '\\operatorname{km}', // Kilometer
},
'kg': {
after: 'nothing+digit+operator',
value: '\\operatorname{kg}', // Kilogram
},
// '||': '\\lor',
'...': '\\ldots', // In general, use \ldots
'+...': '+\\cdots', // ... but use \cdots after + ...
'-...': '-\\cdots', // ... - and ...
'->...': '\\to\\cdots', // ->
'to': '\\to',
'->': '\\to',
'|->': '\\mapsto',
'-->': '\\longrightarrow',
'up': '\\nearrow',
'down': '\\searrow',
// '<-': '\\leftarrow',
'<--': '\\longleftarrow',
'=>': '\\Rightarrow',
'==': '\\equiv',
'==>': '\\Longrightarrow',
// '<=': '\\Leftarrow', // CONFLICTS WITH LESS THAN OR EQUAL
'<=>': '\\Leftrightarrow',
'<->': '\\leftrightarrow',
'(.)': '\\odot',
'(+)': '\\oplus',
'(/)': '\\oslash',
'(*)': '\\otimes',
'(-)': '\\ominus',
// '(-)': '\\circleddash',
'||': '\\Vert',
'{': '\\{',
'}': '\\}',
'*': '\\cdot',
/*
//
// ASCIIIMath
//
// Binary operation symbols
'**': '\\ast',
'***': '\\star',
'//': '\\slash',
'\\\\': '\\backslash',
'setminus': '\\backslash',
'|><': '\\ltimes',
'><|': '\\rtimes',
'|><|': '\\bowtie',
'-:': '\\div',
'divide': '\\div',
'@': '\\circ',
'o+': '\\oplus',
'ox': '\\otimes',
'o.': '\\odot',
'^^': '\\wedge',
'^^^': '\\bigwedge',
'vv': '\\vee',
'vvv': '\\bigvee',
'nn': '\\cap',
'nnn': '\\bigcap',
'uu': '\\cup',
'uuu': '\\bigcup',
// Binary relation symbols
'-=': '\\equiv',
'~=': '\\cong',
'lt': '<',
'lt=': '\\leq',
'gt': '>',
'gt=': '\\geq',
'-<': '\\prec',
'-lt': '\\prec',
'-<=': '\\preceq',
// '>-': '\\succ',
'>-=': '\\succeq',
'prop': '\\propto',
'diamond': '\\diamond',
'square': '\\square',
'iff': '\\iff',
'sub': '\\subset',
'sup': '\\supset',
'sube': '\\subseteq',
'supe': '\\supseteq',
'uarr': '\\uparrow',
'darr': '\\downarrow',
'rarr': '\\rightarrow',
'rArr': '\\Rightarrow',
'larr': '\\leftarrow',
'lArr': '\\Leftarrow',
'harr': '\\leftrightarrow',
'hArr': '\\Leftrightarrow',
'aleph': '\\aleph',
// Logic
'and': '\\land',
'or': '\\lor',
'not': '\\neg',
'_|_': '\\bot',
'TT': '\\top',
'|--': '\\vdash',
'|==': '\\models',
// Other functions
'|__': '\\lfloor',
'__|': '\\rfloor',
'|~': '\\lceil',
'~|': '\\rceil',
// Arrows
'>->': '\\rightarrowtail',
'->>': '\\twoheadrightarrow',
'>->>': '\\twoheadrightarrowtail'
*/
};
export default ML_SHORTCUTS
================================================
FILE: src/main/Onboarding.js
================================================
const onboardingContent = {
"blocks": [
{
"w": 8,
"h": 2,
"x": 0,
"y": 0,
"i": "de34c56c-ffa2-467a-a769-f5827c8c8802",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-one",
"children": [{ "text": "Welcome to Mathberet! 👋" }]
}
]
}
},
{
"w": 8,
"h": 5,
"x": 0,
"y": 2,
"i": "a1ec4ffb-20d8-4972-b5bb-9ef3efcc5711",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "paragraph",
"children": [
{
"text": "Mathberet is an open-source digital mathematics notebook written in React and TypeScript, designed for math students who need a platform for graphing, sketching, and writing in LaTeX. The goal here is to create a learning platform that allows students to write mathematical statements fluently and easily, in addition to sketching, graphing and arranging notes as freely as in a real-life notebook. We're also trying to keep the UI as clean and user-friendly as possible, allowing students to make the most out of their learning without thinking about the app itself. As a self-hosted application, Mathberet is both free and customizable, providing a reliable and efficient tool that works anywhere and anytime."
}
]
},
{ "type": "paragraph", "children": [{ "text": "Important note:" }] },
{
"type": "paragraph",
"children": [
{
"text": "🚧 Mathberet is still in development! 🚧 - If you encounter a bug, please open an issue on our GitHub repo!"
}
]
}
]
}
},
{
"w": 3,
"h": 4,
"x": 0,
"y": 10,
"i": "4c8f483d-88a3-43a3-ac4c-5ed69a8af189",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-two",
"children": [{ "text": "How do I add blocks?" }]
},
{
"type": "bulleted-list",
"children": [
{
"type": "list-item",
"children": [
{
"text": "Move your mouse to the bottom of this page to view the toolbar."
}
]
},
{
"type": "list-item",
"children": [{ "text": "Click on any of the buttons." }]
}
]
}
]
}
},
{
"w": 8,
"h": 1,
"x": 0,
"y": 7,
"i": "b7fb5109-713d-4ee2-aa4b-d2734b87e466",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 1,
"moved": false,
"static": false,
"type": 0,
"metaData": {}
},
{
"w": 3,
"h": 4,
"x": 0,
"y": 18,
"i": "348f049f-3c34-4da9-bab4-6c49e637a494",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-two",
"children": [{ "text": "How do I save files?" }]
},
{
"type": "bulleted-list",
"children": [
{
"type": "list-item",
"children": [
{
"text": "Move your mouse to the bottom of this page to view the toolbar."
}
]
},
{
"type": "list-item",
"children": [{ "text": "Click on the save button." }]
}
]
}
]
}
},
{
"w": 3,
"h": 4,
"x": 0,
"y": 14,
"i": "9249ad8b-238a-4020-a521-c41f961c5973",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-two",
"children": [{ "text": "How do I clear the page?" }]
},
{
"type": "bulleted-list",
"children": [
{
"type": "list-item",
"children": [
{
"text": "Move your mouse to the bottom of this page to view the toolbar."
}
]
},
{
"type": "list-item",
"children": [{ "text": "Click on the trash button." }]
}
]
}
]
}
},
{
"w": 5,
"h": 2,
"x": 3,
"y": 8,
"i": "d90c4f52-e515-4017-8927-19c1e9c02640",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{ "type": "heading-one", "children": [{ "text": "Block Examples" }] }
]
}
},
{
"w": 5,
"h": 2,
"x": 3,
"y": 15,
"i": "65e61c01-c999-411c-8c4d-4c7242d1a274",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 4,
"metaData": { "content": "x_{1,2}=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}" }
},
{
"w": 5,
"h": 3,
"x": 3,
"y": 12,
"i": "630fc019-caff-43f3-a629-d91ffa34e635",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{ "type": "heading-three", "children": [{ "text": "Math block" }] },
{
"type": "paragraph",
"children": [
{
"text": "In addition to writing in LaTeX, we've added dozens of keyboard shortcuts to help you write faster in math blocks. For example, try writing \"intfx\" in a math block. Keyboard shortcuts help menu coming soon!"
}
]
}
]
}
},
{
"w": 5,
"h": 3,
"x": 3,
"y": 17,
"i": "997ff1a3-8919-4302-8d6a-47e3d8fb397d",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{ "type": "heading-three", "children": [{ "text": "Graph Block" }] },
{
"type": "paragraph",
"children": [
{
"text": "Currently, the only functions supported in the graph block are trigonometric and polynomial functions. More functions to be supported soon!"
}
]
}
]
}
},
{
"w": 5,
"h": 5,
"x": 3,
"y": 20,
"i": "4455135f-af3c-454d-bb87-d393b7814b1f",
"minW": 2,
"maxW": 8,
"minH": 2,
"maxH": 100,
"moved": false,
"static": false,
"type": 1,
"metaData": { "content": ["\\sin(x)\\cdot\\tan(x)"] }
},
{
"w": 5,
"h": 4,
"x": 3,
"y": 27,
"i": "2c7648cb-bad0-4d17-8101-b6044f2f12d3",
"minW": 4,
"maxW": 8,
"minH": 4,
"maxH": 100,
"moved": false,
"static": false,
"type": 6,
"metaData": {
"content": {
"shapes": [],
"bindings": [],
"assets": []
}
}
},
{
"w": 5,
"h": 2,
"x": 3,
"y": 25,
"i": "bbd2df59-7777-4353-8ee2-c6e1942fba57",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-three",
"children": [{ "text": "Drawing Block" }]
},
{
"type": "paragraph",
"children": [
{ "text": "Based on tldraw. Draw to your heart content!" }
]
}
]
}
},
{
"w": 5,
"h": 2,
"x": 3,
"y": 10,
"i": "64fbccd1-e25d-4a01-8749-aa4a23507519",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{ "type": "heading-three", "children": [{ "text": "Text Block" }] },
{
"type": "paragraph",
"children": [
{
"text": "Written in markdown (currently limited to headers and unordered lists)."
}
]
}
]
}
},
{
"w": 3,
"h": 4,
"x": 0,
"y": 22,
"i": "c0e9fa2b-6b44-44bc-a7b4-564ae5dbc6b5",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-two",
"children": [{ "text": "How do I create a file/folder?" }]
},
{
"type": "bulleted-list",
"children": [
{
"type": "list-item",
"children": [
{
"text": "Click on the notebooks button in the left sidebar."
}
]
},
{
"type": "list-item",
"children": [
{ "text": "Click on the create file/folder button." }
]
}
]
}
]
}
},
{
"w": 3,
"h": 4,
"x": 0,
"y": 26,
"i": "6900c23a-d4b5-42c5-92a5-01c5b6f32e89",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [
{
"type": "heading-two",
"children": [{ "text": "How do I change themes?" }]
},
{
"type": "bulleted-list",
"children": [
{
"type": "list-item",
"children": [
{
"text": "Click on the command button in the left sidebar (or press Ctrl+Shift+P)."
}
]
},
{
"type": "list-item",
"children": [{ "text": "Click on Preferences -> Theme." }]
}
]
}
]
}
},
{
"w": 3,
"h": 2,
"x": 0,
"y": 8,
"i": "d76c816e-9e3b-4f29-83b8-4f5c2104ef81",
"minW": 1,
"maxW": 8,
"minH": 1,
"maxH": 100,
"moved": false,
"static": false,
"type": 3,
"metaData": {
"content": [{ "type": "heading-one", "children": [{ "text": "FAQ" }] }]
}
}
],
"tags": [],
"mathMemory": {}
}
export default onboardingContent;
================================================
FILE: src/main/app.ts
================================================
import { app, BrowserWindow } from 'electron';
import { createAppWindow } from './appWindow';
/** Handle creating/removing shortcuts on Windows when installing/uninstalling. */
if (require('electron-squirrel-startup')) {
app.quit();
}
/**
* This method will be called when Electron has finished
* initialization and is ready to create browser windows.
* Some APIs can only be used after this event occurs.
*/
app.on('ready', createAppWindow);
/**
* Emitted when the application is activated. Various actions can
* trigger this event, such as launching the application for the first time,
* attempting to re-launch the application when it's already running,
* or clicking on the application's dock or taskbar icon.
*/
app.on('activate', () => {
/**
* On OS X it's common to re-create a window in the app when the
* dock icon is clicked and there are no other windows open.
*/
if (BrowserWindow.getAllWindows().length === 0) {
createAppWindow();
}
});
/**
* Emitted when all windows have been closed.
*/
app.on('window-all-closed', () => {
/**
* On OS X it is common for applications and their menu bar
* to stay active until the user quits explicitly with Cmd + Q
*/
if (process.platform !== 'darwin') {
app.quit();
}
});
/**
* In this file you can include the rest of your app's specific main process code.
* You can also put them in separate files and import them here.
*/
================================================
FILE: src/main/appWindow.ts
================================================
import { app, BrowserWindow, ipcMain, shell } from 'electron';
import path from 'path';
import { registerTitlebarIpc } from '@misc/window/titlebarIPC';
import * as fs from 'fs';
const { resolve } = require('path');
const os = require('os');
import onboardingContent from './Onboarding';
// Electron Forge automatically creates these entry points
declare const APP_WINDOW_WEBPACK_ENTRY: string;
declare const APP_WINDOW_PRELOAD_WEBPACK_ENTRY: string;
let appWindow: BrowserWindow;
/**
* Create Application Window
* @returns {BrowserWindow} Application Window Instance
*/
export function createAppWindow(): BrowserWindow {
// Create new window instance
appWindow = new BrowserWindow({
width: 800,
height: 600,
minWidth: 700,
minHeight: 400,
backgroundColor: '#202020',
show: false,
autoHideMenuBar: true,
frame: false,
titleBarStyle: 'hidden',
icon: resolve('assets/images/appIcon.ico'),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
nodeIntegrationInWorker: false,
nodeIntegrationInSubFrames: false,
preload: APP_WINDOW_PRELOAD_WEBPACK_ENTRY,
sandbox: false,
},
});
// Load the index.html of the app window.
appWindow.loadURL(APP_WINDOW_WEBPACK_ENTRY);
// Show window when its ready to
appWindow.on('ready-to-show', () => appWindow.show());
// Register Inter Process Communication for main process
registerMainIPC();
// Close all windows when main window is closed
appWindow.on('close', () => {
appWindow = null;
app.quit();
});
return appWindow;
}
ipcMain.on('getOS', () => {
let OS = '';
switch (os.platform()) {
case "darwin":
OS = "mac";
break;
case "win32":
OS = "windows"
break;
case "linux":
OS = "linux"
break;
default:
break;
}
appWindow.webContents.send('gotOS', OS);
});
ipcMain.on('saveX', (event, data, filePath) => {
const filesPath = path.join(app.getPath('documents'), 'Mathberet', 'files');
if (fs.existsSync(filesPath)) {
fs.writeFileSync(path.join(filePath), data, 'utf-8');
} else {
fs.mkdirSync(filesPath, { recursive: true });
fs.writeFileSync(path.join(filePath), data, 'utf-8');
}
});
ipcMain.on('loadX', (event, filePath) => {
if (fs.existsSync(filePath)) {
fs.readFile(filePath, 'utf-8', (error, data) => {
error
? console.error('Error Reading file: ', error)
: appWindow.webContents.send('gotLoadedDataX', data);
});
} else {
console.error('File not found!');
}
});
ipcMain.on('openFiles', () => {
shell
.openPath(path.join(app.getPath('documents'), 'Mathberet', 'files'))
.catch((error) => {
console.error(error);
});
});
ipcMain.on('move', (event, oldDir, newDir) => {
fs.renameSync(oldDir, newDir);
});
ipcMain.on('delete', (event, path, isFolder) => {
isFolder ? fs.rmSync(path, { recursive: true, force: true }) : fs.rmSync(path);
});
ipcMain.on('load', (event, file) => {
fs.readFile(file, 'utf-8', (error, data) => {
appWindow.webContents.send('fromMain', data);
});
});
ipcMain.on('newFile', (event, filePath) => {
fs.writeFileSync(filePath, '{}');
});
ipcMain.on('newFolder', (event, folderPath) => {
fs.mkdirSync(folderPath);
});
let firstTime = true;
function buildTree(dir: string, root: any) {
const stats = fs.statSync(dir);
let name = path.basename(dir).split('.')[0];
let key = dir;
if (firstTime) {
name = 'root';
key = 'root';
firstTime = false;
}
if (!stats.isDirectory()) {
root[key] = {
index: key,
data: name,
children: [],
path: dir,
isFolder: false,
};
return key;
}
const children = fs
.readdirSync(dir)
.map((child) => buildTree(path.join(dir, child), root));
root[key] = {
index: key,
isFolder: true,
data: name,
children,
path: dir,
};
return key;
}
ipcMain.on('getNotebooks', () => {
const filesPath = path.join(app.getPath('documents'), 'Mathberet', 'files');
if (!fs.existsSync(filesPath)) {
fs.mkdirSync(filesPath, {recursive: true});
fs.writeFileSync(path.join(filesPath, "Welcome to Mathberet!.json"), JSON.stringify(onboardingContent))
}
const root = {};
buildTree(filesPath, root);
firstTime = true;
appWindow.webContents.send('gotNotebooks', { filesPath, root });
});
ipcMain.on('getPicture', (event, id) => {
const allPics = fs.readdirSync(path.join(__dirname, '..', 'attachments'), {
withFileTypes: true,
});
let foundPath, b64;
for (const picture of allPics) {
if (picture.name.split('.')[0] == id.toString()) {
foundPath = path.join(__dirname, '..', 'attachments', picture.name);
b64 = fs.readFileSync(foundPath, 'base64');
break;
}
}
appWindow.webContents.send('gotPicture', `data:image/png;base64,${b64}`);
return;
});
ipcMain.on('getArchive', () => {
const filesPath = path.join(__dirname, '..', 'files');
const groupsToFilter: [] = [];
function getAllGroups() {
const allGroups = [];
const allFiles = fs.readdirSync(filesPath, { withFileTypes: true });
for (const file of allFiles) {
if (file.isDirectory()) {
const subFiles = fs.readdirSync(path.join(filesPath, file.name), {
withFileTypes: true,
});
for (const subfile of subFiles) {
if (subfile.name.split('.')[1] == 'json') {
const readFile = fs.readFileSync(
path.join(filesPath, file.name, subfile.name),
'utf-8',
);
for (const block of JSON.parse(readFile)) {
if (block.type == 'Group') {
allGroups.push(block);
}
}
}
}
} else {
if (file.name.split('.')[1] == 'json') {
const readFile = fs.readFileSync(
path.join(filesPath, file.name),
'utf-8',
);
for (const block of JSON.parse(readFile)) {
if (block.type == 'Group') {
allGroups.push(block);
}
}
}
}
}
return allGroups;
}
const allGroups = getAllGroups();
function removeDups(arr: any[]) {
const uniqueIds: any[] = [];
const unique = arr.filter((element) => {
const isDuplicate = uniqueIds.includes(element);
if (!isDuplicate) {
uniqueIds.push(element);
return true;
}
return false;
});
return unique.map(
(groupTitle) => (groupTitle = { groupName: groupTitle, subGroups: [] }),
);
}
const finalArr = [];
for (const group of removeDups(groupsToFilter)) {
if (group.groupName != 'קבוצה') {
for (const subGroup of allGroups) {
if (subGroup.groupTitle == group.groupName) {
group.subGroups.push(subGroup);
}
}
finalArr.push(group);
}
}
appWindow.webContents.send('gotArchive', finalArr);
});
ipcMain.on('startSearch', (event, args) => {
const filesPath = path.join(__dirname, '..', 'files');
function getAllBlocks() {
const allGroups = [];
const allFiles = fs.readdirSync(filesPath, { withFileTypes: true });
for (const file of allFiles) {
if (file.isDirectory()) {
const subFiles = fs.readdirSync(path.join(filesPath, file.name), {
withFileTypes: true,
});
for (const subfile of subFiles) {
const readFile = fs.readFileSync(
path.join(filesPath, file.name, subfile.name),
'utf-8',
);
allGroups.push({
filePath: path.join(filesPath, file.name, subfile.name),
fileName: subfile.name.replace('.json', ''),
blocks: JSON.parse(readFile),
});
}
} else {
const readFile = fs.readFileSync(
path.join(filesPath, file.name),
'utf-8',
);
allGroups.push({
filePath: path.join(filesPath, file.name),
fileName: file.name.replace('.json', ''),
blocks: JSON.parse(readFile),
});
}
}
return allGroups;
}
const allGroups = getAllBlocks();
appWindow.webContents.send('gotAllBlocks', allGroups);
});
/**
* Register Inter Process Communication
*/
function registerMainIPC() {
/**
* Here you can assign IPC related codes for the application window
* to Communicate asynchronously from the main process to renderer processes.
*/
registerTitlebarIpc(appWindow);
}
================================================
FILE: src/renderer/app.html
================================================
<!DOCTYPE html>
<html lang="he">
<head>
<meta charset="UTF-8" />
<title>מתברת</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
================================================
FILE: src/renderer/appPreload.tsx
================================================
import '@misc/window/windowPreload';
// Say something
console.log('[ERWT] : Preload execution started');
// Get versions
window.addEventListener('DOMContentLoaded', () => {
const { env } = process;
const versions: Record<string, unknown> = {};
// ERWT Package version
versions['erwt'] = env['npm_package_version'];
versions['license'] = env['npm_package_license'];
// Process versions
for (const type of ['chrome', 'node', 'electron']) {
versions[type] = process.versions[type].replace('+', '');
}
// NPM deps versions
for (const type of ['react']) {
const v = env['npm_package_dependencies_' + type];
if (v) versions[type] = v.replace('^', '');
}
// NPM @dev deps versions
for (const type of ['webpack', 'typescript']) {
const v = env['npm_package_devDependencies_' + type];
if (v) versions[type] = v.replace('^', '');
}
// Set versions to app data
// app.setAttribute('data-versions', JSON.stringify(versions));
});
================================================
FILE: src/renderer/appRenderer.tsx
================================================
import React from 'react';
import { createRoot } from 'react-dom/client';
import WindowFrame from '@misc/window/components/WindowFrame';
import Application from '@components/Application';
// Say something
console.log('[ERWT] : Renderer execution started');
// Application to Render
const app = (
<WindowFrame title='מתברת' platform='windows'>
<Application />
<div id="portal"></div>
</WindowFrame>
);
// Render application in DOM
createRoot(document.getElementById('app')).render(app);
================================================
FILE: src/renderer/common/types.ts
================================================
import { TDShape, TDBinding, TDAsset } from '@tldraw/tldraw';
// eslint-disable-next-line import/named
import { Descendant } from 'slate';
export enum WidgetType {
Divider,
Graph,
Group,
Text,
Math,
Picture,
Draw,
}
export type canvasProps = {
shapes: TDShape[];
bindings?: TDBinding[];
assets?: TDAsset[];
};
export type ValueProps = {
blockStateFunction: (...args: unknown[]) => unknown;
content: string | string[] | Descendant[] | canvasProps;
};
export type BlockState = {
id: string,
metaData: {content: string | string[] | Descendant[] | canvasProps},
}
export type FileStructure = {
tags: string[];
blocks: Array<BlockElement>;
mathMemory: object;
};
export type BlockElement = {
type: WidgetType;
metaData?: ValueProps;
} & ReactGridLayout.Layout;
export type newWidgetRequest = {
widgetType: WidgetType;
};
export type PageGridState = {
items: BlockElement[];
breakpoint: string;
cols: number;
};
================================================
FILE: src/renderer/components/Application.scss
================================================
/**
* Licensed under the MIT License. See LICENSE file in the project root for license information.
* Copyright (c) 2022 Codesbiome, guasam
*
* @author : guasam
* @project : ERWT Boilerplate
* @package : Application Sass Stylesheet
*/
@import '../../../assets/icons/uicons.css';
@import './Theme.scss';
@import './Fonts.css';
::selection {
background: var(--selection-bgcolor);
color: var(--selection-color);
}
::-webkit-scrollbar {
width: var(--scroll-width);
&-track {
background: transparent;
}
&-thumb {
background: var(--scroll-thumb-bgcolor);
border-radius: 50px;
}
&-thumb:hover {
background: var(--scroll-thumb-hover-bgcolor);
}
}
html,
body,
#app {
transition: 0.3s;
height: 100%;
overflow: hidden;
direction: var(--app-direction);
}
body {
margin: 0;
margin-right: 0 !important;
font-size: var(--app-font-size);
font-family: var(--app-font-family);
color: var(--app-color);
background: var(--app-bgcolor);
line-height: 1.5;
}
h1 {
margin: 0;
}
#app {
display: flex;
flex-direction: column;
box-sizing: border-box;
-webkit-user-select: none;
user-select: none;
&.has-border {
border: var(--app-border-color);
}
}
button {
background: var(--button-bgcolor);
color: var(--button-color);
font-weight: normal;
text-shadow: 0px 1px var(--button-shadow-color);
font-family: var(--app-font-family);
border: none;
padding: 0.5rem 1rem;
font-size: 0.875rem;
cursor: pointer;
transition: 0.1s;
display: inline-flex;
justify-content: space-around;
align-items: center;
outline: none;
&.tool {
background-color: #1a2428;
}
&:hover {
background: var(--button-hover-bgcolor);
}
&:active {
background: var(--button-active-bgcolor);
}
}
.rotate {
animation: rotate 4.5s linear infinite;
}
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
.hidden {
display: none !important;
}
.center {
text-align: center;
}
#main-app {
display: flex;
flex-direction: column;
height: 100%;
gap: 5px;
overflow-x: hidden;
.workspace {
width: calc(100% - 20px);
align-self: center;
height: 100%;
display: flex;
flex-direction: row;
direction: var(--app-direction);
justify-content: center;
gap: 10px;
.math-sidebar.open {
width: 100%;
min-width: 230px;
max-width: 15vw;
}
.math-sidebar {
transition: 0.2s;
width: 45px;
min-width: 45px;
max-width: 45px;
height: 100%;
display: flex;
flex-direction: column;
gap: 20px;
}
}
}
================================================
FILE: src/renderer/components/Application.tsx
================================================
import React from 'react';
import '../../../node_modules/react-grid-layout/css/styles.css';
import '../../../node_modules/react-resizable/css/styles.css';
import './Application.scss';
import { CommandBar } from './CommandBar/CommandBar';
import FilesSidebar from './FilesSidebar/FilesSidebar';
import { GeneralContextProvider } from './GeneralContext';
import Header from './Header/Header';
import MathSidebar from './MathSidebar/MathSidebar';
import Page from './Page/Page';
const Application = () => {
return (
<GeneralContextProvider>
<div id='main-app'>
<Header />
<div className='workspace'>
<FilesSidebar />
<CommandBar />
<Page />
<MathSidebar />
</div>
</div>
</GeneralContextProvider>
);
};
export default Application;
================================================
FILE: src/renderer/components/CommandBar/CommandBar.scss
================================================
@import '../Theme.scss';
.command-bar {
&-search {
padding: 12px 16px;
font-size: 16px;
width: 100%;
font-family: 'Rubik2', 'NotoSansArabic';
box-sizing: border-box;
outline: none;
border: none;
background: transparent;
color: hsla(var(--app-text-color), 1);
}
&-result {
padding: 14px 10px;
border-radius: 8px;
font-size: 16px;
user-select: none;
background: transparent;
&.active {
background: hsla(var(--theme-hue), 50%, 50%, 0.1);
}
}
}
body:has(#main-app.rtl) {
.command-bar-search,
.command-bar-result {
direction: rtl !important;
}
}
================================================
FILE: src/renderer/components/CommandBar/CommandBar.tsx
================================================
import React from 'react';
import './CommandBar.scss';
import {
KBarPortal,
KBarPositioner,
KBarAnimator,
KBarResults,
KBarSearch,
useMatches,
useRegisterActions,
} from 'kbar';
import { useTranslation } from 'react-i18next';
import { useGeneralContext } from '@components/GeneralContext';
export function CommandBar() {
const { t } = useTranslation();
const { actions } = useGeneralContext();
function RenderResults() {
// updating the actions using `useRegisterActions` *before*
// getting the results from `useMatches` so the results
// are always up to date. the actions are also up to date
// cause they are now stateful
useRegisterActions(actions);
const { results } = useMatches();
return (
<KBarResults
items={results}
onRender={({ item, active }) =>
typeof item === 'string' ? (
<div>{item}</div>
) : (
<div className={`command-bar-result${active ? ' active' : ''}`}>
{item.name}
</div>
)
}
/>
);
}
const animatorStyle = {
maxWidth: '600px',
width: '100%',
zIndex: '10000',
padding: '10px 8px',
outline: '1px solid var(--page-border)',
backdropFilter: 'blur(7px)',
background: 'var(--command-bar-bg)',
color: 'hsla(var(--app-text-color), 1)',
borderRadius: '12px',
boxShadow: '0 0 10px 1px rgba(0, 0, 0, .25)',
overflow: 'hidden',
};
return (
<KBarPortal>
<KBarPositioner style={{ width: 'unset' }}>
<KBarAnimator style={animatorStyle}>
<KBarSearch
className='command-bar-search'
defaultPlaceholder={t('Prompt')}
/>
<RenderResults />
</KBarAnimator>
</KBarPositioner>
</KBarPortal>
);
}
================================================
FILE: src/renderer/components/FilesSidebar/FileSystem.scss
================================================
@import '~react-complex-tree/lib/style-modern.css';
@import '../Theme.scss';
#main-app.rtl .rct-tree-item-title-container {
margin-inline-end: 10px !important;
margin-inline-start: unset !important;
}
.file-system {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
min-width: 190px;
max-width: 230px;
.file-system-header {
display: flex;
flex-direction: row;
direction: var(--app-direction);
height: max-content;
padding-bottom: 10px;
padding-top: 3px;
align-items: center;
.file-system-header-title {
cursor: alias;
color: hsla(var(--app-text-color), 0.6);
white-space: nowrap;
font-size: 21px;
font-weight: 700;
width: 100%;
&:hover::after {
content: attr(data-tooltip);
color: hsla(var(--app-text-color), 1);
font-size: 14px;
font-weight: 400;
min-width: max-content;
position: fixed;
margin-top: 40px;
margin-inline-start: -130px;
z-index: 1000;
padding: 6px 10px 6px 10px;
background-color: var(--button-bgcolor);
text-shadow: none;
border: 1px solid var(--page-border);
border-radius: 6px;
opacity: 0%;
animation: tooltip 0.1s ease-in-out 0.2s forwards;
}
}
.file-system-header-buttons {
border-radius: 10px;
display: flex;
flex-direction: row;
direction: var(--app-direction);
width: max-content;
gap: 3px;
button {
background: none;
padding: 5px !important;
color: var(--tool-color);
transition: 0.1s;
&:hover {
background: none;
color: var(--button-color);
&::after {
content: attr(data-tooltip);
color: hsla(var(--app-text-color), 1);
min-width: max-content;
position: fixed;
margin-top: 80px;
z-index: 1000;
padding: 6px 10px 6px 10px;
background-color: var(--button-bgcolor);
text-shadow: none;
border: 1px solid var(--page-border);
border-radius: 6px;
opacity: 0%;
animation: tooltip 0.1s ease-in-out 0.2s forwards;
}
}
&:active {
transform: scale(0.92);
}
i {
font-size: 18px;
height: 18px;
}
}
}
}
.files-tree-container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
min-width: inherit;
max-width: inherit;
.rct-tree-root {
height: 90%;
[role='tree'] {
height: inherit;
& > .rct-tree-items-container {
height: inherit;
[role='treeitem'] {
input {
text-shadow: none;
font-family: 'Rubik2', 'NotoSansArabic';
font-size: 16px;
height: 40px;
}
.rct-tree-item-title-container {
margin-inline-start: 10px;
margin-inline-end: unset;
padding-inline-end: 10px !important;
padding-right: 0px !important;
padding-left: 0px !important;
.rct-tree-item-button {
overflow: hidden;
min-width: inherit;
text-overflow: ellipsis;
white-space: nowrap;
height: 100%;
direction: var(--app-direction);
background-color: transparent;
color: hsla(var(--app-text-color), 1);
border-radius: 10px;
text-shadow: none;
font-family: 'Rubik2', 'NotoSansArabic';
font-size: 16px;
height: 40px;
flex-direction: row;
justify-content: flex-start;
padding-inline-start: 10px;
// direction: ltr;
// padding: 0 var(--rct-item-padding) 0
// calc(
// var(--rct-item-padding) + var(--rct-arrow-container-size) +
// var(--rct-arrow-padding)
// );
// margin-right: calc(-1 * var(--rct-arrow-size));
// margin-left: calc(-1 * var(--rct-arrow-size));
// padding-right: 12px;
cursor: var(--rct-cursor);
transition: color 100ms ease-out,
background-color 100ms ease-out, font-weight 100ms ease-in;
&:hover {
background-color: var(--file-hover-bgcolor);
color: hsla(var(--app-text-color), 1);
}
&:active {
background-color: var(--file-active-bgcolor);
color: hsla(var(--app-text-color), 1);
}
&::before {
// Override
position: unset;
gitextract_iwhcz0fy/ ├── .eslintrc ├── .gitattributes ├── .github/ │ └── ISSUE_TEMPLATE/ │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .hintrc ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets/ │ ├── icons/ │ │ └── uicons.css │ └── webfonts/ │ └── OFL.txt ├── misc/ │ └── window/ │ ├── LICENSE │ ├── components/ │ │ ├── ControlButton.tsx │ │ ├── Titlebar.less │ │ ├── Titlebar.tsx │ │ ├── WindowControls.tsx │ │ └── WindowFrame.tsx │ ├── titlebarContext.ts │ ├── titlebarContextApi.ts │ ├── titlebarIPC.ts │ ├── titlebarMenus.ts │ └── windowPreload.ts ├── package.json ├── src/ │ ├── common/ │ │ ├── helpers.ts │ │ ├── i18n.ts │ │ ├── keybindings.ts │ │ ├── locals/ │ │ │ ├── ar.ts │ │ │ ├── en.ts │ │ │ ├── es.ts │ │ │ ├── fr.ts │ │ │ ├── he.ts │ │ │ ├── hi.ts │ │ │ ├── ru.ts │ │ │ └── zh.ts │ │ └── shortcuts.ts │ ├── main/ │ │ ├── Onboarding.js │ │ ├── app.ts │ │ └── appWindow.ts │ ├── renderer/ │ │ ├── app.html │ │ ├── appPreload.tsx │ │ ├── appRenderer.tsx │ │ ├── common/ │ │ │ └── types.ts │ │ ├── components/ │ │ │ ├── Application.scss │ │ │ ├── Application.tsx │ │ │ ├── CommandBar/ │ │ │ │ ├── CommandBar.scss │ │ │ │ └── CommandBar.tsx │ │ │ ├── FilesSidebar/ │ │ │ │ ├── FileSystem.scss │ │ │ │ ├── FileSystem.tsx │ │ │ │ ├── FileSystemHelpers.ts │ │ │ │ ├── FilesSidebar.scss │ │ │ │ ├── FilesSidebar.tsx │ │ │ │ ├── SidebarButton.tsx │ │ │ │ └── types.ts │ │ │ ├── Fonts.css │ │ │ ├── GeneralContext.tsx │ │ │ ├── Header/ │ │ │ │ ├── AddTag.tsx │ │ │ │ ├── FilePath.tsx │ │ │ │ ├── Header.scss │ │ │ │ ├── Header.tsx │ │ │ │ └── Tag.tsx │ │ │ ├── Icons.tsx │ │ │ ├── MathSidebar/ │ │ │ │ ├── ActionsGroup.tsx │ │ │ │ ├── MathSidebar.scss │ │ │ │ └── MathSidebar.tsx │ │ │ ├── Page/ │ │ │ │ ├── Grid/ │ │ │ │ │ ├── Blocks/ │ │ │ │ │ │ ├── Blocks.scss │ │ │ │ │ │ ├── DrawBlock.tsx │ │ │ │ │ │ ├── GraphBlock.tsx │ │ │ │ │ │ ├── MathBlock.tsx │ │ │ │ │ │ └── TextBlock.tsx │ │ │ │ │ ├── Grid.scss │ │ │ │ │ ├── Grid.tsx │ │ │ │ │ └── GridElement.tsx │ │ │ │ ├── Page.scss │ │ │ │ ├── Page.tsx │ │ │ │ ├── PagePlaceholder.tsx │ │ │ │ └── ToolsPanel/ │ │ │ │ ├── Tool.tsx │ │ │ │ ├── ToolsPanel.scss │ │ │ │ └── ToolsPanel.tsx │ │ │ ├── Theme.scss │ │ │ └── common/ │ │ │ ├── Modals/ │ │ │ │ ├── ConfirmModal.scss │ │ │ │ ├── ConfirmModal.tsx │ │ │ │ ├── ErrorModal.scss │ │ │ │ └── ErrorModal.tsx │ │ │ ├── Notification.scss │ │ │ ├── Notification.tsx │ │ │ └── Shortcut.tsx │ │ └── hooks/ │ │ ├── useAddBlock.tsx │ │ ├── useDialog.tsx │ │ ├── useFileSaveLoad.tsx │ │ └── useSettings.tsx │ └── typings/ │ └── index.d.ts ├── tools/ │ ├── forge/ │ │ └── forge.config.js │ └── webpack/ │ ├── webpack.aliases.js │ ├── webpack.helpers.js │ ├── webpack.main.js │ ├── webpack.plugins.js │ ├── webpack.renderer.js │ └── webpack.rules.js └── tsconfig.json
SYMBOL INDEX (96 symbols across 44 files)
FILE: misc/window/components/ControlButton.tsx
type IControlButtonProps (line 4) | interface IControlButtonProps {
FILE: misc/window/components/Titlebar.tsx
type Props (line 21) | type Props = {
function handleClickOutside (line 53) | function handleClickOutside(event: MouseEvent) {
function showMenu (line 76) | function showMenu(index: number, e: React.MouseEvent<HTMLDivElement>) {
function onMenuHover (line 91) | function onMenuHover(index: number) {
function closeActiveMenu (line 104) | function closeActiveMenu() {
function handleAction (line 112) | function handleAction(action?: string, value?: string | number) {
FILE: misc/window/components/WindowControls.tsx
type Props (line 19) | type Props = {
FILE: misc/window/components/WindowFrame.tsx
type Props (line 17) | type Props = {
type Context (line 24) | type Context = {
FILE: misc/window/titlebarContext.ts
method exit (line 16) | exit() {
method undo (line 19) | undo() {
method redo (line 22) | redo() {
method cut (line 25) | cut() {
method copy (line 28) | copy() {
method paste (line 31) | paste() {
method delete (line 34) | delete() {
method select_all (line 37) | select_all() {
method reload (line 40) | reload() {
method force_reload (line 43) | force_reload() {
method toggle_devtools (line 46) | toggle_devtools() {
method actual_size (line 49) | actual_size() {
method zoom_in (line 52) | zoom_in() {
method zoom_out (line 55) | zoom_out() {
method toggle_fullscreen (line 58) | toggle_fullscreen() {
method minimize (line 61) | minimize() {
method toggle_maximize (line 64) | toggle_maximize() {
method open_url (line 67) | open_url(url: string) {
type TitlebarContextApi (line 72) | type TitlebarContextApi = typeof titlebarContext;
FILE: misc/window/titlebarMenus.ts
type TitlebarMenuItem (line 13) | type TitlebarMenuItem = {
type TitlebarMenu (line 21) | type TitlebarMenu = {
FILE: src/common/helpers.ts
function inDev (line 4) | function inDev(): boolean {
FILE: src/common/keybindings.ts
constant DEFAULT_KEYBINDINGS (line 3) | const DEFAULT_KEYBINDINGS: Array<Keybinding> = [
constant CUSTOM_KEYBINDINGS (line 427) | const CUSTOM_KEYBINDINGS: Array<Keybinding> = [
constant ML_KEYBINDINGS (line 475) | const ML_KEYBINDINGS = [DEFAULT_KEYBINDINGS, CUSTOM_KEYBINDINGS].flat()
FILE: src/common/locals/ar.ts
constant AR_TRANSLATION (line 1) | const AR_TRANSLATION = {
FILE: src/common/locals/en.ts
constant EN_TRANSLATION (line 1) | const EN_TRANSLATION = {
FILE: src/common/locals/es.ts
constant ES_TRANSLATION (line 1) | const ES_TRANSLATION = {
FILE: src/common/locals/fr.ts
constant FR_TRANSLATION (line 1) | const FR_TRANSLATION = {
FILE: src/common/locals/he.ts
constant HE_TRANSLATION (line 1) | const HE_TRANSLATION = {
FILE: src/common/locals/hi.ts
constant HI_TRANSLATION (line 1) | const HI_TRANSLATION = {
FILE: src/common/locals/ru.ts
constant RU_TRANSLATION (line 1) | const RU_TRANSLATION = {
FILE: src/common/locals/zh.ts
constant ZH_TRANSLATION (line 2) | const ZH_TRANSLATION = {
FILE: src/common/shortcuts.ts
constant ML_SHORTCUTS (line 3) | const ML_SHORTCUTS: Record<string, InlineShortcutDefinition> = {
FILE: src/main/appWindow.ts
function createAppWindow (line 19) | function createAppWindow(): BrowserWindow {
function buildTree (line 136) | function buildTree(dir: string, root: any) {
function getAllGroups (line 209) | function getAllGroups() {
function removeDups (line 249) | function removeDups(arr: any[]) {
function getAllBlocks (line 281) | function getAllBlocks() {
function registerMainIPC (line 321) | function registerMainIPC() {
FILE: src/renderer/common/types.ts
type WidgetType (line 5) | enum WidgetType {
type canvasProps (line 15) | type canvasProps = {
type ValueProps (line 21) | type ValueProps = {
type BlockState (line 26) | type BlockState = {
type FileStructure (line 31) | type FileStructure = {
type BlockElement (line 37) | type BlockElement = {
type newWidgetRequest (line 42) | type newWidgetRequest = {
type PageGridState (line 46) | type PageGridState = {
FILE: src/renderer/components/CommandBar/CommandBar.tsx
function CommandBar (line 17) | function CommandBar() {
FILE: src/renderer/components/FilesSidebar/FileSystem.tsx
type receivedProps (line 30) | type receivedProps = { filesPath: string; root: SetStateAction<TreeItems...
type Window (line 32) | interface Window {
function FileSystem (line 36) | function FileSystem() {
FILE: src/renderer/components/FilesSidebar/FileSystemHelpers.ts
function itemExistsInParent (line 183) | function itemExistsInParent(
FILE: src/renderer/components/FilesSidebar/SidebarButton.tsx
type SidebarButtonProps (line 5) | type SidebarButtonProps = {
FILE: src/renderer/components/FilesSidebar/types.ts
type MathTreeItem (line 4) | type MathTreeItem = {
type TreeItemsObj (line 8) | type TreeItemsObj = {
FILE: src/renderer/components/GeneralContext.tsx
function GeneralContextProvider (line 14) | function GeneralContextProvider({ children }: PropsWithChildren) {
function useGeneralContext (line 324) | function useGeneralContext() {
FILE: src/renderer/components/Header/FilePath.tsx
type FilePathProps (line 4) | type FilePathProps = { filePath: string };
FILE: src/renderer/components/Header/Tag.tsx
type TagProps (line 4) | type TagProps = {
FILE: src/renderer/components/MathSidebar/ActionsGroup.tsx
type ActionsGroupProps (line 5) | type ActionsGroupProps = { title: string; groupType: string };
FILE: src/renderer/components/Page/Grid/Blocks/DrawBlock.tsx
function DrawBlockContent (line 5) | function DrawBlockContent({ content, blockStateFunction }: ValueProps) {
FILE: src/renderer/components/Page/Grid/Blocks/GraphBlock.tsx
function latex2function (line 10) | function latex2function(latex: string, i: number) {
function GraphBlockContent (line 21) | function GraphBlockContent({ content, blockStateFunction }: ValueProps) {
FILE: src/renderer/components/Page/Grid/Blocks/MathBlock.tsx
function MathBlockContent (line 8) | function MathBlockContent({ content, blockStateFunction }: ValueProps) {
FILE: src/renderer/components/Page/Grid/Blocks/TextBlock.tsx
type BulletedListElement (line 23) | type BulletedListElement = {
type CustomElement (line 29) | interface CustomElement extends BaseElement {
constant SHORTCUTS (line 34) | const SHORTCUTS = {
function isDescendant (line 49) | function isDescendant(content: string | string[] | Descendant[] | canvas...
FILE: src/renderer/components/Page/Grid/GridElement.tsx
type GridElementProps (line 9) | type GridElementProps = {
function Switcher (line 24) | function Switcher(
FILE: src/renderer/components/Page/ToolsPanel/Tool.tsx
type ToolProps (line 3) | type ToolProps = {
FILE: src/renderer/components/common/Modals/ConfirmModal.tsx
type ConfirmModalProps (line 6) | interface ConfirmModalProps {
function ConfirmModal (line 13) | function ConfirmModal({
FILE: src/renderer/components/common/Modals/ErrorModal.tsx
type ErrorModalProps (line 6) | interface ErrorModalProps extends PropsWithChildren {
function ErrorModal (line 11) | function ErrorModal({
FILE: src/renderer/components/common/Notification.tsx
type NotificationProps (line 5) | type NotificationProps = {
FILE: src/renderer/components/common/Shortcut.tsx
type ShortcutProps (line 3) | type ShortcutProps = {
FILE: src/renderer/hooks/useAddBlock.tsx
function useAddBlock (line 9) | function useAddBlock(setStateFunction: (...args: unknown[]) => unknown) {
FILE: src/renderer/hooks/useDialog.tsx
function useDialog (line 5) | function useDialog(
FILE: src/renderer/hooks/useFileSaveLoad.tsx
function useFileSaveLoad (line 11) | function useFileSaveLoad(
FILE: src/renderer/hooks/useSettings.tsx
function useSettings (line 3) | function useSettings() {
FILE: src/typings/index.d.ts
type CustomElement (line 9) | type CustomElement<T> = Partial<T & DOMAttributes<T>>;
type IntrinsicElements (line 13) | interface IntrinsicElements {
FILE: tools/webpack/webpack.helpers.js
function inDev (line 5) | function inDev() {
function createWebpackAliases (line 9) | function createWebpackAliases (aliases) {
Condensed preview — 101 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (329K chars).
[
{
"path": ".eslintrc",
"chars": 995,
"preview": "{\n \"env\": {\n \"browser\": true,\n \"es6\": true,\n \"node\": true\n },\n \"extends\": [\n \"eslint:recommended\",\n \"p"
},
{
"path": ".gitattributes",
"chars": 66,
"preview": "*.scss linguist-detectable=false\n*.sass linguist-detectable=false\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 630,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 604,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is"
},
{
"path": ".gitignore",
"chars": 1156,
"preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n# Diagnostic reports (https://nodejs."
},
{
"path": ".hintrc",
"chars": 512,
"preview": "{\n \"extends\": [\n \"development\"\n ],\n \"hints\": {\n \"axe/text-alternatives\": [\n \"default\",\n {\n \"im"
},
{
"path": ".prettierrc",
"chars": 78,
"preview": "{\n \"singleQuote\": true,\n \"trailingComma\": \"all\",\n \"jsxSingleQuote\": true\n}\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5224,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 432,
"preview": "# Contributing to Mathberet\n\nThank you for investing your time in contributing to our project!\n\nRead our [Code of Conduc"
},
{
"path": "LICENSE",
"chars": 1066,
"preview": "MIT License\n\nCopyright (c) 2023 Mathberet\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
},
{
"path": "README.md",
"chars": 6447,
"preview": "\n<div align=\"center\">\n <picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://github.com/yonatanmgr"
},
{
"path": "assets/icons/uicons.css",
"chars": 63386,
"preview": "@font-face{font-family:uicons-regular-rounded;src:url(../webfonts/uicons-regular-rounded-BG3GDTFR.eot) format(\"embedded-"
},
{
"path": "assets/webfonts/OFL.txt",
"chars": 4382,
"preview": "Copyright 2019 The Baloo 2 Project Authors (https://github.com/EkType/Baloo2)\n\nThis Font Software is licensed under the"
},
{
"path": "misc/window/LICENSE",
"chars": 839,
"preview": "Copyright (c) 2021-2022 Guasam\n\nThis software is provided \"as-is\", without any express or implied warranty. In no event\n"
},
{
"path": "misc/window/components/ControlButton.tsx",
"chars": 727,
"preview": "import classNames from 'classnames';\nimport React from 'react';\n\ninterface IControlButtonProps {\n readonly name: string"
},
{
"path": "misc/window/components/Titlebar.less",
"chars": 3913,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/components/Titlebar.tsx",
"chars": 6181,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/components/WindowControls.tsx",
"chars": 1613,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/components/WindowFrame.tsx",
"chars": 1676,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/titlebarContext.ts",
"chars": 1635,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/titlebarContextApi.ts",
"chars": 504,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/titlebarIPC.ts",
"chars": 2287,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/titlebarMenus.ts",
"chars": 2813,
"preview": "/**\n * Copyright (c) 2021, Guasam\n *\n * This software is provided \"as-is\", without any express or implied warranty. In n"
},
{
"path": "misc/window/windowPreload.ts",
"chars": 2985,
"preview": "import { contextBridge, ipcRenderer } from 'electron';\nimport titlebarContext from './titlebarContext';\n\ncontextBridge.e"
},
{
"path": "package.json",
"chars": 3220,
"preview": "{\n \"name\": \"mathberet\",\n \"productName\": \"Mathberet\",\n \"version\": \"1.0.0\",\n \"description\": \"Digital Mathematics Noteb"
},
{
"path": "src/common/helpers.ts",
"chars": 145,
"preview": "/**\n * Checks if process NODE_ENV in 'development' mode\n */\nexport function inDev(): boolean {\n return process.env.NODE"
},
{
"path": "src/common/i18n.ts",
"chars": 946,
"preview": "import i18n from 'i18next';\nimport { initReactI18next } from 'react-i18next';\nimport { HE_TRANSLATION } from './locals/h"
},
{
"path": "src/common/keybindings.ts",
"chars": 15326,
"preview": "import { Keybinding } from \"mathlive\"\n\nconst DEFAULT_KEYBINDINGS: Array<Keybinding> = [\n { key: \"left\", command: \"mov"
},
{
"path": "src/common/locals/ar.ts",
"chars": 1637,
"preview": "export const AR_TRANSLATION = {\n 'My Notebooks': 'دفاتري',\n 'Command Bar': 'شريط الأوامر',\n 'Math Panel': 'لوحة الريا"
},
{
"path": "src/common/locals/en.ts",
"chars": 1697,
"preview": "export const EN_TRANSLATION = {\n 'My Notebooks': 'Notebooks',\n 'Command Bar': 'Command Bar',\n 'Math Panel': 'Math Pan"
},
{
"path": "src/common/locals/es.ts",
"chars": 1869,
"preview": "export const ES_TRANSLATION = {\n 'My Notebooks': 'Mis Cuadernos',\n 'Command Bar': 'Barra de Comandos',\n 'Math Panel':"
},
{
"path": "src/common/locals/fr.ts",
"chars": 2032,
"preview": "export const FR_TRANSLATION = {\n 'My Notebooks': 'Mes carnets',\n 'Command Bar': 'Barre de commande',\n 'Math Pan"
},
{
"path": "src/common/locals/he.ts",
"chars": 1665,
"preview": "export const HE_TRANSLATION = {\n 'My Notebooks': 'המחברות שלי',\n 'Command Bar': 'חיפוש ופקודות',\n 'Math Panel': 'זיכר"
},
{
"path": "src/common/locals/hi.ts",
"chars": 1739,
"preview": "export const HI_TRANSLATION = {\n 'My Notebooks': 'नोटबुक',\n 'Command Bar': 'कमांड बार',\n 'Math Panel': 'गणित पैनल',\n "
},
{
"path": "src/common/locals/ru.ts",
"chars": 1905,
"preview": "export const RU_TRANSLATION = {\n 'My Notebooks': 'Мои блокноты',\n 'Command Bar': 'Поиск и команды',\n 'Math Panel': 'М"
},
{
"path": "src/common/locals/zh.ts",
"chars": 1296,
"preview": "//Mandarin Chinese\nexport const ZH_TRANSLATION = {\n 'My Notebooks': '笔记本',\n 'Command Bar': '命令栏',\n 'Math Panel': '数学面"
},
{
"path": "src/common/shortcuts.ts",
"chars": 15018,
"preview": "import { InlineShortcutDefinition } from \"mathlive\";\n\nconst ML_SHORTCUTS: Record<string, InlineShortcutDefinition> = {\n "
},
{
"path": "src/main/Onboarding.js",
"chars": 11474,
"preview": "const onboardingContent = {\n \"blocks\": [\n {\n \"w\": 8,\n \"h\": 2,\n \"x\": 0,\n \"y\": 0,\n \"i\": \"de34"
},
{
"path": "src/main/app.ts",
"chars": 1433,
"preview": "import { app, BrowserWindow } from 'electron';\nimport { createAppWindow } from './appWindow';\n\n/** Handle creating/remov"
},
{
"path": "src/main/appWindow.ts",
"chars": 8501,
"preview": "import { app, BrowserWindow, ipcMain, shell } from 'electron';\nimport path from 'path';\nimport { registerTitlebarIpc } f"
},
{
"path": "src/renderer/app.html",
"chars": 158,
"preview": "<!DOCTYPE html>\n<html lang=\"he\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>מתברת</title>\n </head>\n <body>\n <"
},
{
"path": "src/renderer/appPreload.tsx",
"chars": 977,
"preview": "import '@misc/window/windowPreload';\n\n// Say something\nconsole.log('[ERWT] : Preload execution started');\n\n// Get versio"
},
{
"path": "src/renderer/appRenderer.tsx",
"chars": 501,
"preview": "import React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport WindowFrame from '@misc/window/componen"
},
{
"path": "src/renderer/common/types.ts",
"chars": 960,
"preview": "import { TDShape, TDBinding, TDAsset } from '@tldraw/tldraw';\n// eslint-disable-next-line import/named\nimport { Descenda"
},
{
"path": "src/renderer/components/Application.scss",
"chars": 2600,
"preview": "/**\n * Licensed under the MIT License. See LICENSE file in the project root for license information.\n * Copyright (c) 20"
},
{
"path": "src/renderer/components/Application.tsx",
"chars": 818,
"preview": "import React from 'react';\nimport '../../../node_modules/react-grid-layout/css/styles.css';\nimport '../../../node_module"
},
{
"path": "src/renderer/components/CommandBar/CommandBar.scss",
"chars": 633,
"preview": "@import '../Theme.scss';\n\n.command-bar {\n &-search {\n padding: 12px 16px;\n font-size: 16px;\n width: 100%;\n "
},
{
"path": "src/renderer/components/CommandBar/CommandBar.tsx",
"chars": 1817,
"preview": "import React from 'react';\nimport './CommandBar.scss';\n\nimport {\n KBarPortal,\n KBarPositioner,\n KBarAnimator,\n KBarR"
},
{
"path": "src/renderer/components/FilesSidebar/FileSystem.scss",
"chars": 7566,
"preview": "@import '~react-complex-tree/lib/style-modern.css';\n@import '../Theme.scss';\n\n#main-app.rtl .rct-tree-item-title-contain"
},
{
"path": "src/renderer/components/FilesSidebar/FileSystem.tsx",
"chars": 8511,
"preview": "/* eslint-disable import/named */\nimport ErrorModal from '@components/common/Modals/ErrorModal';\nimport { useGeneralCont"
},
{
"path": "src/renderer/components/FilesSidebar/FileSystemHelpers.ts",
"chars": 5539,
"preview": "/* eslint-disable import/named */\nimport {\n TreeItem,\n DraggingPositionItem,\n DraggingPositionBetweenItems,\n TreeIte"
},
{
"path": "src/renderer/components/FilesSidebar/FilesSidebar.scss",
"chars": 2498,
"preview": ".files-sidebar {\n transition: 0.2s;\n display: flex;\n flex-direction: row;\n width: 45px;\n min-width: 45px;\n max-wid"
},
{
"path": "src/renderer/components/FilesSidebar/FilesSidebar.tsx",
"chars": 1916,
"preview": "import React from 'react';\nimport './FilesSidebar.scss';\nimport SidebarButton from './SidebarButton';\nimport FileSystem "
},
{
"path": "src/renderer/components/FilesSidebar/SidebarButton.tsx",
"chars": 680,
"preview": "import React from 'react';\nimport '../Application.scss';\nimport './FilesSidebar.scss';\n\ntype SidebarButtonProps = {\n ti"
},
{
"path": "src/renderer/components/FilesSidebar/types.ts",
"chars": 212,
"preview": "// eslint-disable-next-line import/named\nimport { TreeItem } from 'react-complex-tree';\n\nexport type MathTreeItem = {\n "
},
{
"path": "src/renderer/components/Fonts.css",
"chars": 415,
"preview": "@import \"../../../node_modules/computer-modern/cmu-serif.css\";\n\n@font-face {\n font-family: 'Rubik2';\n src: url('.."
},
{
"path": "src/renderer/components/GeneralContext.tsx",
"chars": 7485,
"preview": "import React, {\n createContext,\n PropsWithChildren,\n useContext,\n useEffect,\n useState,\n} from 'react';\nimport { ne"
},
{
"path": "src/renderer/components/Header/AddTag.tsx",
"chars": 2314,
"preview": "import React, { useEffect, useState } from 'react';\nimport { TagProps } from './Tag';\nimport { useGeneralContext } from "
},
{
"path": "src/renderer/components/Header/FilePath.tsx",
"chars": 703,
"preview": "import React from 'react';\nimport './Header.scss';\n\ntype FilePathProps = { filePath: string };\n\nconst FilePath = ({ file"
},
{
"path": "src/renderer/components/Header/Header.scss",
"chars": 3928,
"preview": "@import '../Theme.scss';\n\n.header {\n width: calc(100% - 20px);\n max-width: 100%;\n align-self: center;\n padding-top: "
},
{
"path": "src/renderer/components/Header/Header.tsx",
"chars": 1851,
"preview": "import React, { useEffect, useState } from 'react';\nimport '../Application.scss';\nimport { icons } from '../Icons';\nimpo"
},
{
"path": "src/renderer/components/Header/Tag.tsx",
"chars": 997,
"preview": "import { useGeneralContext } from '@components/GeneralContext';\nimport React from 'react';\n\nexport type TagProps = {\n t"
},
{
"path": "src/renderer/components/Icons.tsx",
"chars": 148,
"preview": "const pngLogo = require('@assets/icons/pngLogo.png');\nconst logo = require('@assets/icons/logo.svg');\n\n\nexport const ico"
},
{
"path": "src/renderer/components/MathSidebar/ActionsGroup.tsx",
"chars": 466,
"preview": "import React from 'react';\nimport '../Application.scss';\nimport './MathSidebar.scss'\n\ntype ActionsGroupProps = { title: "
},
{
"path": "src/renderer/components/MathSidebar/MathSidebar.scss",
"chars": 520,
"preview": "@import '../Theme.scss';\n\n.actions-group {\n display: none;\n}\n\n.math-sidebar.open{\n min-width: max-content;\n\n .a"
},
{
"path": "src/renderer/components/MathSidebar/MathSidebar.tsx",
"chars": 704,
"preview": "import React, { useEffect, useState } from 'react';\nimport ActionsGroup from './ActionsGroup';\nimport { useGeneralContex"
},
{
"path": "src/renderer/components/Page/Grid/Blocks/Blocks.scss",
"chars": 4065,
"preview": "@import '../../../Theme.scss';\n@import '../../Page.scss';\n@import '../Grid.scss';\n@import \"/node_modules/mafs/core.css\";"
},
{
"path": "src/renderer/components/Page/Grid/Blocks/DrawBlock.tsx",
"chars": 957,
"preview": "import { ValueProps, canvasProps } from '@renderer/common/types';\nimport { Tldraw, TldrawApp } from '@tldraw/tldraw';\nim"
},
{
"path": "src/renderer/components/Page/Grid/Blocks/GraphBlock.tsx",
"chars": 2845,
"preview": "import { Mafs, Coordinates, Plot, Theme } from 'mafs';\nimport React, { useEffect, useRef, useState } from 'react';\n// es"
},
{
"path": "src/renderer/components/Page/Grid/Blocks/MathBlock.tsx",
"chars": 972,
"preview": "import React, { useEffect, useRef, useState } from 'react';\n// eslint-disable-next-line import/named\nimport MathView, { "
},
{
"path": "src/renderer/components/Page/Grid/Blocks/TextBlock.tsx",
"chars": 7462,
"preview": "import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport {\n createEditor,\n // eslint-disable-n"
},
{
"path": "src/renderer/components/Page/Grid/Grid.scss",
"chars": 2430,
"preview": "@import '../../Theme.scss';\n@import '../Page.scss';\n\n#main-app.rtl .block-remove-button {\n left: 1px !important;\n "
},
{
"path": "src/renderer/components/Page/Grid/Grid.tsx",
"chars": 3840,
"preview": "import React, { useEffect, useState } from 'react';\nimport { useGeneralContext } from '@components/GeneralContext';\n\nimp"
},
{
"path": "src/renderer/components/Page/Grid/GridElement.tsx",
"chars": 3705,
"preview": "import React, { LegacyRef, useEffect, useState } from 'react';\nimport TextBlockContent from './Blocks/TextBlock';\nimport"
},
{
"path": "src/renderer/components/Page/Page.scss",
"chars": 2674,
"preview": "@import '../Theme.scss';\n@import '~keyboard-css/dist/css/main.min.css';\n\n::-webkit-scrollbar {\n width: 0;\n}\n\n.page {\n"
},
{
"path": "src/renderer/components/Page/Page.tsx",
"chars": 1024,
"preview": "import React, { useEffect, useState } from 'react';\nimport '../Application.scss';\n\nimport './Page.scss';\n\nimport ToolsPa"
},
{
"path": "src/renderer/components/Page/PagePlaceholder.tsx",
"chars": 647,
"preview": "import React from 'react';\nimport Shortcut from '@components/common/Shortcut';\nimport './Page.scss';\nimport { useTransla"
},
{
"path": "src/renderer/components/Page/ToolsPanel/Tool.tsx",
"chars": 453,
"preview": "import React from 'react';\n\ntype ToolProps = {\n title: string;\n buttonType: string;\n icon?: string;\n onClick?: React"
},
{
"path": "src/renderer/components/Page/ToolsPanel/ToolsPanel.scss",
"chars": 2699,
"preview": "@import '../../Theme.scss';\n@import '../Page.scss';\n\n.tools-panel-container {\n position: fixed;\n height: 80px;\n "
},
{
"path": "src/renderer/components/Page/ToolsPanel/ToolsPanel.tsx",
"chars": 2551,
"preview": "import React from 'react';\nimport '../Page.scss';\nimport Tool from './Tool';\nimport { useGeneralContext } from '@compone"
},
{
"path": "src/renderer/components/Theme.scss",
"chars": 7871,
"preview": "#main-app.rtl {\n --app-direction: rtl;\n}\n\n:root {\n --app-direction: unset;\n\n // Logo \n --logo-filter: brightness(1);"
},
{
"path": "src/renderer/components/common/Modals/ConfirmModal.scss",
"chars": 2173,
"preview": "@import '../../Theme.scss';\n\nbody:has(#main-app.rtl){\n .modal-text{\n direction: rtl;\n }\n}\n\n#portal {\n display: fle"
},
{
"path": "src/renderer/components/common/Modals/ConfirmModal.tsx",
"chars": 874,
"preview": "import React from 'react';\nimport ReactDom from 'react-dom';\nimport './ConfirmModal.scss';\nimport { useTranslation } fro"
},
{
"path": "src/renderer/components/common/Modals/ErrorModal.scss",
"chars": 2106,
"preview": "@import '../../Theme.scss';\n\n#portal {\n display: flex;\n align-items: center;\n justify-content: center;\n\n .overlay {\n"
},
{
"path": "src/renderer/components/common/Modals/ErrorModal.tsx",
"chars": 770,
"preview": "import React, { PropsWithChildren } from 'react';\nimport ReactDom from 'react-dom';\nimport './ErrorModal.scss';\nimport {"
},
{
"path": "src/renderer/components/common/Notification.scss",
"chars": 1030,
"preview": "@import '../Theme.scss';\n\n#notification {\n direction: var(--app-direction);\n visibility: hidden;\n z-index: 1;\n "
},
{
"path": "src/renderer/components/common/Notification.tsx",
"chars": 829,
"preview": "import React from 'react';\nimport './Notification.scss';\nimport { useTranslation } from 'react-i18next';\n\ntype Notificat"
},
{
"path": "src/renderer/components/common/Shortcut.tsx",
"chars": 579,
"preview": "import React from 'react';\n\ntype ShortcutProps = {\n shortcut: string[];\n};\n\nconst Shortcut = ({ shortcut }: ShortcutPro"
},
{
"path": "src/renderer/hooks/useAddBlock.tsx",
"chars": 1883,
"preview": "import { useEffect } from 'react';\nimport {\n BlockElement,\n WidgetType,\n newWidgetRequest,\n} from '@renderer/common/t"
},
{
"path": "src/renderer/hooks/useDialog.tsx",
"chars": 876,
"preview": "import { BlockElement } from '@renderer/common/types';\nimport { useEffect } from 'react';\nimport { useGeneralContext } f"
},
{
"path": "src/renderer/hooks/useFileSaveLoad.tsx",
"chars": 2986,
"preview": "import { useGeneralContext } from '@components/GeneralContext';\nimport { useEffect } from 'react';\nimport { triggerPopup"
},
{
"path": "src/renderer/hooks/useSettings.tsx",
"chars": 752,
"preview": "import { useState } from 'react';\n\nfunction useSettings() {\n const [isRtl, setIsRtl] = useState(true);\n const [languag"
},
{
"path": "src/typings/index.d.ts",
"chars": 416,
"preview": "declare module '*.css';\ndeclare module '*.png';\ndeclare module '*.jpg';\ndeclare module '*.jpeg';\ndeclare module '*.svg';"
},
{
"path": "tools/forge/forge.config.js",
"chars": 3023,
"preview": "// Forge Configuration\nconst path = require('path');\nconst rootDir = process.cwd();\n\nmodule.exports = {\n // Packager Co"
},
{
"path": "tools/webpack/webpack.aliases.js",
"chars": 310,
"preview": "const { createWebpackAliases } = require('./webpack.helpers');\n\n// Export aliases\nmodule.exports = createWebpackAliases("
},
{
"path": "tools/webpack/webpack.helpers.js",
"chars": 353,
"preview": "const path = require('path');\nconst cwd = process.cwd();\n\n\nfunction inDev() {\n return process.env.NODE_ENV == 'developm"
},
{
"path": "tools/webpack/webpack.main.js",
"chars": 425,
"preview": "module.exports = {\n /**\n * This is the main entry point for your application, it's the first file\n * that runs in t"
},
{
"path": "tools/webpack/webpack.plugins.js",
"chars": 421,
"preview": "const webpack = require('webpack');\nconst ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');\nconst "
},
{
"path": "tools/webpack/webpack.renderer.js",
"chars": 497,
"preview": "const rules = require('./webpack.rules');\nconst plugins = require('./webpack.plugins');\n\nmodule.exports = {\n module: {\n"
},
{
"path": "tools/webpack/webpack.rules.js",
"chars": 1258,
"preview": "module.exports = [\n {\n // Add support for native node modules\n test: /native_modules\\/.+\\.node$/,\n use: 'node-"
},
{
"path": "tsconfig.json",
"chars": 734,
"preview": "{\n \"compilerOptions\": {\n \"forceConsistentCasingInFileNames\": true,\n \"jsx\": \"react\",\n \"allowJs\": true,\n \"tar"
}
]
About this extraction
This page contains the full source code of the yonatanmgr/mathberet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 101 files (294.4 KB), approximately 92.9k tokens, and a symbol index with 96 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.