Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da6c2657e1 | ||
|
|
eb6a6f1950 | ||
|
|
553324bc1c | ||
|
|
982827a00f | ||
|
|
0c0ceeb0fa | ||
|
|
24d5352f04 | ||
|
|
5b9df3748b | ||
|
|
5c4d058e72 | ||
|
|
39486a3f29 | ||
|
|
a09a321a7a | ||
|
|
dca99eae08 | ||
|
|
fbc753b467 | ||
|
|
e86b2559d6 | ||
|
|
a83b1bd9bd | ||
|
|
6decdd580a | ||
|
|
41f32f8af9 | ||
|
|
0620d76d8d | ||
|
|
dd8a91d0f8 | ||
|
|
977841899f | ||
|
|
81aee53e4f | ||
|
|
992f026662 | ||
|
|
44d4c83030 | ||
|
|
a88dfc4c37 | ||
|
|
40733ed679 | ||
|
|
e2ca8d5df3 | ||
|
|
20536d4f69 | ||
|
|
0cad4919a9 | ||
|
|
f85f52a7e5 | ||
|
|
24933a677d | ||
|
|
fcc96c0460 | ||
|
|
a4f55d9455 | ||
|
|
f7fdc3a8a0 | ||
|
|
aa639a0139 |
@@ -1,6 +1,3 @@
|
||||
src/App/Utilities/YAML/Schema/
|
||||
*.cjs
|
||||
*.js
|
||||
*.gen.tsx
|
||||
node_modules
|
||||
/app
|
||||
/deploy
|
||||
|
||||
@@ -8,8 +8,7 @@ plugins:
|
||||
parserOptions:
|
||||
ecmaVersion: latest
|
||||
sourceType: module
|
||||
project:
|
||||
- ./tsconfig.json
|
||||
project: ./tsconfig.json
|
||||
ecmaFeatures:
|
||||
jsx: true
|
||||
env:
|
||||
@@ -166,7 +165,6 @@ rules:
|
||||
jsx-quotes: 2
|
||||
key-spacing: 2
|
||||
keyword-spacing: 2
|
||||
line-comment-position: 2
|
||||
lines-around-comment:
|
||||
- 0
|
||||
# requires an empty line before block comments
|
||||
@@ -211,7 +209,6 @@ rules:
|
||||
- ignoreChainWithDepth: 2
|
||||
no-bitwise: 2
|
||||
no-continue: 2
|
||||
no-inline-comments: 2
|
||||
no-lonely-if: 2
|
||||
no-mixed-operators:
|
||||
- 2
|
||||
@@ -247,11 +244,6 @@ rules:
|
||||
- blocks: never
|
||||
classes: never
|
||||
switches: never
|
||||
padding-line-between-statements:
|
||||
- 2
|
||||
- blankLine: always
|
||||
prev: "*"
|
||||
next: return
|
||||
prefer-object-spread: 2
|
||||
quote-props:
|
||||
- 2
|
||||
@@ -291,8 +283,12 @@ rules:
|
||||
prefer-const: 2
|
||||
prefer-destructuring:
|
||||
- 2
|
||||
- object: true
|
||||
array: false
|
||||
- VariableDeclarator:
|
||||
array: true
|
||||
object: true
|
||||
AssignmentExpression:
|
||||
array: false
|
||||
object: false
|
||||
prefer-numeric-literals: 2
|
||||
prefer-rest-params: 2
|
||||
prefer-spread: 2
|
||||
@@ -341,7 +337,6 @@ rules:
|
||||
"@typescript-eslint/prefer-for-of": 2
|
||||
"@typescript-eslint/prefer-includes": 2
|
||||
"@typescript-eslint/prefer-readonly": 2
|
||||
"@typescript-eslint/promise-function-async": 2
|
||||
# "@typescript-eslint/quotes": 2
|
||||
"@typescript-eslint/require-array-sort-compare": 2
|
||||
"@typescript-eslint/require-await": 2
|
||||
@@ -363,10 +358,7 @@ rules:
|
||||
comma-spacing: 0
|
||||
"@typescript-eslint/comma-spacing": 2
|
||||
func-call-spacing: 0
|
||||
"@typescript-eslint/func-call-spacing":
|
||||
- 2
|
||||
- always
|
||||
- allowNewlines: true
|
||||
"@typescript-eslint/func-call-spacing": 2
|
||||
indent: 0
|
||||
"@typescript-eslint/indent": 0
|
||||
no-array-constructor: 0
|
||||
@@ -399,8 +391,6 @@ rules:
|
||||
- 2
|
||||
- never
|
||||
- beforeStatementContinuationChars: never
|
||||
space-before-function-paren: 0
|
||||
"@typescript-eslint/space-before-function-paren": 2
|
||||
|
||||
# React
|
||||
react/boolean-prop-naming: 2
|
||||
@@ -429,7 +419,7 @@ rules:
|
||||
react/no-will-update-set-state: 2
|
||||
react/prefer-es6-class: 2
|
||||
react/prefer-stateless-function: 2
|
||||
react/react-in-jsx-scope: 2
|
||||
react/react-in-jsx-scope: 0
|
||||
react/require-render-return: 2
|
||||
react/self-closing-comp: 2
|
||||
react/state-in-constructor:
|
||||
|
||||
@@ -27,10 +27,10 @@ jobs:
|
||||
with:
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
- name: Use Node.js 18.x
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20
|
||||
- name: Install Node.js dependencies
|
||||
run: npm ci
|
||||
- name: Compile JavaScript files
|
||||
|
||||
@@ -27,10 +27,10 @@ jobs:
|
||||
with:
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
- name: Use Node.js 18.x
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20
|
||||
- name: Install Node.js dependencies
|
||||
run: npm ci
|
||||
- name: Compile JavaScript files
|
||||
|
||||
@@ -20,10 +20,10 @@ jobs:
|
||||
with:
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
- name: Use Node.js 18.x
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20
|
||||
- name: Install Node.js dependencies
|
||||
run: npm ci
|
||||
- name: Compile TypeScript files
|
||||
@@ -39,10 +39,10 @@ jobs:
|
||||
with:
|
||||
token: ${{ secrets.ACCESS_TOKEN }}
|
||||
submodules: true
|
||||
- name: Use Node.js 18.x
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 18.x
|
||||
node-version: 20
|
||||
- name: Install Node.js dependencies
|
||||
run: npm ci
|
||||
- name: Run linter
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
.DS_Store
|
||||
node_modules/
|
||||
/.webpack/**/*
|
||||
!/.webpack/package.json
|
||||
npm-debug.log*
|
||||
.vs/
|
||||
/data/
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[submodule "app/Database"]
|
||||
path = app/Database
|
||||
path = src/database/contents
|
||||
url = https://github.com/elyukai/optolith-data.git
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "Schema/Config/Config.l10n.schema.json",
|
||||
"$ref": "#/definitions/Config",
|
||||
"definitions": {
|
||||
"Config": {
|
||||
"title": "RawConfig",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"herolistSortOrder": {
|
||||
"enum": ["name", "datemodified", "dateModified"]
|
||||
},
|
||||
"herolistVisibilityFilter": {
|
||||
"enum": ["all", "own", "shared"]
|
||||
},
|
||||
"racesSortOrder": {
|
||||
"enum": ["name", "cost"]
|
||||
},
|
||||
"racesValueVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"culturesSortOrder": {
|
||||
"enum": ["name", "cost"]
|
||||
},
|
||||
"culturesVisibilityFilter": {
|
||||
"enum": ["all", "common"]
|
||||
},
|
||||
"culturesValueVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"professionsSortOrder": {
|
||||
"enum": ["name", "cost"]
|
||||
},
|
||||
"professionsVisibilityFilter": {
|
||||
"enum": ["all", "common"]
|
||||
},
|
||||
"professionsFromExpansionsVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"professionsGroupVisibilityFilter": {
|
||||
"enum": [0, 1, 2, 3]
|
||||
},
|
||||
"advantagesDisadvantagesCultureRatingVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"talentsSortOrder": {
|
||||
"enum": ["name", "group", "ic"]
|
||||
},
|
||||
"talentsCultureRatingVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"combatTechniquesSortOrder": {
|
||||
"enum": ["name", "group", "ic"]
|
||||
},
|
||||
"specialAbilitiesSortOrder": {
|
||||
"enum": ["name", "group", "groupname"]
|
||||
},
|
||||
"spellsSortOrder": {
|
||||
"enum": ["name", "group", "property", "ic"]
|
||||
},
|
||||
"spellsUnfamiliarVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"liturgiesSortOrder": {
|
||||
"enum": ["name", "group", "ic"]
|
||||
},
|
||||
"equipmentSortOrder": {
|
||||
"enum": ["name", "groupname", "where", "weight"]
|
||||
},
|
||||
"equipmentGroupVisibilityFilter": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sheetCheckAttributeValueVisibility": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sheetUseParchment": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sheetZoomFactor": {
|
||||
"type": "number"
|
||||
},
|
||||
"enableActiveItemHints": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"locale": {
|
||||
"type": "string"
|
||||
},
|
||||
"fallbackLocale": {
|
||||
"type": "string"
|
||||
},
|
||||
"theme": {
|
||||
"enum": ["light", "dark"]
|
||||
},
|
||||
"enableEditingHeroAfterCreationPhase": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"meleeItemTemplatesCombatTechniqueFilter": {
|
||||
"type": "string"
|
||||
},
|
||||
"rangedItemTemplatesCombatTechniqueFilter": {
|
||||
"type": "string"
|
||||
},
|
||||
"enableAnimations": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"herolistSortOrder",
|
||||
"herolistVisibilityFilter",
|
||||
"racesSortOrder",
|
||||
"culturesSortOrder",
|
||||
"culturesVisibilityFilter",
|
||||
"professionsSortOrder",
|
||||
"professionsVisibilityFilter",
|
||||
"professionsGroupVisibilityFilter",
|
||||
"advantagesDisadvantagesCultureRatingVisibility",
|
||||
"talentsSortOrder",
|
||||
"talentsCultureRatingVisibility",
|
||||
"combatTechniquesSortOrder",
|
||||
"specialAbilitiesSortOrder",
|
||||
"spellsSortOrder",
|
||||
"spellsUnfamiliarVisibility",
|
||||
"liturgiesSortOrder",
|
||||
"equipmentSortOrder",
|
||||
"equipmentGroupVisibilityFilter",
|
||||
"enableActiveItemHints"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-check
|
||||
import { join } from "node:path"
|
||||
import { jsonSchema } from "optolith-tsjsonschemamd/renderers"
|
||||
|
||||
/** @type {import("optolith-tsjsonschemamd").GeneratorOptions} */
|
||||
export default {
|
||||
sourceDir: join("src", "shared", "schema"),
|
||||
outputs: [
|
||||
{
|
||||
targetDir: join("src", "assets", "schema"),
|
||||
renderer: jsonSchema({ spec: "Draft_07" }),
|
||||
}
|
||||
],
|
||||
clean: true,
|
||||
verbose: false
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "optolith",
|
||||
"productName": "Optolith",
|
||||
"version": "1.5.2-alpha.4",
|
||||
"version": "2.0.0-alpha.1",
|
||||
"description": "A generator for heroes for the P&P-RPG 'The Dark Eye'.",
|
||||
"author": {
|
||||
"name": "Lukas Obermann",
|
||||
@@ -9,31 +9,28 @@
|
||||
},
|
||||
"homepage": "https://optolith.app",
|
||||
"license": "MPL-2.0",
|
||||
"main": "app/main.js",
|
||||
"main": ".webpack/main.js",
|
||||
"dependencies": {
|
||||
"@electron/remote": "^2.0.8",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"adm-zip": "^0.5.1",
|
||||
"ajv": "6.12.6",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"ajv": "^8.12.0",
|
||||
"ajv-formats": "^2.1.1",
|
||||
"electron-extension-installer": "^1.2.0",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-updater": "^5.0.5",
|
||||
"electron-window-state": "5.0.3",
|
||||
"moment": "^2.29.4",
|
||||
"mousetrap": "1.6.5",
|
||||
"react": "16.13.1",
|
||||
"react-custom-scrollbars": "4.2.1",
|
||||
"react-dom": "16.13.1",
|
||||
"optolith-database-schema": "^0.12.0",
|
||||
"react": "^18.2.0",
|
||||
"react-custom-scrollbars-2": "^4.5.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-markdown": "^8.0.0",
|
||||
"react-portal": "4.2.1",
|
||||
"react-redux": "7.2.1",
|
||||
"react-textfit": "1.1.0",
|
||||
"redux": "4.0.5",
|
||||
"react-redux": "^8.0.7",
|
||||
"redux-devtools-extension": "2.13.8",
|
||||
"redux-thunk": "2.3.0",
|
||||
"rehype-raw": "^5.1.0",
|
||||
"remark-breaks": "^2.0.2",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"reselect": "4.0.0",
|
||||
"semver": "7.3.2",
|
||||
"tslib": "^2.3.1",
|
||||
"yaml": "1.10.0"
|
||||
@@ -41,40 +38,37 @@
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "11.0.0",
|
||||
"@commitlint/config-conventional": "11.0.0",
|
||||
"@types/classnames": "2.2.11",
|
||||
"@types/jest": "26.0.15",
|
||||
"@types/mousetrap": "1.6.4",
|
||||
"@types/node": "14.14.7",
|
||||
"@types/react": "16.9.56",
|
||||
"@types/react-custom-scrollbars": "4.0.7",
|
||||
"@types/react-dom": "16.9.9",
|
||||
"@types/react-portal": "4.0.2",
|
||||
"@types/node": "^20.2.5",
|
||||
"@types/react": "^18.2.7",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"@types/react-redux": "7.1.11",
|
||||
"@types/semver": "7.3.4",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"custom-env": "2.0.1",
|
||||
"dotenv": "8.2.0",
|
||||
"electron": "^19.0.8",
|
||||
"css-loader": "^6.8.1",
|
||||
"electron": "^24.1.3",
|
||||
"electron-builder": "^23.1.0",
|
||||
"electron-notarize": "^1.2.1",
|
||||
"eslint": "^8.7.0",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0",
|
||||
"eslint-plugin-tsdoc": "^0.2.14",
|
||||
"fs-extra": "9.0.1",
|
||||
"gentype": "3.38.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"husky": "^4.3.8",
|
||||
"jest": "^26.6.3",
|
||||
"sass": "1.29.0",
|
||||
"glob": "^10.2.6",
|
||||
"html-webpack-plugin": "^5.5.1",
|
||||
"mini-css-extract-plugin": "^2.7.6",
|
||||
"optolith-tsjsonschemamd": "^0.9.3",
|
||||
"resolve-url-loader": "^5.0.0",
|
||||
"sass": "^1.62.1",
|
||||
"sass-loader": "^13.3.1",
|
||||
"ssh2-sftp-client": "^9.0.1",
|
||||
"standard-version": "^9.3.1",
|
||||
"ts-jest": "^26.5.6",
|
||||
"ts-loader": "^9.2.6",
|
||||
"typescript": "^4.5.5",
|
||||
"webpack": "^5.67.0",
|
||||
"webpack-cli": "^4.9.2"
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"tsx": "^3.12.7",
|
||||
"typescript": "^5.0.4",
|
||||
"webpack": "^5.84.1",
|
||||
"webpack-cli": "^5.1.1"
|
||||
},
|
||||
"scripts": {
|
||||
"prerelease:win": "set NODE_ENV=development && node ./deploy/buildInsiderWin.js",
|
||||
@@ -90,17 +84,14 @@
|
||||
"js:watch": "webpack -w",
|
||||
"ts:build": "tsc",
|
||||
"ts:watch": "tsc -w",
|
||||
"createschemas": "otjsmd",
|
||||
"lint": "eslint \"src/\" --ext \".ts\" --ext \".tsx\"",
|
||||
"start": "electron .",
|
||||
"test": "jest",
|
||||
"test": "glob -c \"node --loader tsx --test\" \"./src/shared/**/*.test.ts\"",
|
||||
"circ": "madge -c ./src",
|
||||
"release:main": "standard-version --skip.commit --skip.tag",
|
||||
"release:pre": "standard-version --prerelease=alpha"
|
||||
},
|
||||
"repository": "github:elyukai/optolith-client",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
}
|
||||
}
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#about {
|
||||
.scroll-inner {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.third-party-software-body {
|
||||
font-size: 12px;
|
||||
line-height: normal;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import * as React from "react"
|
||||
import { L10n } from "../../Models/Wiki/L10n"
|
||||
import { StaticData, StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { app_path } from "../../Selectors/envSelectors"
|
||||
import { Markdown } from "../Universal/Markdown"
|
||||
import { Page } from "../Universal/Page"
|
||||
import { Scroll } from "../Universal/Scroll"
|
||||
|
||||
const getPath =
|
||||
(staticData: StaticDataRecord) =>
|
||||
path.join (
|
||||
app_path,
|
||||
"app",
|
||||
"Docs",
|
||||
L10n.A.id (StaticData.A.ui (staticData)),
|
||||
"CHANGELOG.md"
|
||||
)
|
||||
|
||||
interface LastChangesProps {
|
||||
staticData: StaticDataRecord
|
||||
}
|
||||
|
||||
export const LastChanges: React.FC<LastChangesProps> = ({ staticData }) => {
|
||||
const [ text, setText ] = React.useState<string> ("...")
|
||||
|
||||
React.useEffect (
|
||||
() => {
|
||||
fs.promises.readFile (getPath (staticData), "utf-8")
|
||||
.then (setText)
|
||||
.catch (err => {
|
||||
console.error (err)
|
||||
setText ("Changelog could not be loaded")
|
||||
})
|
||||
},
|
||||
[ staticData ]
|
||||
)
|
||||
|
||||
return (
|
||||
<Page id="last-changes">
|
||||
<Scroll className="text">
|
||||
<Markdown source={text} />
|
||||
</Scroll>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import * as React from "react"
|
||||
import { app_path, current_version } from "../../Selectors/envSelectors"
|
||||
import { Page } from "../Universal/Page"
|
||||
import { Scroll } from "../Universal/Scroll"
|
||||
|
||||
export const ThirdPartyLicenses = () => {
|
||||
const [ text, setText ] = React.useState<string> ("...")
|
||||
|
||||
React.useEffect (
|
||||
() => {
|
||||
fs.promises.readFile (path.join (app_path, "LICENSE"), "utf-8")
|
||||
.then (setText)
|
||||
.catch (err => {
|
||||
console.error (err)
|
||||
setText ("Third-party licenses could not be loaded")
|
||||
})
|
||||
},
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<Page id="last-changes">
|
||||
<Scroll className="text">
|
||||
<h2>
|
||||
{"Optolith Desktop Client v"}
|
||||
{current_version}
|
||||
</h2>
|
||||
<p>{"Third Party Software and Content Licenses"}</p>
|
||||
<pre className="third-party-software-body">
|
||||
{text}
|
||||
</pre>
|
||||
</Scroll>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
html, body, #bodywrapper, #body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#body {
|
||||
cursor: default;
|
||||
background: var(--background-color);
|
||||
display: flex;
|
||||
font: 14px Alegreya;
|
||||
border: 1px solid var(--separator-color-transparent);
|
||||
}
|
||||
|
||||
.background-image {
|
||||
position: absolute;
|
||||
width: 120vmax;
|
||||
height: 120vmax;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
left: -10vmax;
|
||||
|
||||
> img {
|
||||
opacity: .15;
|
||||
width: 100vmax;
|
||||
height: 100vmax;
|
||||
}
|
||||
}
|
||||
|
||||
#body.show-animations {
|
||||
@keyframes rotateBackground {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.background-image > img {
|
||||
animation-name: rotateBackground;
|
||||
animation-timing-function: linear;
|
||||
animation-duration: 300s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.loading-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
@keyframes rotateLoading {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
border-width: 3px;
|
||||
border-color: var(--accent-color) transparent;
|
||||
border-style: solid;
|
||||
animation-name: rotateLoading;
|
||||
animation-timing-function: linear;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
margin-top: 24px;
|
||||
color: var(--accent-color);
|
||||
font: 500 14px "Alegreya Sans";
|
||||
}
|
||||
}
|
||||
|
||||
section#content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.small-info-text {
|
||||
font: 500 12px Alegreya Sans;
|
||||
letter-spacing: 0.05em;
|
||||
text-transform: uppercase;
|
||||
color: var(--separator-color-halftransparent);
|
||||
}
|
||||
|
||||
ul:not(.list-wrapper) {
|
||||
list-style: none outside none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
padding-left: 18px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
transform: rotate(45deg);
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: var(--separator-color-transparent);
|
||||
margin-top: 8px;
|
||||
margin-left: -17px;
|
||||
}
|
||||
|
||||
em {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List, splitOn } from "../../Data/List"
|
||||
import { fromMaybe, guardReplace, Just, listToMaybe, Maybe } from "../../Data/Maybe"
|
||||
import { AlertsContainer } from "../Containers/AlertsContainer"
|
||||
import { DownloaderContainer } from "../Containers/DownloaderContainer"
|
||||
import { NavigationBarContainer } from "../Containers/NavigationBarContainer"
|
||||
import { Theme } from "../Models/Config"
|
||||
import { HeroModelRecord } from "../Models/Hero/HeroModel"
|
||||
import { L10n } from "../Models/Wiki/L10n"
|
||||
import { StaticData, StaticDataRecord } from "../Models/Wiki/WikiModel"
|
||||
import { classListMaybe } from "../Utilities/CSS"
|
||||
import { getSystemLocale } from "../Utilities/IOUtils"
|
||||
import { TabId } from "../Utilities/LocationUtils"
|
||||
import { pipe_ } from "../Utilities/pipe"
|
||||
import { Router } from "./Router/Router"
|
||||
import { Scroll } from "./Universal/Scroll"
|
||||
import { TitleBar } from "./Universal/TitleBar"
|
||||
|
||||
export interface AppOwnProps {}
|
||||
|
||||
export interface AppStateProps {
|
||||
currentTab: TabId
|
||||
staticData: StaticDataRecord
|
||||
mhero: Maybe<HeroModelRecord>
|
||||
platform: string
|
||||
theme: Theme
|
||||
areAnimationsEnabled: boolean
|
||||
isLoading: boolean
|
||||
hasInitWithError: boolean
|
||||
}
|
||||
|
||||
export interface AppDispatchProps {
|
||||
minimize (): void
|
||||
maximize (): void
|
||||
restore (): void
|
||||
close (): void
|
||||
closeDuringLoad (): void
|
||||
enterFullscreen (): void
|
||||
leaveFullscreen (): void
|
||||
checkForUpdates (): void
|
||||
}
|
||||
|
||||
export type AppProps = AppStateProps & AppDispatchProps & AppOwnProps
|
||||
|
||||
export interface AppState {
|
||||
hasError?: {
|
||||
error: Error
|
||||
info: any
|
||||
}
|
||||
}
|
||||
|
||||
export class App extends React.Component<AppProps, AppState> {
|
||||
state: AppState = {}
|
||||
|
||||
componentDidCatch (error: any, info: any) {
|
||||
this.setState (() => ({ hasError: { error, info } }))
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
currentTab,
|
||||
staticData,
|
||||
mhero,
|
||||
platform,
|
||||
theme,
|
||||
areAnimationsEnabled,
|
||||
minimize,
|
||||
maximize,
|
||||
restore,
|
||||
close,
|
||||
closeDuringLoad,
|
||||
enterFullscreen,
|
||||
leaveFullscreen,
|
||||
checkForUpdates,
|
||||
isLoading,
|
||||
hasInitWithError,
|
||||
} = this.props
|
||||
|
||||
const { hasError } = this.state
|
||||
|
||||
if (typeof hasError === "object") {
|
||||
return (
|
||||
<div id="body" className={`theme-${theme}`}>
|
||||
<Scroll className="error-message">
|
||||
<h4>{"Error"}</h4>
|
||||
<p>{hasError.error.stack}</p>
|
||||
<h4>{"Component Stack"}</h4>
|
||||
<p>{hasError.info.componentStack}</p>
|
||||
</Scroll>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div
|
||||
id="body"
|
||||
className={classListMaybe (List (
|
||||
Just (`theme-${theme}`),
|
||||
Just (`platform-${platform}`)
|
||||
))}
|
||||
lang={fromMaybe ("") (listToMaybe (splitOn ("-") (getSystemLocale ())))}
|
||||
>
|
||||
<div className="background-image">
|
||||
<img src="images/background.svg" alt="" />
|
||||
</div>
|
||||
|
||||
<div className="loading-wrapper">
|
||||
<div className="loading" />
|
||||
<div className="loading-text">
|
||||
{getSystemLocale () === "de-DE"
|
||||
? "Lade und überprüfe Tabellen und Nutzerdaten..."
|
||||
: "Loading and validating tables and user data..."}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<AlertsContainer />
|
||||
<TitleBar
|
||||
close={closeDuringLoad}
|
||||
enterFullscreen={enterFullscreen}
|
||||
leaveFullscreen={leaveFullscreen}
|
||||
maximize={maximize}
|
||||
minimize={minimize}
|
||||
platform={platform}
|
||||
restore={restore}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (hasInitWithError) {
|
||||
return (
|
||||
<div
|
||||
id="body"
|
||||
className={classListMaybe (List (
|
||||
Just (`theme-${theme}`),
|
||||
Just (`platform-${platform}`)
|
||||
))}
|
||||
lang={fromMaybe ("") (listToMaybe (splitOn ("-") (getSystemLocale ())))}
|
||||
>
|
||||
<div className="background-image">
|
||||
<img src="images/background.svg" alt="" />
|
||||
</div>
|
||||
<AlertsContainer />
|
||||
<TitleBar
|
||||
close={closeDuringLoad}
|
||||
enterFullscreen={enterFullscreen}
|
||||
leaveFullscreen={leaveFullscreen}
|
||||
maximize={maximize}
|
||||
minimize={minimize}
|
||||
platform={platform}
|
||||
restore={restore}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
id="body"
|
||||
className={classListMaybe (List (
|
||||
Just (`theme-${theme}`),
|
||||
Just (`platform-${platform}`),
|
||||
guardReplace (areAnimationsEnabled) ("show-animations")
|
||||
))}
|
||||
lang={pipe_ (
|
||||
staticData,
|
||||
StaticData.A.ui,
|
||||
L10n.A.id,
|
||||
splitOn ("-"),
|
||||
listToMaybe,
|
||||
fromMaybe ("")
|
||||
)}
|
||||
>
|
||||
<div className="background-image">
|
||||
<img src="images/background.svg" alt="" />
|
||||
</div>
|
||||
|
||||
<AlertsContainer />
|
||||
<DownloaderContainer staticData={staticData} />
|
||||
<TitleBar
|
||||
close={close}
|
||||
enterFullscreen={enterFullscreen}
|
||||
leaveFullscreen={leaveFullscreen}
|
||||
maximize={maximize}
|
||||
minimize={minimize}
|
||||
platform={platform}
|
||||
restore={restore}
|
||||
/>
|
||||
|
||||
<section id="content">
|
||||
<NavigationBarContainer
|
||||
staticData={staticData}
|
||||
checkForUpdates={checkForUpdates}
|
||||
mhero={mhero}
|
||||
/>
|
||||
<Router
|
||||
key={currentTab}
|
||||
id={currentTab}
|
||||
staticData={staticData}
|
||||
mhero={mhero}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
@import "NavigationBarBack";
|
||||
@import "NavigationBarLeft";
|
||||
@import "NavigationBarRight";
|
||||
@import "NavigationBarTabs";
|
||||
@import "NavigationBarWrapper";
|
||||
@@ -1,197 +0,0 @@
|
||||
import * as remote from "@electron/remote"
|
||||
import * as React from "react"
|
||||
import { fmap } from "../../../Data/Functor"
|
||||
import { List } from "../../../Data/List"
|
||||
import { fromMaybe, Maybe, maybe } from "../../../Data/Maybe"
|
||||
import { Record } from "../../../Data/Record"
|
||||
import { SettingsContainer } from "../../Containers/SettingsContainer"
|
||||
import { HeroModelRecord } from "../../Models/Hero/HeroModel"
|
||||
import { SubTab } from "../../Models/Hero/heroTypeHelpers"
|
||||
import { AdventurePointsCategories } from "../../Models/View/AdventurePointsCategories"
|
||||
import { NavigationBarTabOptions } from "../../Models/View/NavigationBarTabOptions"
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { translate, translateP } from "../../Utilities/I18n"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { signNeg } from "../../Utilities/NumberUtils"
|
||||
import { pipe, pipe_ } from "../../Utilities/pipe"
|
||||
import { AvatarWrapper } from "../Universal/AvatarWrapper"
|
||||
import { BorderButton } from "../Universal/BorderButton"
|
||||
import { IconButton } from "../Universal/IconButton"
|
||||
import { Text } from "../Universal/Text"
|
||||
import { TooltipToggle } from "../Universal/TooltipToggle"
|
||||
import { ApTooltip } from "./ApTooltip"
|
||||
import { NavigationBarBack } from "./NavigationBarBack"
|
||||
import { NavigationBarLeft } from "./NavigationBarLeft"
|
||||
import { NavigationBarRight } from "./NavigationBarRight"
|
||||
import { NavigationBarSubTabs } from "./NavigationBarSubTabs"
|
||||
import { NavigationBarTabs } from "./NavigationBarTabs"
|
||||
import { NavigationBarWrapper } from "./NavigationBarWrapper"
|
||||
|
||||
const toggleDevtools = () => {
|
||||
remote.getCurrentWindow ().webContents.toggleDevTools ()
|
||||
}
|
||||
|
||||
export interface NavigationBarOwnProps {
|
||||
mhero: Maybe<HeroModelRecord>
|
||||
staticData: StaticDataRecord
|
||||
checkForUpdates (): void
|
||||
}
|
||||
|
||||
export interface NavigationBarStateProps {
|
||||
currentTab: TabId
|
||||
avatar: Maybe<string>
|
||||
isRedoAvailable: boolean
|
||||
isRemovingEnabled: boolean
|
||||
isUndoAvailable: boolean
|
||||
isSettingsOpen: boolean
|
||||
isHeroSection: boolean
|
||||
tabs: List<Record<NavigationBarTabOptions>>
|
||||
subtabs: Maybe<List<SubTab>>
|
||||
adventurePoints: Maybe<Record<AdventurePointsCategories>>
|
||||
maximumForMagicalAdvantagesDisadvantages: Maybe<number>
|
||||
isSpellcaster: boolean
|
||||
isBlessedOne: boolean
|
||||
}
|
||||
|
||||
export interface NavigationBarDispatchProps {
|
||||
undo (): void
|
||||
redo (): void
|
||||
saveHero (): void
|
||||
saveGroup (): void
|
||||
setTab (id: TabId): void
|
||||
openSettings (): void
|
||||
closeSettings (): void
|
||||
}
|
||||
|
||||
export type NavigationBarProps =
|
||||
NavigationBarStateProps & NavigationBarDispatchProps & NavigationBarOwnProps
|
||||
|
||||
export const NavigationBar: React.FC<NavigationBarProps> = props => {
|
||||
const {
|
||||
currentTab,
|
||||
tabs,
|
||||
subtabs: msubtabs,
|
||||
openSettings,
|
||||
closeSettings,
|
||||
isHeroSection,
|
||||
avatar,
|
||||
staticData,
|
||||
undo,
|
||||
isRedoAvailable,
|
||||
isUndoAvailable,
|
||||
redo,
|
||||
saveHero,
|
||||
setTab,
|
||||
adventurePoints: m_ap,
|
||||
maximumForMagicalAdvantagesDisadvantages,
|
||||
isSpellcaster,
|
||||
isBlessedOne,
|
||||
isSettingsOpen,
|
||||
checkForUpdates,
|
||||
} = props
|
||||
|
||||
const handleHerolistTab = React.useCallback (() => setTab (TabId.Herolist), [ setTab ])
|
||||
|
||||
return (
|
||||
<>
|
||||
<NavigationBarWrapper>
|
||||
<NavigationBarLeft>
|
||||
{isHeroSection
|
||||
? (
|
||||
<>
|
||||
<NavigationBarBack handleSetTab={handleHerolistTab} />
|
||||
<AvatarWrapper src={avatar} />
|
||||
</>
|
||||
)
|
||||
: null}
|
||||
<NavigationBarTabs
|
||||
currentTab={currentTab}
|
||||
tabs={tabs}
|
||||
/>
|
||||
</NavigationBarLeft>
|
||||
<NavigationBarRight>
|
||||
{isHeroSection
|
||||
? (
|
||||
<>
|
||||
{maybe (<Text className="collected-ap">
|
||||
{translateP (staticData) ("header.apleft") (List ("X"))}
|
||||
</Text>)
|
||||
((ap: Record<AdventurePointsCategories>) => (
|
||||
<TooltipToggle
|
||||
position="bottom"
|
||||
margin={12}
|
||||
content={
|
||||
<ApTooltip
|
||||
adventurePoints={ap}
|
||||
staticData={staticData}
|
||||
maximumForMagicalAdvantagesDisadvantages={
|
||||
maximumForMagicalAdvantagesDisadvantages
|
||||
}
|
||||
isSpellcaster={isSpellcaster}
|
||||
isBlessedOne={isBlessedOne}
|
||||
/>
|
||||
}
|
||||
target={
|
||||
<Text className="collected-ap">
|
||||
{translateP (staticData)
|
||||
("header.apleft")
|
||||
(List (
|
||||
pipe_ (
|
||||
m_ap,
|
||||
fmap (pipe (
|
||||
AdventurePointsCategories.A.available,
|
||||
signNeg
|
||||
)),
|
||||
fromMaybe <string | number > ("")
|
||||
)
|
||||
))}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
))
|
||||
(m_ap)}
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={undo}
|
||||
disabled={!isUndoAvailable}
|
||||
/>
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={redo}
|
||||
disabled={!isRedoAvailable}
|
||||
/>
|
||||
<BorderButton
|
||||
label={translate (staticData) ("header.savebtn")}
|
||||
onClick={saveHero}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
: null}
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={openSettings}
|
||||
/>
|
||||
<SettingsContainer
|
||||
staticData={staticData}
|
||||
isSettingsOpen={isSettingsOpen}
|
||||
close={closeSettings}
|
||||
checkForUpdates={checkForUpdates}
|
||||
/>
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={toggleDevtools}
|
||||
/>
|
||||
</NavigationBarRight>
|
||||
</NavigationBarWrapper>
|
||||
{maybe (null as React.ReactNode)
|
||||
((subtabs: List<SubTab>) => (
|
||||
<NavigationBarSubTabs
|
||||
tabs={subtabs}
|
||||
currentTab={currentTab}
|
||||
setTab={setTab}
|
||||
/>
|
||||
))
|
||||
(msubtabs)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import * as remote from "@electron/remote"
|
||||
import * as React from "react"
|
||||
import { useDispatch } from "react-redux"
|
||||
import { setTab } from "../../Actions/LocationActions"
|
||||
import { SettingsContainer } from "../../Containers/SettingsContainer"
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { translate } from "../../Utilities/I18n"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { BorderButton } from "../Universal/BorderButton"
|
||||
import { IconButton } from "../Universal/IconButton"
|
||||
import { Text } from "../Universal/Text"
|
||||
import { NavigationBarBack } from "./NavigationBarBack"
|
||||
import { NavigationBarLeft } from "./NavigationBarLeft"
|
||||
import { NavigationBarRight } from "./NavigationBarRight"
|
||||
import { NavigationBarWrapper } from "./NavigationBarWrapper"
|
||||
|
||||
interface Props {
|
||||
staticData: StaticDataRecord
|
||||
groupName: string
|
||||
isSettingsOpen: boolean
|
||||
closeSettings (): void
|
||||
openSettings (): void
|
||||
saveGroup (): void
|
||||
checkForUpdates (): void
|
||||
}
|
||||
|
||||
const toggleDevtools = remote.getCurrentWindow ().webContents.toggleDevTools
|
||||
|
||||
export const NavigationBarForGroup: React.FC<Props> = props => {
|
||||
const {
|
||||
staticData,
|
||||
groupName,
|
||||
isSettingsOpen,
|
||||
closeSettings,
|
||||
openSettings,
|
||||
saveGroup,
|
||||
checkForUpdates,
|
||||
} = props
|
||||
|
||||
const dispatch = useDispatch ()
|
||||
|
||||
const handleSetTab = React.useCallback (
|
||||
() => dispatch (setTab (TabId.Grouplist)),
|
||||
[ dispatch ]
|
||||
)
|
||||
|
||||
return (
|
||||
<NavigationBarWrapper>
|
||||
<NavigationBarLeft>
|
||||
<NavigationBarBack handleSetTab={handleSetTab} />
|
||||
<Text>{groupName}</Text>
|
||||
</NavigationBarLeft>
|
||||
<NavigationBarRight>
|
||||
<BorderButton
|
||||
label={translate (staticData) ("header.savebtn")}
|
||||
onClick={saveGroup}
|
||||
/>
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={openSettings}
|
||||
/>
|
||||
<SettingsContainer
|
||||
staticData={staticData}
|
||||
isSettingsOpen={isSettingsOpen}
|
||||
close={closeSettings}
|
||||
checkForUpdates={checkForUpdates}
|
||||
/>
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={toggleDevtools}
|
||||
/>
|
||||
</NavigationBarRight>
|
||||
</NavigationBarWrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
.navigationbar-left {
|
||||
flex: 1 1 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
> div {
|
||||
margin-left: 24px;
|
||||
|
||||
&.avatar-wrapper {
|
||||
flex-shrink: 0;
|
||||
align-self: center;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-left: 28px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&.text {
|
||||
color: var(--headings-color);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import * as React from "react"
|
||||
|
||||
interface Props { }
|
||||
|
||||
export const NavigationBarLeft: React.FC<Props> = ({ children }) => (
|
||||
<div className="navigationbar-left">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
@@ -1,9 +0,0 @@
|
||||
import * as React from "react"
|
||||
|
||||
interface Props { }
|
||||
|
||||
export const NavigationBarRight: React.FC<Props> = ({ children }) => (
|
||||
<div className="navigationbar-right">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
@@ -1,29 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { SubTab } from "../../Models/Hero/heroTypeHelpers"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { Tab } from "../Universal/Tab"
|
||||
|
||||
interface Props {
|
||||
currentTab: TabId
|
||||
tab: SubTab
|
||||
setTab (tab: TabId): void
|
||||
}
|
||||
|
||||
export const NavigationBarSubTab: React.FC<Props> = props => {
|
||||
const { currentTab, tab, setTab } = props
|
||||
|
||||
const { id, label, disabled } = tab
|
||||
|
||||
const is_active = currentTab === id
|
||||
|
||||
const handleTab = React.useCallback (() => setTab (id), [ setTab, id ])
|
||||
|
||||
return (
|
||||
<Tab
|
||||
active={is_active}
|
||||
onClick={handleTab}
|
||||
label={label}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
.navigationbar-subtabs {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 32px;
|
||||
flex: none;
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background: var(--separator-color-transparent);
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
> .tab {
|
||||
font: bold 13px/32px Alegreya SC;
|
||||
flex: 0 1 auto;
|
||||
letter-spacing: 0.1em;
|
||||
margin: 0 20px;
|
||||
text-transform: uppercase;
|
||||
position: relative;
|
||||
color: var(--accent-color);
|
||||
min-width: 0;
|
||||
z-index: 2;
|
||||
|
||||
&:hover {
|
||||
color: var(--headings-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
color: var(--accent-color-intense);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
&.active {
|
||||
pointer-events: none;
|
||||
color: var(--headings-color);
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: auto;
|
||||
height: 2px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
background: var(--accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
color: var(--separator-color-halftransparent);
|
||||
}
|
||||
|
||||
div {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List, map, toArray } from "../../../Data/List"
|
||||
import { SubTab } from "../../Models/Hero/heroTypeHelpers"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { pipe_ } from "../../Utilities/pipe"
|
||||
import { NavigationBarSubTab } from "./NavigationBarSubTab"
|
||||
|
||||
interface Props {
|
||||
currentTab: TabId
|
||||
tabs: List<SubTab>
|
||||
setTab (tab: TabId): void
|
||||
}
|
||||
|
||||
export const NavigationBarSubTabs: React.FC<Props> = props => {
|
||||
const { currentTab, tabs, setTab } = props
|
||||
|
||||
return (
|
||||
<div className="navigationbar-subtabs">
|
||||
{pipe_ (
|
||||
tabs,
|
||||
map (tab => (
|
||||
<NavigationBarSubTab
|
||||
key={tab .id}
|
||||
currentTab={currentTab}
|
||||
tab={tab}
|
||||
setTab={setTab}
|
||||
/>
|
||||
)),
|
||||
toArray
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { useDispatch } from "react-redux"
|
||||
import { elem, notNull } from "../../../Data/List"
|
||||
import { Record } from "../../../Data/Record"
|
||||
import { setTab } from "../../Actions/LocationActions"
|
||||
import { NavigationBarTabOptions } from "../../Models/View/NavigationBarTabOptions"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { Tab } from "../Universal/Tab"
|
||||
|
||||
const NBTOA = NavigationBarTabOptions.A
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
currentTab: TabId
|
||||
options: Record<NavigationBarTabOptions>
|
||||
}
|
||||
|
||||
export const NavigationBarTab: React.FC<Props> = props => {
|
||||
const {
|
||||
className,
|
||||
currentTab,
|
||||
options,
|
||||
} = props
|
||||
|
||||
const id = NBTOA.id (options)
|
||||
const label = NBTOA.label (options)
|
||||
const subTabs = NBTOA.subTabs (options)
|
||||
|
||||
const dispatch = useDispatch ()
|
||||
|
||||
const handleSetTab = React.useCallback (
|
||||
() => dispatch (setTab (id)),
|
||||
[ dispatch, id ]
|
||||
)
|
||||
|
||||
const isActive = notNull (subTabs) ? elem (currentTab) (subTabs) : currentTab === id
|
||||
|
||||
return (
|
||||
<Tab
|
||||
key={id}
|
||||
active={isActive}
|
||||
onClick={handleSetTab}
|
||||
className={className}
|
||||
label={label}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
.navigationbar-tabs {
|
||||
flex: 1 1 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
.tab {
|
||||
font: bold 15px/var(--navigationbar-height) Alegreya SC;
|
||||
// font: bold 18px/#{$titlebar-height} Alegreya SC;
|
||||
flex: 0 1 auto;
|
||||
letter-spacing: 0.1em;
|
||||
margin: 0 20px;
|
||||
text-transform: uppercase;
|
||||
color: var(--accent-color);
|
||||
min-width: 0;
|
||||
// padding: 0 10px;
|
||||
position: relative;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--headings-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active, &:focus {
|
||||
color: var(--accent-color-intense);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.active {
|
||||
pointer-events: none;
|
||||
color: var(--headings-color);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: auto;
|
||||
height: 3px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
background: var(--accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
color: var(--separator-color-halftransparent);
|
||||
}
|
||||
|
||||
div {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List, map, toArray } from "../../../Data/List"
|
||||
import { Record } from "../../../Data/Record"
|
||||
import { NavigationBarTabOptions } from "../../Models/View/NavigationBarTabOptions"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { pipe_ } from "../../Utilities/pipe"
|
||||
import { NavigationBarTab } from "./NavigationBarTab"
|
||||
|
||||
const NBTOA = NavigationBarTabOptions.A
|
||||
|
||||
interface Props {
|
||||
currentTab: TabId
|
||||
tabs: List<Record<NavigationBarTabOptions>>
|
||||
}
|
||||
|
||||
export const NavigationBarTabs: React.FC<Props> = props => {
|
||||
const { currentTab, tabs } = props
|
||||
|
||||
return (
|
||||
<div className="navigationbar-tabs">
|
||||
{pipe_ (
|
||||
tabs,
|
||||
map (tab => (
|
||||
<NavigationBarTab
|
||||
key={NBTOA.id (tab)}
|
||||
currentTab={currentTab}
|
||||
options={tab}
|
||||
/>
|
||||
)),
|
||||
toArray
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import * as React from "react"
|
||||
|
||||
interface Props { }
|
||||
|
||||
export const NavigationBarWrapper: React.FC<Props> = ({ children }) => (
|
||||
<div className="navigationbar">
|
||||
<div className="navigationbar-inner">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -1,171 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { Maybe, maybe } from "../../../Data/Maybe"
|
||||
import { AdvantagesContainer } from "../../Containers/AdvantagesContainer"
|
||||
import { AttributesContainer } from "../../Containers/AttributesContainer"
|
||||
import { CombatTechniquesContainer } from "../../Containers/CombatTechniquesContainer"
|
||||
import { CulturesContainer } from "../../Containers/CulturesContainer"
|
||||
import { DisadvantagesContainer } from "../../Containers/DisadvantagesContainer"
|
||||
import { EquipmentContainer } from "../../Containers/EquipmentContainer"
|
||||
import { HelpContainer } from "../../Containers/HelpContainer"
|
||||
import { HerolistContainer } from "../../Containers/HerolistContainer"
|
||||
import { HitZoneArmorsContainer } from "../../Containers/HitZoneArmorsContainer"
|
||||
import { LiturgicalChantsContainer } from "../../Containers/LiturgicalChantsContainer"
|
||||
import { PactContainer } from "../../Containers/PactContainer"
|
||||
import { PersonalDataContainer } from "../../Containers/PersonalDataContainer"
|
||||
import { PetsContainer } from "../../Containers/PetsContainer"
|
||||
import { ProfessionsContainer } from "../../Containers/ProfessionsContainer"
|
||||
import { RacesContainer } from "../../Containers/RacesContainer"
|
||||
import { RulesContainer } from "../../Containers/RulesContainer"
|
||||
import { SheetsContainer } from "../../Containers/SheetsContainer"
|
||||
import { SkillsContainer } from "../../Containers/SkillsContainer"
|
||||
import { SpecialAbilitiesContainer } from "../../Containers/SpecialAbilitiesContainer"
|
||||
import { SpellsContainer } from "../../Containers/SpellsContainer"
|
||||
import { WikiContainer } from "../../Containers/WikiContainer"
|
||||
import { HeroModelRecord } from "../../Models/Hero/HeroModel"
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { Imprint } from "../About/Imprint"
|
||||
import { LastChanges } from "../About/LastChanges"
|
||||
import { ThirdPartyLicenses } from "../About/ThirdPartyLicenses"
|
||||
import { Grouplist } from "../Groups/Grouplist"
|
||||
import { MainContent } from "../Universal/MainContent"
|
||||
import { Page } from "../Universal/Page"
|
||||
import { Scroll } from "../Universal/Scroll"
|
||||
|
||||
interface Props {
|
||||
id: TabId
|
||||
staticData: StaticDataRecord
|
||||
mhero: Maybe<HeroModelRecord>
|
||||
}
|
||||
|
||||
interface State {
|
||||
hasError?: {
|
||||
error: Error
|
||||
info: any
|
||||
}
|
||||
}
|
||||
|
||||
export class Router extends React.Component<Props> {
|
||||
state: State = {}
|
||||
|
||||
componentDidCatch (error: any, info: any) {
|
||||
this.setState (() => ({ hasError: { error, info } }))
|
||||
}
|
||||
|
||||
render (): React.ReactNode {
|
||||
const { id, staticData, mhero } = this.props
|
||||
const { hasError } = this.state
|
||||
|
||||
if (typeof hasError === "object") {
|
||||
return (
|
||||
<Page>
|
||||
<MainContent>
|
||||
<Scroll className="error-message">
|
||||
<h4>{"Error"}</h4>
|
||||
<p>{hasError.error.stack}</p>
|
||||
<h4>{"Component Stack"}</h4>
|
||||
<p>{hasError.info.componentStack}</p>
|
||||
</Scroll>
|
||||
</MainContent>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
const unwrapWithHero =
|
||||
(f: (hero: HeroModelRecord) => JSX.Element) =>
|
||||
maybe (null as React.ReactNode) (f) (mhero)
|
||||
|
||||
const VIEWS: { [K in TabId]: () => React.ReactNode } = {
|
||||
[TabId.Herolist]: () => <HerolistContainer staticData={staticData} />,
|
||||
[TabId.Grouplist]: () => <Grouplist />,
|
||||
[TabId.Wiki]: () => <WikiContainer staticData={staticData} />,
|
||||
[TabId.Faq]: () => <HelpContainer staticData={staticData} />,
|
||||
[TabId.Imprint]: () => <Imprint staticData={staticData} />,
|
||||
[TabId.ThirdPartyLicenses]: () => <ThirdPartyLicenses />,
|
||||
[TabId.LastChanges]: () => <LastChanges staticData={staticData} />,
|
||||
|
||||
[TabId.Profile]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<PersonalDataContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.PersonalData]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<PersonalDataContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.CharacterSheet]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<SheetsContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Pact]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<PactContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Rules]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<RulesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
|
||||
[TabId.Races]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<RacesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Cultures]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<CulturesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Professions]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<ProfessionsContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
|
||||
[TabId.Attributes]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<AttributesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
|
||||
[TabId.Advantages]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<AdvantagesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Disadvantages]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<DisadvantagesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
|
||||
[TabId.Skills]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<SkillsContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.CombatTechniques]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<CombatTechniquesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.SpecialAbilities]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<SpecialAbilitiesContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Spells]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<SpellsContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.LiturgicalChants]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<LiturgicalChantsContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
|
||||
[TabId.Equipment]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<EquipmentContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.ZoneArmor]:
|
||||
() => unwrapWithHero (hero => (
|
||||
<HitZoneArmorsContainer staticData={staticData} hero={hero} />
|
||||
)),
|
||||
[TabId.Pets]: () => <PetsContainer staticData={staticData} />,
|
||||
|
||||
// master: <Master />
|
||||
}
|
||||
|
||||
return VIEWS [id] ()
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
.btn {
|
||||
height: auto;
|
||||
min-height: 32px;
|
||||
color: var(--accent-color);
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--accent-color);
|
||||
|
||||
&:hover, &:active {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
border-color: var(--separator-color-transparent);
|
||||
background: none;
|
||||
color: var(--separator-color-halftransparent);
|
||||
pointer-events: none;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--separator-color-transparent);
|
||||
color: var(--separator-color-halftransparent);
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--accent-color);
|
||||
color: var(--background-color);
|
||||
pointer-events: none;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--accent-color);
|
||||
}
|
||||
}
|
||||
|
||||
&.autoWidth {
|
||||
width: auto;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
&.btn-flat {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { guardReplace, Just, Maybe, maybe, normalize, or, orN } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
import { TooltipHint } from "./TooltipHint"
|
||||
|
||||
interface Props {
|
||||
active?: boolean
|
||||
autoWidth?: boolean
|
||||
className?: string
|
||||
disabled?: boolean | Maybe<boolean>
|
||||
flat?: boolean
|
||||
fullWidth?: boolean
|
||||
hint?: Maybe<string>
|
||||
primary?: boolean
|
||||
round?: boolean
|
||||
onClick? (): void
|
||||
}
|
||||
|
||||
export const Button: React.FC<Props> = props => {
|
||||
const {
|
||||
active,
|
||||
autoWidth,
|
||||
primary,
|
||||
flat,
|
||||
fullWidth,
|
||||
disabled,
|
||||
round,
|
||||
children,
|
||||
onClick,
|
||||
hint: mhint,
|
||||
} = props
|
||||
|
||||
let { className } = props
|
||||
|
||||
const disabled_m = or (normalize (disabled))
|
||||
|
||||
className = classListMaybe (List (
|
||||
Just ("btn"),
|
||||
Just (orN (round) ? "btn-round" : "btn-text"),
|
||||
guardReplace (orN (primary)) ("btn-primary"),
|
||||
guardReplace (orN (flat)) ("btn-flat"),
|
||||
guardReplace (orN (autoWidth)) ("autoWidth"),
|
||||
guardReplace (orN (fullWidth)) ("fullWidth"),
|
||||
guardReplace (disabled_m) ("disabled"),
|
||||
guardReplace (orN (active)) ("active")
|
||||
))
|
||||
|
||||
const btnElement = (
|
||||
<div
|
||||
className={className}
|
||||
onClick={disabled_m ? undefined : onClick}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
|
||||
return maybe (btnElement)
|
||||
((hint: string) => (
|
||||
<TooltipHint
|
||||
hint={hint}
|
||||
target={btnElement}
|
||||
margin={8}
|
||||
/>
|
||||
))
|
||||
(normalize (mhint))
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { Just, Maybe } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const Icon: React.FC<Props> = props => {
|
||||
const { className, children } = props
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classListMaybe (List (Just ("icon"), Maybe (className)))}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { Just, Maybe } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
}
|
||||
|
||||
export const ListView: React.FC<Props> = props => {
|
||||
const { children, className } = props
|
||||
|
||||
return (
|
||||
<ul className={classListMaybe (List (Just ("list-wrapper"), Maybe (className)))}>
|
||||
{children}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import * as React from "react"
|
||||
|
||||
interface Props { }
|
||||
|
||||
export const ListHeader: React.FC<Props> = props => {
|
||||
const { children } = props
|
||||
|
||||
return (
|
||||
<div className="list-header">
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { Just, Maybe } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
import { TooltipHint } from "./TooltipHint"
|
||||
|
||||
interface Props {
|
||||
children?: React.ReactNode
|
||||
className: string
|
||||
hint?: string
|
||||
}
|
||||
|
||||
export const ListHeaderTag: React.FC<Props> = props => {
|
||||
const { children, className, hint } = props
|
||||
|
||||
if (typeof hint === "string") {
|
||||
return (
|
||||
<TooltipHint
|
||||
hint={hint}
|
||||
target={
|
||||
<div className={classListMaybe (List (Just ("has-hint"), Maybe (className)))}>
|
||||
{children}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
.page {
|
||||
flex: 1 1 auto;
|
||||
font: 14px/22px Alegreya Sans;
|
||||
letter-spacing: 0.025em;
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List, notNullStrUndef } from "../../../Data/List"
|
||||
import { guardReplace, Just, Maybe, orN } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
import { Text } from "./Text"
|
||||
|
||||
export interface TabBaseProps {
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
label: string | undefined
|
||||
}
|
||||
|
||||
export interface TabProps extends TabBaseProps {
|
||||
active: boolean
|
||||
onClick (): void
|
||||
}
|
||||
|
||||
export const Tab: React.FC<TabProps> = props => {
|
||||
const { active, children, className, disabled, label, onClick } = props
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
classListMaybe (List (
|
||||
Just ("tab"),
|
||||
guardReplace (active) ("active"),
|
||||
guardReplace (orN (disabled)) ("disabled"),
|
||||
Maybe (className)
|
||||
))
|
||||
}
|
||||
onClick={orN (disabled) ? undefined : onClick}
|
||||
>
|
||||
<Text>{notNullStrUndef (label) ? label : children}</Text>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
.titlebar {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: calc(var(--titlebar-height) + 1px);
|
||||
z-index: 11000;
|
||||
top: 0;
|
||||
right: 0;
|
||||
-webkit-app-region: drag;
|
||||
padding: 1px 1px 0;
|
||||
|
||||
&.empty {
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
--windows-titlebar-close: #e81123;
|
||||
--mac-titlebar-close: #fc5753;
|
||||
--mac-titlebar-close-active: #bf4744;
|
||||
--mac-titlebar-close-icon: #97040c;
|
||||
--mac-titlebar-close-icon-active: #5c090b;
|
||||
--mac-titlebar-minimize: #fdbc40;
|
||||
--mac-titlebar-minimize-active: #be8d2f;
|
||||
--mac-titlebar-minimize-icon: #985712;
|
||||
--mac-titlebar-minimize-icon-active: #582806;
|
||||
--mac-titlebar-fullscreen: #33c748;
|
||||
--mac-titlebar-fullscreen-active: #269636;
|
||||
--mac-titlebar-fullscreen-icon: #0b650d;
|
||||
--mac-titlebar-fullscreen-icon-active: #023002;
|
||||
}
|
||||
|
||||
.titlebar-inner {
|
||||
height: var(--titlebar-height);
|
||||
width: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
justify-content: flex-end;
|
||||
border-bottom: 1px solid var(--separator-color-transparent);
|
||||
// background: var(--background-color);
|
||||
}
|
||||
|
||||
.platform-win32, .platform-linux {
|
||||
.titlebar .titlebar-btn {
|
||||
width: 46px;
|
||||
height: 30px;
|
||||
font: 16px/30px TDE Heroes;
|
||||
color: var(--accent-color);
|
||||
-webkit-app-region: no-drag;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
color: var(--headings-color);
|
||||
background: var(--separator-color-transparent);
|
||||
}
|
||||
|
||||
&.close:hover {
|
||||
background: var(--windows-titlebar-close);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.platform-darwin .titlebar {
|
||||
.titlebar-inner {
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&.not-focused .titlebar-btn {
|
||||
&.close, &.minimize, &.fullscreen {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
|
||||
.macos-hover-area {
|
||||
-webkit-app-region: no-drag;
|
||||
border-radius: 6px;
|
||||
margin-left: 13px;
|
||||
display: flex;
|
||||
|
||||
&:hover .titlebar-btn, &:active .titlebar-btn {
|
||||
&.close, &.minimize, &.fullscreen {
|
||||
span {
|
||||
&::after, &::before {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.close {
|
||||
background: var(--mac-titlebar-close);
|
||||
}
|
||||
|
||||
&.minimize {
|
||||
background: var(--mac-titlebar-minimize);
|
||||
}
|
||||
|
||||
&.fullscreen {
|
||||
background: var(--mac-titlebar-fullscreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.titlebar-btn {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
font: 24px/22px TDE Heroes;
|
||||
color: transparent;
|
||||
-webkit-app-region: no-drag;
|
||||
text-align: center;
|
||||
border-radius: 50%;
|
||||
margin-left: 8px;
|
||||
border: 1px solid var(--separator-color-transparent);
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
&::after, &::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.close {
|
||||
background: var(--mac-titlebar-close);
|
||||
|
||||
span::after, span::before {
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
background: var(--mac-titlebar-close-icon);
|
||||
}
|
||||
|
||||
span::before {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
span::after {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--mac-titlebar-close-active);
|
||||
|
||||
span::after, span::before {
|
||||
background: var(--mac-titlebar-close-icon-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.minimize {
|
||||
background: var(--mac-titlebar-minimize);
|
||||
|
||||
span::before {
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
background: var(--mac-titlebar-minimize-icon);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--mac-titlebar-minimize-active);
|
||||
|
||||
span::before {
|
||||
background: var(--mac-titlebar-minimize-icon-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.fullscreen {
|
||||
background: var(--mac-titlebar-fullscreen);
|
||||
|
||||
span::after, span::before {
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
span::before {
|
||||
background: var(--mac-titlebar-fullscreen-icon);
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
span::after {
|
||||
background: var(--mac-titlebar-fullscreen);
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--mac-titlebar-fullscreen-active);
|
||||
|
||||
span::before {
|
||||
background: var(--mac-titlebar-fullscreen-icon-active);
|
||||
}
|
||||
|
||||
span::after {
|
||||
background: var(--mac-titlebar-fullscreen-active);
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import * as remote from "@electron/remote"
|
||||
import * as React from "react"
|
||||
import { TitleBarButton } from "./TitleBarButton"
|
||||
import { TitleBarWrapper } from "./TitleBarWrapper"
|
||||
|
||||
interface Props {
|
||||
platform: string
|
||||
minimize (): void
|
||||
maximize (): void
|
||||
restore (): void
|
||||
close (): void
|
||||
enterFullscreen (): void
|
||||
leaveFullscreen (): void
|
||||
}
|
||||
|
||||
const win = remote.getCurrentWindow ()
|
||||
|
||||
export const TitleBar: React.FC<Props> = props => {
|
||||
const {
|
||||
platform,
|
||||
maximize,
|
||||
minimize,
|
||||
restore,
|
||||
enterFullscreen,
|
||||
leaveFullscreen,
|
||||
close,
|
||||
} = props
|
||||
|
||||
const [ isMaximized, setIsMaximized ] = React.useState (win .isMaximized ())
|
||||
const [ isFullScreen, setIsFullScreen ] = React.useState (win .isFullScreen ())
|
||||
const [ isFocused, setIsFocused ] = React.useState (win .isFocused ())
|
||||
|
||||
const handleMaximized = React.useCallback (
|
||||
() => setIsMaximized (remote.getCurrentWindow () .isMaximized ()),
|
||||
[]
|
||||
)
|
||||
|
||||
const handleFullScreen = React.useCallback (
|
||||
() => setIsFullScreen (remote.getCurrentWindow () .isFullScreen ()),
|
||||
[]
|
||||
)
|
||||
|
||||
const handleFocused = React.useCallback (
|
||||
() => setIsFocused (remote.getCurrentWindow () .isFocused ()),
|
||||
[]
|
||||
)
|
||||
|
||||
React.useEffect (
|
||||
() => {
|
||||
remote.getCurrentWindow ()
|
||||
.addListener ("maximize", handleMaximized)
|
||||
.addListener ("unmaximize", handleMaximized)
|
||||
.addListener ("enter-full-screen", handleFullScreen)
|
||||
.addListener ("leave-full-screen", handleFullScreen)
|
||||
.addListener ("blur", handleFocused)
|
||||
.addListener ("focus", handleFocused)
|
||||
|
||||
return () => {
|
||||
remote.getCurrentWindow ()
|
||||
.removeListener ("maximize", handleMaximized)
|
||||
.removeListener ("unmaximize", handleMaximized)
|
||||
.removeListener ("enter-full-screen", handleFullScreen)
|
||||
.removeListener ("leave-full-screen", handleFullScreen)
|
||||
.removeListener ("blur", handleFocused)
|
||||
.removeListener ("focus", handleFocused)
|
||||
}
|
||||
},
|
||||
[ handleMaximized, handleFullScreen, handleFocused ]
|
||||
)
|
||||
|
||||
if (platform === "darwin") {
|
||||
return (
|
||||
<TitleBarWrapper isFocused={isFocused}>
|
||||
<div className="macos-hover-area">
|
||||
<TitleBarButton icon="" onClick={close} className="close" />
|
||||
<TitleBarButton icon="" onClick={minimize} className="minimize" />
|
||||
{
|
||||
isFullScreen
|
||||
? <TitleBarButton icon="" onClick={leaveFullscreen} className="fullscreen" />
|
||||
: <TitleBarButton icon="" onClick={enterFullscreen} className="fullscreen" />
|
||||
}
|
||||
</div>
|
||||
</TitleBarWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<TitleBarWrapper isFocused={isFocused}>
|
||||
<TitleBarButton icon="" onClick={minimize} className="minimize" />
|
||||
{isMaximized
|
||||
? null
|
||||
: <TitleBarButton icon="" onClick={maximize} className="maximize" />}
|
||||
{isMaximized
|
||||
? <TitleBarButton icon="" onClick={restore} className="restore" />
|
||||
: null}
|
||||
<TitleBarButton icon="" onClick={close} className="close" />
|
||||
</TitleBarWrapper>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { Just, Maybe } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
icon: string
|
||||
onClick (): void
|
||||
}
|
||||
|
||||
export const TitleBarButton: React.FC<Props> = ({ className, icon, onClick }) => (
|
||||
<div
|
||||
className={classListMaybe (List (Just ("titlebar-btn"), Maybe (className)))}
|
||||
onClick={onClick}
|
||||
>
|
||||
<span>{icon}</span>
|
||||
</div>
|
||||
)
|
||||
@@ -1,23 +0,0 @@
|
||||
import * as React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { guardReplace, Just } from "../../../Data/Maybe"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
|
||||
interface Props {
|
||||
isFocused: boolean
|
||||
}
|
||||
|
||||
export const TitleBarWrapper: React.FC<Props> = ({ isFocused, children }) => (
|
||||
<div
|
||||
className={
|
||||
classListMaybe (List (
|
||||
Just ("titlebar"),
|
||||
guardReplace (!isFocused) ("not-focused")
|
||||
))
|
||||
}
|
||||
>
|
||||
<div className="titlebar-inner">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -1,135 +0,0 @@
|
||||
@import "Variables";
|
||||
|
||||
@import "Fonts";
|
||||
@import "BasicText";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
-ms-overflow-style: none;
|
||||
|
||||
&:not(input):not(textarea) {
|
||||
-moz-user-select: none;
|
||||
-o-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link);
|
||||
|
||||
&:hover {
|
||||
color: var(--link-hover);
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
&:first-child {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
margin: 10px 0 0;
|
||||
|
||||
&.featured {
|
||||
font-weight: 500;
|
||||
color: var(--headings-color);
|
||||
}
|
||||
}
|
||||
|
||||
.default-1-1 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
%label {
|
||||
label {
|
||||
color: #a19b8f;
|
||||
letter-spacing: 0.05em;
|
||||
display: block;
|
||||
font: 500 12px/1 Alegreya Sans;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.smallcaps {
|
||||
font: bold 13px/1 Alegreya SC;
|
||||
text-transform: uppercase;
|
||||
color: var(--headings-color);
|
||||
}
|
||||
|
||||
@import "App/Views/Universal/Aside";
|
||||
@import "App/Views/Universal/Avatar";
|
||||
@import "App/Views/Universal/AvatarChange";
|
||||
@import "App/Views/Universal/AvatarWrapper";
|
||||
@import "App/Views/Universal/BorderButton";
|
||||
@import "App/Views/Universal/Box";
|
||||
@import "App/Views/Universal/Button";
|
||||
@import "App/Views/Universal/Checkbox";
|
||||
@import "App/Views/Universal/Dialog";
|
||||
@import "App/Views/Universal/Dropdown";
|
||||
@import "App/Views/Universal/EditText";
|
||||
@import "App/Views/Universal/ErrorMessage";
|
||||
@import "App/Views/Universal/Hr";
|
||||
@import "App/Views/Universal/IconButton";
|
||||
@import "App/Views/Universal/Label";
|
||||
@import "App/Views/Universal/LabelBox";
|
||||
@import "App/Views/Universal/List";
|
||||
@import "App/Views/Universal/ListHeader";
|
||||
@import "App/Views/Universal/Loader";
|
||||
@import "App/Views/Universal/MainContent";
|
||||
@import "App/Views/Universal/NumberBox";
|
||||
@import "App/Views/Universal/Options";
|
||||
@import "App/Views/Universal/Overlay";
|
||||
@import "App/Views/Universal/Page";
|
||||
@import "App/Views/Universal/Plain";
|
||||
@import "App/Views/Universal/ProgressBar";
|
||||
@import "App/Views/Universal/RadioButton";
|
||||
@import "App/Views/Universal/RecommendedReference";
|
||||
@import "App/Views/Universal/Scroll";
|
||||
@import "App/Views/Universal/SegmentedControls";
|
||||
@import "App/Views/Universal/Slidein";
|
||||
@import "App/Views/Universal/Slider";
|
||||
@import "App/Views/Universal/TextField";
|
||||
@import "App/Views/Universal/InputButtonGroup";
|
||||
@import "App/Views/Universal/TitleBar";
|
||||
@import "App/Views/Universal/TooltipToggle";
|
||||
@import "App/Views/Universal/VerticalList";
|
||||
|
||||
@import "App/Views/App";
|
||||
@import "App/Views/Router/Router";
|
||||
@import "App/Views/About/About";
|
||||
@import "App/Views/Attributes/Attribute";
|
||||
@import "App/Views/DisAdvantages/DisAdvantages";
|
||||
@import "App/Views/Downloader/Downloader";
|
||||
@import "App/Views/Heroes/Herolist";
|
||||
@import "App/Views/Equipment/Belongings";
|
||||
@import "App/Views/InGame/Master";
|
||||
@import "App/Views/InGame/InGame";
|
||||
@import "App/Views/InGame/InGameControls";
|
||||
@import "App/Views/InGame/InGameTableCenter";
|
||||
@import "App/Views/InGame/InGameTableHealth";
|
||||
@import "App/Views/InGame/InGameTableIni";
|
||||
@import "App/Views/InGame/InGameTableLeft";
|
||||
@import "App/Views/InGame/InGameTableRight";
|
||||
@import "App/Views/InlineWiki/WikiInfo";
|
||||
@import "App/Views/NavBar/NavigationBar";
|
||||
@import "App/Views/NavBar/NavigationBarSubTabs";
|
||||
@import "App/Views/Pact/Pact";
|
||||
@import "App/Views/Pets/Pets";
|
||||
@import "App/Views/Profile/Profile";
|
||||
@import "App/Views/RCPOptionSelections/RCPOptionSelections";
|
||||
@import "App/Views/Rules/Rules";
|
||||
@import "App/Views/Sheets/CombatSheet/CombatSheet";
|
||||
@import "App/Views/Sheets/BelongingsSheet/BelongingsSheet";
|
||||
@import "App/Views/Sheets/MainSheet/MainSheet";
|
||||
@import "App/Views/Sheets/Sheets";
|
||||
@import "App/Views/Sheets/SpellsLiturgiesSheet";
|
||||
@import "App/Views/Sheets/SkillsSheet/SkillsSheet";
|
||||
@import "App/Views/Skills/Skills";
|
||||
@import "App/Views/Wiki/Wiki";
|
||||
|
||||
@import "Print";
|
||||
@@ -1,77 +0,0 @@
|
||||
:root {
|
||||
--separator-color: #7a7a7a;
|
||||
--separator-color-halftransparent: rgba(122, 122, 122, .3);
|
||||
--secondary-text-color: rgba(122, 122, 122, .5);
|
||||
--disabled-color: rgba(122, 122, 122, .3);
|
||||
--separator-color-transparent: rgba(122, 122, 122, .2);
|
||||
--selection-color: #79643c;
|
||||
--accent-color: #826a3e;
|
||||
--accent-color-intense: #5d4517;
|
||||
--background-color: #111;
|
||||
--background-color-transparent02: rgba(17, 17, 17, 0.2);
|
||||
--background-color-transparent04: rgba(17, 17, 17, 0.4);
|
||||
--background-color-transparent06: rgba(17, 17, 17, 0.6);
|
||||
--background-color-transparent08: rgba(17, 17, 17, 0.8);
|
||||
--headings-color: #f7f4ed;
|
||||
--text-color: #7f7f7f;
|
||||
--titlebar-height: 31px;
|
||||
--navigationbar-height: 64px;
|
||||
--important-bright-color: #fabe0a;
|
||||
--important-dark-color: #c89c3d;
|
||||
--common-bright-color: #0acbe6;
|
||||
--common-dark-color: #005177;
|
||||
--uncommon-bright-color: #ff2345;
|
||||
--uncommon-dark-color: #aa1b32;
|
||||
--adult-badge: #aa1b33;
|
||||
--courage-color: #aa1b32;
|
||||
--sagacity-color: #6b4497;
|
||||
--intuition-color: #06a341;
|
||||
--charisma-color: #3c3c41;
|
||||
--dexterity-color: #aea000;
|
||||
--agility-color: #005177;
|
||||
--constitution-color: #f7f4ed;
|
||||
--strength-color: #ac6000;
|
||||
--default-ease: cubic-bezier(.23, 1, .32, 1);
|
||||
--link: #0080b9;
|
||||
--link-hover: #52abd1;
|
||||
|
||||
--print-border: 0.25mm solid black;
|
||||
}
|
||||
|
||||
.theme-light {
|
||||
--selection-color: #c2ad88;
|
||||
--accent-color-intense: #b6a68a;
|
||||
--background-color: #f0f0f0;
|
||||
--background-color-transparent02: rgba(240, 240, 240, 0.2);
|
||||
--background-color-transparent04: rgba(240, 240, 240, 0.4);
|
||||
--background-color-transparent06: rgba(240, 240, 240, 0.6);
|
||||
--background-color-transparent08: rgba(240, 240, 240, 0.8);
|
||||
--headings-color: black;
|
||||
--text-color: #3c3c3c;
|
||||
--important-bright-color: #cac158;
|
||||
--important-dark-color: #cac158;
|
||||
--common-bright-color: #5398bb;
|
||||
--common-dark-color: #5398bb;
|
||||
--uncommon-bright-color: #c54747;
|
||||
--uncommon-dark-color: #c54747;
|
||||
--courage-color: #c54747;
|
||||
--sagacity-color: #a85bd4;
|
||||
--intuition-color: #339b5b;
|
||||
--charisma-color: black;
|
||||
--dexterity-color: #cac158;
|
||||
--agility-color: #5398bb;
|
||||
--constitution-color: white;
|
||||
--strength-color: #c28e46;
|
||||
// --courage-color: #d00000;
|
||||
// --sagacity-color: #8100ca;
|
||||
// --intuition-color: #00ba4a;
|
||||
// --charisma-color: black;
|
||||
// --dexterity-color: #daca00;
|
||||
// --agility-color: #007eca;
|
||||
// --constitution-color: white;
|
||||
// --strength-color: #ea8c00;
|
||||
}
|
||||
|
||||
.platform-darwin {
|
||||
--titlebar-height: 39px;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/* eslint-disable init-declarations */
|
||||
|
||||
declare module "*.png" {
|
||||
declare const url: string
|
||||
export default url
|
||||
}
|
||||
|
||||
declare module "*.ico" {
|
||||
declare const url: string
|
||||
export default url
|
||||
}
|
||||
|
||||
declare module "*.icns" {
|
||||
declare const url: string
|
||||
export default url
|
||||
}
|
||||
|
||||
declare module "*.svg" {
|
||||
declare const url: string
|
||||
export default url
|
||||
}
|
||||
|
Before Width: | Height: | Size: 275 KiB After Width: | Height: | Size: 275 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 460 B |
|
After Width: | Height: | Size: 776 B |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 772 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 265 KiB After Width: | Height: | Size: 265 KiB |
|
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 818 KiB |
|
Before Width: | Height: | Size: 689 B After Width: | Height: | Size: 689 B |
|
Before Width: | Height: | Size: 640 B After Width: | Height: | Size: 640 B |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 519 KiB After Width: | Height: | Size: 519 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |