Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e7ef05d683 | |||
| 3706a4f78e | |||
| f4cf03966c | |||
| 630ec88c7e | |||
| 8484265c2a | |||
| dbdb75a888 | |||
| 0dc6316b5b | |||
| c7d1735e4b | |||
| aa93dab7fd | |||
| 5a9ae86cf9 | |||
| 7f5f94491e | |||
| a2979650f2 | |||
| 3e2f55b9a2 | |||
| 8d02399238 | |||
| f0d46a9d73 | |||
| c3f7f4faa8 | |||
| ed97c55c4e | |||
| 8e8932cd83 | |||
| c15505062d |
@@ -9,19 +9,27 @@ assignees: ''
|
||||
|
||||
## Sources
|
||||
|
||||
> List here what is included in this part of the book to implement. E.g., for special abilities, you need to list every source of entries from the book. Example (in German):
|
||||
>
|
||||
> - S. 133–150 (Berufsgeheimnisse)
|
||||
<!-- List here what is included in this part of the book to implement. E.g., for special abilities, you need to list every source of entries from the book. Use page ranges if entries span multiple pages. Example:
|
||||
|
||||
- S. X (Section/Chapter Name)
|
||||
- [ ] S. 133 (Entry A)
|
||||
- [ ] S. 133–134 (Entry B)
|
||||
|
||||
Alternatively, provide an overview of the different sections in the book where one or more relevant entries occur. Example (in German):
|
||||
|
||||
- [ ] S. 133–150 (Berufsgeheimnisse)
|
||||
|
||||
-->
|
||||
|
||||
- [ ] S. X (Entry/Section/Chapter Name)
|
||||
|
||||
## Special Notes
|
||||
|
||||
> List here any special hints to implement the sources listed above.
|
||||
>
|
||||
> - …
|
||||
<!-- List here any special hints to implement the sources listed above. Example:
|
||||
|
||||
- All entries are already present, only add source references
|
||||
- Pay attention to the layout of entry A, there is a gap that should not be in Optolith
|
||||
|
||||
Replace the dash below this comment if there are any notes. -->
|
||||
|
||||
—
|
||||
|
||||
@@ -29,8 +37,10 @@ assignees: ''
|
||||
|
||||
## Special Implementations
|
||||
|
||||
> List here what cannot be solved only using the database. Example (in German):
|
||||
>
|
||||
> - [ ] Voraussetzungen Vorliebe I-II
|
||||
<!-- List issues that track what cannot be solved only using the database. Example:
|
||||
|
||||
- #123
|
||||
|
||||
Replace the dash below this comment if there are any notes. -->
|
||||
|
||||
—
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [1.5.2](https://github.com/elyukai/optolith-client/compare/v1.5.2-alpha.4...v1.5.2) (2025-01-02)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* throws during startup due to changed devtools identifiers ([7f5f944](https://github.com/elyukai/optolith-client/commit/7f5f94491e1432d66add1315889075fb5369f700)), closes [#1634](https://github.com/elyukai/optolith-client/issues/1634)
|
||||
|
||||
### [1.5.2-alpha.4](https://github.com/elyukai/optolith-client/compare/v1.5.2-alpha.3...v1.5.2-alpha.4) (2022-07-22)
|
||||
|
||||
|
||||
|
||||
Vendored
+1
@@ -22,6 +22,7 @@ export interface RawConfig {
|
||||
equipmentGroupVisibilityFilter: number
|
||||
sheetCheckAttributeValueVisibility?: boolean
|
||||
sheetUseParchment?: boolean
|
||||
sheetShowRules?: boolean
|
||||
sheetZoomFactor?: number
|
||||
enableActiveItemHints: boolean
|
||||
locale?: string
|
||||
|
||||
@@ -76,6 +76,9 @@
|
||||
"sheetUseParchment": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sheetShowRules": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"sheetZoomFactor": {
|
||||
"type": "number"
|
||||
},
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"appId": "com.lukasobermann.optolith",
|
||||
"productName": "Optolith",
|
||||
"directories": { "output": "dist" },
|
||||
"files": ["app/**/*", "LICENSE"],
|
||||
"npmRebuild": false,
|
||||
"mac": {
|
||||
"category": "public.app-category.role-playing-games",
|
||||
"icon": "app/icon.icns",
|
||||
"target": [
|
||||
{ "target": "dmg", "arch": ["arm64", "x64"] },
|
||||
{ "target": "zip", "arch": ["arm64", "x64"] }
|
||||
],
|
||||
"artifactName": "Optolith_${version}_${arch}.${ext}",
|
||||
"identity": null
|
||||
},
|
||||
"dmg": { "sign": false }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"appId": "com.lukasobermann.optolith",
|
||||
"productName": "Optolith",
|
||||
"directories": {
|
||||
"output": "dist"
|
||||
},
|
||||
"files": [
|
||||
"app/**/*",
|
||||
"LICENSE"
|
||||
],
|
||||
"npmRebuild": false,
|
||||
"win": {
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"icon": "app/icon.ico",
|
||||
"artifactName": "OptolithSetup_${version}.${ext}"
|
||||
},
|
||||
"nsis": {
|
||||
"perMachine": false,
|
||||
"deleteAppDataOnUninstall": false
|
||||
},
|
||||
"linux": {
|
||||
"category": "RolePlaying",
|
||||
"executableName": "Optolith",
|
||||
"icon": "app",
|
||||
"target": [
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "tar.gz",
|
||||
"arch": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"artifactName": "Optolith_${version}.${ext}"
|
||||
},
|
||||
"publish": null
|
||||
}
|
||||
Generated
+1869
-2107
File diff suppressed because it is too large
Load Diff
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "optolith",
|
||||
"productName": "Optolith",
|
||||
"version": "1.5.2-alpha.4",
|
||||
"version": "1.6.0",
|
||||
"description": "A generator for heroes for the P&P-RPG 'The Dark Eye'.",
|
||||
"author": {
|
||||
"name": "Lukas Obermann",
|
||||
@@ -14,7 +14,7 @@
|
||||
"@electron/remote": "^2.0.8",
|
||||
"adm-zip": "^0.5.1",
|
||||
"ajv": "6.12.6",
|
||||
"electron-devtools-installer": "^3.2.0",
|
||||
"electron-devtools-installer": "^3.2.1",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-updater": "^5.0.5",
|
||||
"electron-window-state": "5.0.3",
|
||||
@@ -103,4 +103,4 @@
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import { translate, translateP } from "../Utilities/I18n"
|
||||
import { pipe, pipe_ } from "../Utilities/pipe"
|
||||
import { misNumberM } from "../Utilities/typeCheckUtils"
|
||||
import { getWikiEntry } from "../Utilities/WikiUtils"
|
||||
import { WikiInfoSelector } from "../Views/InlineWiki/WikiInfo"
|
||||
import { ReduxAction, ReduxDispatch } from "./Actions"
|
||||
import { addAlert, addNotEnoughAPAlert, AlertOptions } from "./AlertActions"
|
||||
|
||||
@@ -466,6 +467,14 @@ export const switchRatingVisibility = (): SwitchDisAdvRatingVisibilityAction =>
|
||||
type: ActionTypes.SWITCH_DISADV_RATING_VISIBILITY,
|
||||
})
|
||||
|
||||
export const setRule = (selector: WikiInfoSelector, rule: string): SaveRuleAction => ({
|
||||
type: ActionTypes.SET_CUSTOM_RULE,
|
||||
payload: {
|
||||
rule,
|
||||
selector,
|
||||
},
|
||||
})
|
||||
|
||||
export interface SetActiveAdvantagesFilterTextAction {
|
||||
type: ActionTypes.SET_ADVANTAGES_FILTER_TEXT
|
||||
payload: {
|
||||
@@ -525,3 +534,11 @@ export const setInactiveDisadvantagesFilterText =
|
||||
filterText,
|
||||
},
|
||||
})
|
||||
|
||||
export interface SaveRuleAction {
|
||||
type: ActionTypes.SET_CUSTOM_RULE
|
||||
payload: {
|
||||
rule: string
|
||||
selector: WikiInfoSelector
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ export const requestConfigSave: ReduxAction<Promise<boolean>> =
|
||||
Just (UISSA.sheetCheckAttributeValueVisibility (uiSettingsState)),
|
||||
sheetUseParchment:
|
||||
Just (UISSA.sheetUseParchment (uiSettingsState)),
|
||||
sheetShowRules:
|
||||
Just (UISSA.sheetShowRules (uiSettingsState)),
|
||||
sheetZoomFactor:
|
||||
UISSA.sheetZoomFactor (uiSettingsState),
|
||||
theme: Just (UISSA.theme (uiSettingsState)),
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { SWITCH_SHEET_ATTR_VALUE_VISIBILITY, SWITCH_SHEET_USE_PARCHMENT, SET_SHEET_ZOOM_FACTOR } from "../Constants/ActionTypes"
|
||||
import {
|
||||
SWITCH_SHEET_ATTR_VALUE_VISIBILITY,
|
||||
SWITCH_SHEET_USE_PARCHMENT,
|
||||
SET_SHEET_ZOOM_FACTOR,
|
||||
SWITCH_SHEET_SHOW_RULES
|
||||
} from "../Constants/ActionTypes"
|
||||
|
||||
export interface SwitchSheetAttributeValueVisibilityAction {
|
||||
type: SWITCH_SHEET_ATTR_VALUE_VISIBILITY
|
||||
@@ -16,6 +21,13 @@ export const switchUseParchment = (): SwitchSheetUseParchmentAction => ({
|
||||
type: SWITCH_SHEET_USE_PARCHMENT,
|
||||
})
|
||||
|
||||
export interface SwitchSheetShowRules {
|
||||
type: SWITCH_SHEET_SHOW_RULES
|
||||
}
|
||||
export const switchShowRules = (): SwitchSheetShowRules => ({
|
||||
type: SWITCH_SHEET_SHOW_RULES,
|
||||
})
|
||||
|
||||
export interface SetSheetZoomFactor {
|
||||
type: SET_SHEET_ZOOM_FACTOR
|
||||
payload: {
|
||||
|
||||
@@ -321,6 +321,9 @@ export type SET_DISADV_TIER = "SET_DISADV_TIER"
|
||||
export const SWITCH_DISADV_RATING_VISIBILITY = "SWITCH_DISADV_RATING_VISIBILITY"
|
||||
export type SWITCH_DISADV_RATING_VISIBILITY = "SWITCH_DISADV_RATING_VISIBILITY"
|
||||
|
||||
export const SET_CUSTOM_RULE = "SET_CUSTOM_RULE"
|
||||
export type SET_CUSTOM_RULE = "SET_CUSTOM_RULE"
|
||||
|
||||
export const ADD_TALENT_POINT = "ADD_TALENT_POINT"
|
||||
export type ADD_TALENT_POINT = "ADD_TALENT_POINT"
|
||||
export const REMOVE_TALENT_POINT = "REMOVE_TALENT_POINT"
|
||||
@@ -615,6 +618,9 @@ export type SWITCH_SHEET_ATTR_VALUE_VISIBILITY = "SWITCH_SHEET_ATTR_VALUE_VISIBI
|
||||
export const SWITCH_SHEET_USE_PARCHMENT = "SWITCH_SHEET_USE_PARCHMENT"
|
||||
export type SWITCH_SHEET_USE_PARCHMENT = "SWITCH_SHEET_USE_PARCHMENT"
|
||||
|
||||
export const SWITCH_SHEET_SHOW_RULES = "SWITCH_SHEET_SHOW_RULES"
|
||||
export type SWITCH_SHEET_SHOW_RULES = "SWITCH_SHEET_SHOW_RULES"
|
||||
|
||||
export const SET_SHEET_ZOOM_FACTOR = "SET_SHEET_ZOOM_FACTOR"
|
||||
export type SET_SHEET_ZOOM_FACTOR = "SET_SHEET_ZOOM_FACTOR"
|
||||
|
||||
|
||||
@@ -22,7 +22,12 @@ import { getConditions, getSkillPages, getSkillsByGroup, getStates } from "../Se
|
||||
import { getAllSkills } from "../Selectors/skillsSelectors"
|
||||
import { getCantripsForSheet, getSpellsForSheet } from "../Selectors/spellsSelectors"
|
||||
import { getAvatar, getCurrentHeroName, getCurrentSex, getProfile, getPurse, getSpecialAbilities, getWikiBooks, getWikiSpecialAbilities } from "../Selectors/stateSelectors"
|
||||
import { getSheetCheckAttributeValueVisibility, getSheetUseParchment, getSheetZoomFactor } from "../Selectors/uisettingsSelectors"
|
||||
import {
|
||||
getSheetCheckAttributeValueVisibility,
|
||||
getSheetShowRules,
|
||||
getSheetUseParchment,
|
||||
getSheetZoomFactor
|
||||
} from "../Selectors/uisettingsSelectors"
|
||||
import { requestExportHeroAsRptok } from "../Utilities/MapToolExporter"
|
||||
import { pipe } from "../Utilities/pipe"
|
||||
import { mapGetToMaybeSlice, mapGetToSlice } from "../Utilities/SelectorsUtils"
|
||||
@@ -56,6 +61,7 @@ const mapStateToProps = (state: AppStateRecord, ownProps: SheetsOwnProps): Sheet
|
||||
items: getAllItems (state),
|
||||
pet: getPet (state),
|
||||
useParchment: getSheetUseParchment (state),
|
||||
showRules: getSheetShowRules (state),
|
||||
zoomFactor: getSheetZoomFactor (state),
|
||||
purse: getPurse (state),
|
||||
totalPrice: getTotalPrice (state),
|
||||
@@ -98,6 +104,9 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, ownProps: SheetsOwnProps) =
|
||||
switchUseParchment () {
|
||||
dispatch (SheetActions.switchUseParchment ())
|
||||
},
|
||||
switchShowRules () {
|
||||
dispatch (SheetActions.switchShowRules ())
|
||||
},
|
||||
setSheetZoomFactor (zoomFactor: number) {
|
||||
dispatch (SheetActions.setSheetZoomFactor (zoomFactor))
|
||||
},
|
||||
|
||||
@@ -167,6 +167,7 @@ export interface Config {
|
||||
equipmentGroupVisibilityFilter: EquipmentGroup
|
||||
sheetCheckAttributeValueVisibility: Maybe<boolean>
|
||||
sheetUseParchment: Maybe<boolean>
|
||||
sheetShowRules: Maybe<boolean>
|
||||
sheetZoomFactor: number
|
||||
enableActiveItemHints: boolean
|
||||
locale: Maybe<string>
|
||||
@@ -202,6 +203,7 @@ export const Config =
|
||||
equipmentGroupVisibilityFilter: EquipmentGroup.MeleeWeapons,
|
||||
sheetCheckAttributeValueVisibility: Just (false),
|
||||
sheetUseParchment: Just (false),
|
||||
sheetShowRules: Just (false),
|
||||
sheetZoomFactor: 100,
|
||||
enableActiveItemHints: false,
|
||||
locale: Nothing,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from "react"
|
||||
import { List } from "../../../Data/List"
|
||||
import { Maybe } from "../../../Data/Maybe"
|
||||
import { OrderedMap } from "../../../Data/OrderedMap"
|
||||
@@ -145,8 +146,8 @@ export interface HistoryPrevState {
|
||||
"@@name": "HistoryPrevState"
|
||||
}
|
||||
|
||||
export type InputTextEvent = React.ChangeEvent<HTMLInputElement>
|
||||
export type InputKeyEvent = React.KeyboardEvent<HTMLInputElement>
|
||||
export type InputTextEvent = React.ChangeEvent<HTMLInputElement> | React.KeyboardEvent<HTMLTextAreaElement>
|
||||
export type InputKeyEvent = React.KeyboardEvent<HTMLInputElement> | React.KeyboardEvent<HTMLTextAreaElement>
|
||||
|
||||
export interface SubTab {
|
||||
id: TabId
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface UISettingsState {
|
||||
enableActiveItemHints: boolean
|
||||
sheetCheckAttributeValueVisibility: boolean
|
||||
sheetUseParchment: boolean
|
||||
sheetShowRules: boolean
|
||||
sheetZoomFactor: number
|
||||
theme: Theme
|
||||
enableEditingHeroAfterCreationPhase: boolean
|
||||
@@ -61,6 +62,7 @@ export const UISettingsState =
|
||||
enableActiveItemHints: false,
|
||||
sheetCheckAttributeValueVisibility: false,
|
||||
sheetUseParchment: false,
|
||||
sheetShowRules: false,
|
||||
sheetZoomFactor: 100,
|
||||
theme: Theme.Dark,
|
||||
enableEditingHeroAfterCreationPhase: false,
|
||||
|
||||
@@ -255,6 +255,7 @@ export const L10n =
|
||||
"sheets.dialogs.rptoksaveerror.message": "",
|
||||
"sheets.showattributevalues": "",
|
||||
"sheets.useparchment": "",
|
||||
"sheets.usecustomrules": "",
|
||||
"sheets.zoomfactor": "",
|
||||
"sheets.charactersheet": "",
|
||||
"sheets.attributemodifiers.title": "",
|
||||
@@ -467,6 +468,13 @@ export const L10n =
|
||||
"sheets.chantssheet.blessedspecialabilities": "",
|
||||
"sheets.chantssheet.blessings": "",
|
||||
|
||||
"sheets.rulessheet.title": "",
|
||||
"sheets.rulessheet.header.name": "",
|
||||
"sheets.rulessheet.header.rule": "",
|
||||
"sheets.rulessheet.advantages": "",
|
||||
"sheets.rulessheet.disadvantages": "",
|
||||
"sheets.rulessheet.specialabilities": "",
|
||||
|
||||
"pacts.pactcategory": "",
|
||||
"pacts.nopact": "",
|
||||
"pacts.pactlevel": "",
|
||||
@@ -565,6 +573,12 @@ export const L10n =
|
||||
"inlinewiki.variants": "",
|
||||
"inlinewiki.insteadof": "",
|
||||
|
||||
"inlinewiki.custom.inactive": "",
|
||||
"inlinewiki.custom.norule": "",
|
||||
"inlinewiki.custom.dialog.title": "",
|
||||
"inlinewiki.custom.dialog.markdownInfo": "",
|
||||
"inlinewiki.custom.dialog.saveBtn": "",
|
||||
|
||||
"rcpselectoptions.race": "",
|
||||
"rcpselectoptions.culture": "",
|
||||
"rcpselectoptions.profession": "",
|
||||
|
||||
@@ -15,13 +15,19 @@ import { ActivatableDependentL } from "../Models/ActiveEntries/ActivatableDepend
|
||||
import { ActiveObjectL } from "../Models/ActiveEntries/ActiveObject"
|
||||
import { SkillDependentL } from "../Models/ActiveEntries/SkillDependent"
|
||||
import { HeroModelL, HeroModelRecord } from "../Models/Hero/HeroModel"
|
||||
import { activate, deactivate, setLevel } from "../Utilities/Activatable/activatableActivationUtils"
|
||||
import {
|
||||
activate,
|
||||
deactivate,
|
||||
saveRule,
|
||||
setLevel,
|
||||
} from "../Utilities/Activatable/activatableActivationUtils"
|
||||
import { addOtherSpecialAbilityDependenciesOnActivation, removeOtherSpecialAbilityDependenciesOnDeletion } from "../Utilities/Activatable/SpecialAbilityUtils"
|
||||
import { pipe, pipe_ } from "../Utilities/pipe"
|
||||
|
||||
type Action = DisAdvActions.ActivateDisAdvAction
|
||||
| DisAdvActions.DeactivateDisAdvAction
|
||||
| DisAdvActions.SetDisAdvLevelAction
|
||||
| DisAdvActions.SaveRuleAction
|
||||
| SpecialAbilitiesActions.ActivateSpecialAbilityAction
|
||||
| SpecialAbilitiesActions.DeactivateSpecialAbilityAction
|
||||
| SpecialAbilitiesActions.SetSpecialAbilityTierAction
|
||||
@@ -97,6 +103,16 @@ export const activatableReducer =
|
||||
(SpecialAbilityId.TraditionGuildMages as string))
|
||||
}
|
||||
|
||||
case ActionTypes.SET_CUSTOM_RULE: {
|
||||
return hero => saveRule (
|
||||
action.payload.rule,
|
||||
hero,
|
||||
action.payload.selector.index,
|
||||
action.payload.selector.currentId
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
return ident
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ type Action = AttributesActions.AddAttributePointAction
|
||||
| DisAdvActions.ActivateDisAdvAction
|
||||
| DisAdvActions.DeactivateDisAdvAction
|
||||
| DisAdvActions.SetDisAdvLevelAction
|
||||
| DisAdvActions.SaveRuleAction
|
||||
| SpecialAbilitiesActions.ActivateSpecialAbilityAction
|
||||
| SpecialAbilitiesActions.DeactivateSpecialAbilityAction
|
||||
| SpecialAbilitiesActions.SetSpecialAbilityTierAction
|
||||
@@ -71,6 +72,7 @@ export const dependentReducer =
|
||||
case ActionTypes.ACTIVATE_SPECIALABILITY:
|
||||
case ActionTypes.DEACTIVATE_DISADV:
|
||||
case ActionTypes.DEACTIVATE_SPECIALABILITY:
|
||||
case ActionTypes.SET_CUSTOM_RULE:
|
||||
case ActionTypes.SET_DISADV_TIER:
|
||||
case ActionTypes.SET_SPECIALABILITY_TIER:
|
||||
case ActionTypes.SET_TRAD_GUILD_MAGE_UNFAM_SPELL_ID:
|
||||
|
||||
@@ -13,7 +13,12 @@ import { ReceiveInitialDataAction } from "../Actions/InitializationActions"
|
||||
import { SetLiturgicalChantsSortOrderAction } from "../Actions/LiturgicalChantActions"
|
||||
import { SetProfessionsGroupVisibilityFilterAction, SetProfessionsSortOrderAction, SetProfessionsVisibilityFilterAction } from "../Actions/ProfessionActions"
|
||||
import { SetRacesSortOrderAction } from "../Actions/RaceActions"
|
||||
import { SwitchSheetAttributeValueVisibilityAction, SwitchSheetUseParchmentAction, SetSheetZoomFactor } from "../Actions/SheetActions"
|
||||
import {
|
||||
SwitchSheetAttributeValueVisibilityAction,
|
||||
SwitchSheetUseParchmentAction,
|
||||
SetSheetZoomFactor,
|
||||
SwitchSheetShowRules
|
||||
} from "../Actions/SheetActions"
|
||||
import { SetSkillsSortOrderAction, SwitchSkillRatingVisibilityAction } from "../Actions/SkillActions"
|
||||
import { SetSpecialAbilitiesSortOrderAction } from "../Actions/SpecialAbilitiesActions"
|
||||
import { SetSpellsSortOrderAction } from "../Actions/SpellsActions"
|
||||
@@ -47,6 +52,7 @@ type Action = ReceiveInitialDataAction
|
||||
| SetMeleeItemTemplatesCombatTechniqueFilterAction
|
||||
| SetRangedItemTemplatesCombatTechniqueFilterAction
|
||||
| SwitchEnableAnimationsAction
|
||||
| SwitchSheetShowRules
|
||||
|
||||
const CA = Config.A
|
||||
|
||||
@@ -120,6 +126,8 @@ export const uiSettingsReducer =
|
||||
fromMaybe (false) (CA.sheetCheckAttributeValueVisibility (config)),
|
||||
sheetUseParchment:
|
||||
fromMaybe (false) (CA.sheetUseParchment (config)),
|
||||
sheetShowRules:
|
||||
fromMaybe (false) (CA.sheetShowRules (config)),
|
||||
sheetZoomFactor:
|
||||
CA.sheetZoomFactor (config),
|
||||
theme: fromMaybe (Theme.Dark) (CA.theme (config)),
|
||||
@@ -140,6 +148,8 @@ export const uiSettingsReducer =
|
||||
return over (UISettingsStateL.sheetCheckAttributeValueVisibility) (not)
|
||||
case ActionTypes.SWITCH_SHEET_USE_PARCHMENT:
|
||||
return over (UISettingsStateL.sheetUseParchment) (not)
|
||||
case ActionTypes.SWITCH_SHEET_SHOW_RULES:
|
||||
return over (UISettingsStateL.sheetShowRules) (not)
|
||||
case ActionTypes.SET_SHEET_ZOOM_FACTOR:
|
||||
return set (UISettingsStateL.sheetZoomFactor) (action.payload.zoomFactor)
|
||||
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { notEquals } from "../../Data/Eq"
|
||||
import { fmap, fmapF } from "../../Data/Functor"
|
||||
import { elem, foldr, List } from "../../Data/List"
|
||||
import { bindF, catMaybes, ensure, fromMaybe, Just, liftM2, listToMaybe, maybe, Maybe, Nothing } from "../../Data/Maybe"
|
||||
import {
|
||||
bindF,
|
||||
catMaybes,
|
||||
ensure,
|
||||
fromMaybe,
|
||||
isJust, isNothing,
|
||||
Just,
|
||||
liftM2,
|
||||
listToMaybe,
|
||||
maybe,
|
||||
Maybe,
|
||||
Nothing,
|
||||
} from "../../Data/Maybe"
|
||||
import { add, multiply, negate, subtract } from "../../Data/Num"
|
||||
import { lookup, mapMaybe } from "../../Data/OrderedMap"
|
||||
import { Record } from "../../Data/Record"
|
||||
@@ -15,13 +27,18 @@ import { AttributeDependent } from "../Models/ActiveEntries/AttributeDependent"
|
||||
import { PermanentEnergyLoss } from "../Models/Hero/PermanentEnergyLoss"
|
||||
import { PermanentEnergyLossAndBoughtBack } from "../Models/Hero/PermanentEnergyLossAndBoughtBack"
|
||||
import { Rules } from "../Models/Hero/Rules"
|
||||
import { ActiveActivatable } from "../Models/View/ActiveActivatable"
|
||||
import { AttributeCombined } from "../Models/View/AttributeCombined"
|
||||
import { DerivedCharacteristicValues } from "../Models/View/DerivedCharacteristicCombined"
|
||||
import { Advantage } from "../Models/Wiki/Advantage"
|
||||
import { DerivedCharacteristic } from "../Models/Wiki/DerivedCharacteristic"
|
||||
import { Disadvantage } from "../Models/Wiki/Disadvantage"
|
||||
import { MagicalTradition } from "../Models/Wiki/MagicalTradition"
|
||||
import { Race } from "../Models/Wiki/Race"
|
||||
import { SpecialAbility } from "../Models/Wiki/SpecialAbility"
|
||||
import { StaticData } from "../Models/Wiki/WikiModel"
|
||||
import { getModifierByIsActive, getModifierByIsActives, modifyByLevelM } from "../Utilities/Activatable/activatableModifierUtils"
|
||||
import { isCustomActivatableId } from "../Utilities/Activatable/checkActivatableUtils"
|
||||
import { getActiveSelections } from "../Utilities/Activatable/selectionUtils"
|
||||
import { createMaybeSelector } from "../Utilities/createMaybeSelector"
|
||||
import { getAttributeValueWithDefault } from "../Utilities/Increasable/attributeUtils"
|
||||
@@ -426,3 +443,77 @@ export const getDerivedCharacteristics = createMaybeSelector (
|
||||
lookup ("WT") (mp),
|
||||
))
|
||||
)
|
||||
|
||||
export interface RuleDictionary {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
export interface RuleContainer {
|
||||
total: number
|
||||
advantages: RuleDictionary
|
||||
disadvantages: RuleDictionary
|
||||
specialAbilities: RuleDictionary
|
||||
}
|
||||
|
||||
export const getCustomRules = (
|
||||
advantagesActive: Maybe<List<Record<ActiveActivatable<Advantage>>>>,
|
||||
disadvantagesActive: Maybe<List<Record<ActiveActivatable<Disadvantage>>>>,
|
||||
generalsaActive: Maybe<List<Record<ActiveActivatable<SpecialAbility>>>>,
|
||||
combatSpecialAbilities: Maybe<List<Record<ActiveActivatable<SpecialAbility>>>>
|
||||
): RuleContainer => {
|
||||
const customRules: RuleContainer = {
|
||||
total: 0,
|
||||
advantages: {},
|
||||
disadvantages: { },
|
||||
specialAbilities: { },
|
||||
}
|
||||
const addToCustomRules = (
|
||||
list: List<Record<ActiveActivatable<Advantage>>>
|
||||
| List<Record<ActiveActivatable<Disadvantage>>>
|
||||
| List<Record<ActiveActivatable<SpecialAbility>>>,
|
||||
target: RuleDictionary
|
||||
) => {
|
||||
for (const activatable of list) {
|
||||
const { heroEntry } = activatable.values
|
||||
|
||||
if (!isCustomActivatableId (heroEntry.values.id)) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (const activeObject of heroEntry.values.active) {
|
||||
if (!activeObject.values.sid2) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (
|
||||
isNothing (activeObject.values.sid)
|
||||
|| isNothing (activeObject.values.sid2)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (activeObject.values.sid.value in target) {
|
||||
continue
|
||||
}
|
||||
|
||||
target[activeObject.values.sid.value.toString ()] = activeObject.values.sid2.value.toString ()
|
||||
customRules.total++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isJust(advantagesActive)) {
|
||||
addToCustomRules (advantagesActive.value, customRules.advantages)
|
||||
}
|
||||
if (isJust(disadvantagesActive)) {
|
||||
addToCustomRules (disadvantagesActive.value, customRules.disadvantages)
|
||||
}
|
||||
if (isJust(generalsaActive)) {
|
||||
addToCustomRules (generalsaActive.value, customRules.specialAbilities)
|
||||
}
|
||||
if (isJust(combatSpecialAbilities)) {
|
||||
addToCustomRules (combatSpecialAbilities.value, customRules.specialAbilities)
|
||||
}
|
||||
|
||||
return customRules
|
||||
}
|
||||
|
||||
@@ -72,6 +72,8 @@ export const getSheetCheckAttributeValueVisibility =
|
||||
|
||||
export const getSheetUseParchment =
|
||||
pipe (ASA.ui, UISA.settings, UISSA.sheetUseParchment)
|
||||
export const getSheetShowRules =
|
||||
pipe (ASA.ui, UISA.settings, UISSA.sheetShowRules)
|
||||
|
||||
export const getSheetZoomFactor =
|
||||
pipe (ASA.ui, UISA.settings, UISSA.sheetZoomFactor)
|
||||
|
||||
@@ -208,3 +208,17 @@ export const setLevel =
|
||||
return hero
|
||||
}
|
||||
}
|
||||
|
||||
export function saveRule (
|
||||
rule: string,
|
||||
hero: HeroModelRecord,
|
||||
index: number,
|
||||
itemId: string
|
||||
): HeroModelRecord {
|
||||
return adjustEntryDef (over (ActivatableDependentL.active)
|
||||
(modifyAt (index)
|
||||
(set (ActiveObjectL.sid2)
|
||||
(Just (rule)))))
|
||||
(itemId)
|
||||
(hero)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { any } from "../../../Data/List"
|
||||
import { member, Record } from "../../../Data/Record"
|
||||
import { Pair } from "../../../Data/Tuple"
|
||||
import { AdvantageId } from "../../Constants/Ids"
|
||||
import { AdvantageId, DisadvantageId, SpecialAbilityId } from "../../Constants/Ids"
|
||||
import { ActiveActivatable } from "../../Models/View/ActiveActivatable"
|
||||
import { InactiveActivatable } from "../../Models/View/InactiveActivatable"
|
||||
import { Advantage } from "../../Models/Wiki/Advantage"
|
||||
@@ -44,3 +44,13 @@ type ViewActivatable = Record<ActiveActivatable> | Record<InactiveActivatable>
|
||||
export const isActiveViewObject =
|
||||
(obj: ViewActivatable): obj is Record<ActiveActivatable> =>
|
||||
member ("index") (obj)
|
||||
|
||||
export const isCustomActivatable =
|
||||
(obj: Activatable): boolean =>
|
||||
isCustomActivatableId(obj.values.id)
|
||||
|
||||
export const isCustomActivatableId =
|
||||
(activatableId: string): boolean =>
|
||||
activatableId === AdvantageId.CustomAdvantage
|
||||
|| activatableId === DisadvantageId.CustomDisadvantage
|
||||
|| activatableId === SpecialAbilityId.CustomSpecialAbility
|
||||
|
||||
@@ -145,6 +145,8 @@ export const parseConfig = async () => {
|
||||
Maybe (validated_data.value.sheetUseParchment),
|
||||
sheetZoomFactor:
|
||||
validated_data.value.sheetZoomFactor ?? 100,
|
||||
sheetShowRules:
|
||||
Maybe(validated_data.value.sheetShowRules),
|
||||
enableActiveItemHints:
|
||||
validated_data.value.enableActiveItemHints,
|
||||
locale:
|
||||
@@ -181,6 +183,7 @@ export const writeConfig = (x: Record<Config>): string => {
|
||||
...obj,
|
||||
sheetCheckAttributeValueVisibility: maybeToUndefined (obj.sheetCheckAttributeValueVisibility),
|
||||
sheetUseParchment: maybeToUndefined (obj.sheetUseParchment),
|
||||
sheetShowRules: maybeToUndefined (obj.sheetShowRules),
|
||||
sheetZoomFactor: obj.sheetZoomFactor,
|
||||
locale: maybeToUndefined (obj.locale),
|
||||
fallbackLocale: maybeToUndefined (obj.fallbackLocale),
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ActiveActivatable, ActiveActivatableA_ } from "../../Models/View/Active
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { pipe_ } from "../../Utilities/pipe"
|
||||
import { isActiveRated } from "../../Utilities/ratingUtils"
|
||||
import { WikiInfoSelector } from "../InlineWiki/WikiInfo"
|
||||
import { ListView } from "../Universal/List"
|
||||
import { ListPlaceholder } from "../Universal/ListPlaceholder"
|
||||
import { Scroll } from "../Universal/Scroll"
|
||||
@@ -24,10 +25,10 @@ export interface ActivatableRemoveListProps {
|
||||
isRemovingEnabled: boolean
|
||||
rating?: Maybe<OrderedMap<string, EntryRating>>
|
||||
showRating?: boolean
|
||||
selectedForInfo: Maybe<string>
|
||||
selectedForInfo: Maybe<WikiInfoSelector>
|
||||
setLevel (id: string, index: number, level: number): void
|
||||
removeFromList (args: Record<ActivatableDeactivationOptions>): void
|
||||
selectForInfo (id: string): void
|
||||
selectForInfo (selector: WikiInfoSelector): void
|
||||
}
|
||||
|
||||
const AAA_ = ActiveActivatableA_
|
||||
|
||||
@@ -15,11 +15,15 @@ import { ActiveActivatable, ActiveActivatableA_ } from "../../Models/View/Active
|
||||
import { DropdownOption } from "../../Models/View/DropdownOption"
|
||||
import { SpecialAbility } from "../../Models/Wiki/SpecialAbility"
|
||||
import { StaticData, StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import {
|
||||
isCustomActivatableId
|
||||
} from "../../Utilities/Activatable/checkActivatableUtils"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
import { translate } from "../../Utilities/I18n"
|
||||
import { getLevelElementsWithMin } from "../../Utilities/levelUtils"
|
||||
import { pipe, pipe_ } from "../../Utilities/pipe"
|
||||
import { renderMaybe } from "../../Utilities/ReactUtils"
|
||||
import { WikiInfoSelector } from "../InlineWiki/WikiInfo"
|
||||
import { Dropdown } from "../Universal/Dropdown"
|
||||
import { IconButton } from "../Universal/IconButton"
|
||||
import { ListItem } from "../Universal/ListItem"
|
||||
@@ -38,10 +42,10 @@ export interface ActivatableRemoveListItemProps {
|
||||
isImportant?: boolean
|
||||
isTypical?: boolean
|
||||
isUntypical?: boolean
|
||||
selectedForInfo: Maybe<string>
|
||||
selectedForInfo: Maybe<WikiInfoSelector>
|
||||
setLevel (id: string, index: number, level: number): void
|
||||
removeFromList (args: Record<ActivatableDeactivationOptions>): void
|
||||
selectForInfo (id: string): void
|
||||
selectForInfo (selector: WikiInfoSelector): void
|
||||
}
|
||||
|
||||
const AAA = ActiveActivatable.A
|
||||
@@ -64,16 +68,17 @@ const ActivatableRemoveListItem: React.FC<ActivatableRemoveListItemProps> = prop
|
||||
} = props
|
||||
|
||||
const id = AAA_.id (item)
|
||||
const index = AAA_.index (item)
|
||||
|
||||
const handleSelectTier = React.useCallback (
|
||||
(mlevel: Maybe<number>) => {
|
||||
if (isJust (mlevel)) {
|
||||
const level = fromJust (mlevel)
|
||||
|
||||
setLevel (id, AAA_.index (item), level)
|
||||
setLevel (id, index, level)
|
||||
}
|
||||
},
|
||||
[ item, setLevel, id ]
|
||||
[ item, setLevel, id, index ]
|
||||
)
|
||||
|
||||
const handleRemove = React.useCallback (
|
||||
@@ -82,17 +87,21 @@ const ActivatableRemoveListItem: React.FC<ActivatableRemoveListItemProps> = prop
|
||||
AAA_.finalCost,
|
||||
cost => ActivatableDeactivationOptions ({
|
||||
id,
|
||||
index: AAA_.index (item),
|
||||
index,
|
||||
cost,
|
||||
})
|
||||
)),
|
||||
[ item, removeFromList, id ]
|
||||
[ item, removeFromList, id, index ]
|
||||
)
|
||||
|
||||
const handleSelectForInfo =
|
||||
React.useCallback (
|
||||
() => selectForInfo (id),
|
||||
[ selectForInfo, id ]
|
||||
() => selectForInfo ({
|
||||
currentId: id,
|
||||
index,
|
||||
item,
|
||||
}),
|
||||
[ selectForInfo, id, index, item ]
|
||||
)
|
||||
|
||||
const mlevel_element =
|
||||
@@ -138,12 +147,21 @@ const ActivatableRemoveListItem: React.FC<ActivatableRemoveListItemProps> = prop
|
||||
|
||||
const baseName = AAA_.baseName (item)
|
||||
|
||||
let active = false
|
||||
if (isJust (selectedForInfo)) {
|
||||
active = id === selectedForInfo.value.currentId
|
||||
|
||||
if (isCustomActivatableId (id)) {
|
||||
active &&= index === selectedForInfo.value.index
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<ListItem
|
||||
important={isImportant}
|
||||
recommended={isTypical}
|
||||
unrecommended={isUntypical}
|
||||
active={Maybe.elem (id) (selectedForInfo)}
|
||||
active={active}
|
||||
>
|
||||
<ListItemName
|
||||
name={
|
||||
|
||||
@@ -8,6 +8,7 @@ import { EntryRating } from "../../Models/Hero/heroTypeHelpers"
|
||||
import { ActiveActivatable } from "../../Models/View/ActiveActivatable"
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { ActivatableRemoveList } from "../Activatable/ActivatableRemoveList"
|
||||
import { WikiInfoSelector } from "../InlineWiki/WikiInfo"
|
||||
|
||||
export interface ActiveListProps {
|
||||
filterText: string
|
||||
@@ -16,10 +17,10 @@ export interface ActiveListProps {
|
||||
rating: Maybe<OrderedMap<string, EntryRating>>
|
||||
showRating: boolean
|
||||
isRemovingEnabled: boolean
|
||||
selectedForInfo: Maybe<string>
|
||||
selectedForInfo: Maybe<WikiInfoSelector>
|
||||
removeFromList (args: Record<ActivatableDeactivationOptions>): void
|
||||
setLevel (id: string, index: number, level: number): void
|
||||
selectForInfo (id: string): void
|
||||
selectForInfo (selector: WikiInfoSelector): void
|
||||
}
|
||||
|
||||
export const ActiveList: React.FC<ActiveListProps> = props => {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { AdventurePointsCategories } from "../../Models/View/AdventurePointsCate
|
||||
import { InactiveActivatable } from "../../Models/View/InactiveActivatable"
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { translate } from "../../Utilities/I18n"
|
||||
import { WikiInfoSelector } from "../InlineWiki/WikiInfo"
|
||||
import { BorderButton } from "../Universal/BorderButton"
|
||||
import { Checkbox } from "../Universal/Checkbox"
|
||||
import { ListHeader } from "../Universal/ListHeader"
|
||||
@@ -76,7 +77,7 @@ export const AdvantagesDisadvantages: React.FC<AdvantagesDisadvantagesProps> = p
|
||||
} = props
|
||||
|
||||
const [ showAddSlidein, setShowAddSlidein ] = React.useState (false)
|
||||
const [ currentId, setCurrenId ] = React.useState<Maybe<string>> (Nothing)
|
||||
const [ currentWikiSelector, setCurrentWikiSelector ] = React.useState<Maybe<WikiInfoSelector>> (Nothing)
|
||||
const [ currentSlideinId, setCurrentSlideinId ] = React.useState<Maybe<string>> (Nothing)
|
||||
|
||||
const handleShowSlidein = React.useCallback (
|
||||
@@ -94,8 +95,10 @@ export const AdvantagesDisadvantages: React.FC<AdvantagesDisadvantagesProps> = p
|
||||
)
|
||||
|
||||
const handleShowInfo = React.useCallback (
|
||||
(id: string) => setCurrenId (Just (id)),
|
||||
[ setCurrenId ]
|
||||
(selector: WikiInfoSelector) => {
|
||||
setCurrentWikiSelector (Just (selector))
|
||||
},
|
||||
[ setCurrentWikiSelector ]
|
||||
)
|
||||
|
||||
const handleShowSlideinInfo = React.useCallback (
|
||||
@@ -219,13 +222,13 @@ export const AdvantagesDisadvantages: React.FC<AdvantagesDisadvantagesProps> = p
|
||||
rating={rating}
|
||||
showRating={showRating}
|
||||
isRemovingEnabled={isRemovingEnabled}
|
||||
selectedForInfo={currentId}
|
||||
selectedForInfo={currentWikiSelector}
|
||||
removeFromList={removeFromList}
|
||||
setLevel={setLevel}
|
||||
selectForInfo={handleShowInfo}
|
||||
/>
|
||||
</MainContent>
|
||||
<WikiInfoContainer currentId={currentId} />
|
||||
<WikiInfoContainer currentSelector={currentWikiSelector} />
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import { StaticData, StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { Activatable, AllRequirements } from "../../Models/Wiki/wikiTypeHelpers"
|
||||
import { getNameCostForWiki } from "../../Utilities/Activatable/activatableActiveUtils"
|
||||
import { getName } from "../../Utilities/Activatable/activatableNameUtils"
|
||||
import { isCustomActivatable } from "../../Utilities/Activatable/checkActivatableUtils"
|
||||
import { isExtendedSpecialAbility } from "../../Utilities/Activatable/checkStyleUtils"
|
||||
import { isBlessedTradId, isMagicalTradId } from "../../Utilities/Activatable/traditionUtils"
|
||||
import { putLevelName } from "../../Utilities/AdventurePoints/activatableCostUtils"
|
||||
@@ -48,6 +49,8 @@ import { Markdown } from "../Universal/Markdown"
|
||||
import { WikiCombatTechniques } from "./Elements/WikiCombatTechniques"
|
||||
import { WikiSource } from "./Elements/WikiSource"
|
||||
import { WikiBoxTemplate } from "./WikiBoxTemplate"
|
||||
import { WikiInfoSelector } from "./WikiInfo"
|
||||
import { WikiInfoCustomRuleContainer } from "./WikiInfoCustomRuleContainer"
|
||||
import { WikiProperty } from "./WikiProperty"
|
||||
|
||||
const CIA = CategorizedPrerequisites.A
|
||||
@@ -741,10 +744,13 @@ export function PrerequisitesText (props: PrerequisitesTextProps) {
|
||||
export interface WikiActivatableInfoProps {
|
||||
staticData: StaticDataRecord
|
||||
x: Activatable
|
||||
selector: Maybe<WikiInfoSelector>
|
||||
}
|
||||
|
||||
export const WikiActivatableInfo: React.FC<WikiActivatableInfoProps> = props => {
|
||||
const { x, staticData } = props
|
||||
const { x, staticData, selector } = props
|
||||
|
||||
const isCustom = isCustomActivatable (x)
|
||||
|
||||
const specialAbilities = SDA.specialAbilities (staticData)
|
||||
|
||||
@@ -782,6 +788,24 @@ export const WikiActivatableInfo: React.FC<WikiActivatableInfoProps> = props =>
|
||||
(bind (SAA.subgr (x))
|
||||
(lookupF (SDA.combatSpecialAbilityGroups (staticData))))
|
||||
|
||||
|
||||
if (isCustom) {
|
||||
return (
|
||||
<WikiBoxTemplate className="disadv" title={header_name}>
|
||||
<WikiInfoCustomRuleContainer
|
||||
staticData={staticData}
|
||||
selector={selector}
|
||||
/>
|
||||
<PrerequisitesText
|
||||
staticData={staticData}
|
||||
x={x}
|
||||
/>
|
||||
{cost_elem}
|
||||
{source_elem}
|
||||
</WikiBoxTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
switch (SAA.gr (x)) {
|
||||
case SpecialAbilityGroup.StaffEnchantments:
|
||||
case SpecialAbilityGroup.Bannschwert:
|
||||
@@ -1343,6 +1367,24 @@ export const WikiActivatableInfo: React.FC<WikiActivatableInfoProps> = props =>
|
||||
|
||||
const header_name = `${header_full_name}${header_name_levels}${header_rcp}`
|
||||
|
||||
|
||||
if (isCustom) {
|
||||
return (
|
||||
<WikiBoxTemplate className="disadv" title={header_name}>
|
||||
<WikiInfoCustomRuleContainer
|
||||
staticData={staticData}
|
||||
selector={selector}
|
||||
/>
|
||||
<PrerequisitesText
|
||||
staticData={staticData}
|
||||
x={x}
|
||||
/>
|
||||
{cost_elem}
|
||||
{source_elem}
|
||||
</WikiBoxTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<WikiBoxTemplate className="disadv" title={header_name}>
|
||||
<Markdown source={`**${translate (staticData) ("inlinewiki.rule")}:** ${AAL.rules (x)}`} />
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
import * as React from "react"
|
||||
import { Maybe, orN } from "../../../Data/Maybe"
|
||||
import { isJust, Maybe, Nothing, orN } from "../../../Data/Maybe"
|
||||
import { Record } from "../../../Data/Record"
|
||||
import { ActiveActivatable } from "../../Models/View/ActiveActivatable"
|
||||
import { Aside } from "../Universal/Aside"
|
||||
import { ErrorMessage } from "../Universal/ErrorMessage"
|
||||
import { WikiInfoContent, WikiInfoContentStateProps } from "./WikiInfoContent"
|
||||
|
||||
export interface WikiInfoSelector {
|
||||
currentId: string
|
||||
index: number
|
||||
item: Record<ActiveActivatable>
|
||||
}
|
||||
|
||||
export interface WikiInfoOwnProps {
|
||||
currentId: Maybe<string>
|
||||
currentId?: Maybe<string>
|
||||
currentSelector?: Maybe<WikiInfoSelector>
|
||||
noWrapper?: boolean
|
||||
}
|
||||
|
||||
@@ -28,9 +37,9 @@ export class WikiInfo extends React.Component<WikiInfoProps, WikiInfoState> {
|
||||
}
|
||||
|
||||
shouldComponentUpdate (nextProps: WikiInfoProps) {
|
||||
const { currentId } = this.props
|
||||
const { currentId, currentSelector } = this.props
|
||||
|
||||
return nextProps.currentId !== currentId
|
||||
return nextProps.currentId !== currentId || nextProps.currentSelector !== currentSelector
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps: WikiInfoProps, prevState: WikiInfoState) {
|
||||
@@ -44,6 +53,7 @@ export class WikiInfo extends React.Component<WikiInfoProps, WikiInfoState> {
|
||||
render () {
|
||||
const {
|
||||
currentId,
|
||||
currentSelector,
|
||||
noWrapper,
|
||||
combinedRaces,
|
||||
combinedCultures,
|
||||
@@ -70,9 +80,29 @@ export class WikiInfo extends React.Component<WikiInfoProps, WikiInfoState> {
|
||||
return orN (noWrapper) ? currentElement : <Aside>{currentElement}</Aside>
|
||||
}
|
||||
|
||||
const id = (() => {
|
||||
if (currentId && isJust (currentId)) {
|
||||
return currentId
|
||||
}
|
||||
|
||||
if (currentSelector && isJust (currentSelector)) {
|
||||
return Maybe (currentSelector.value.currentId)
|
||||
}
|
||||
|
||||
return Nothing
|
||||
}) ()
|
||||
const selector = (() => {
|
||||
if (currentSelector) {
|
||||
return currentSelector
|
||||
}
|
||||
|
||||
return Nothing
|
||||
}) ()
|
||||
|
||||
return (
|
||||
<WikiInfoContent
|
||||
currentId={currentId}
|
||||
currentId={id}
|
||||
currentSelector={selector}
|
||||
noWrapper={noWrapper}
|
||||
combinedRaces={combinedRaces}
|
||||
combinedCultures={combinedCultures}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { WikiCantripInfo } from "./WikiCantripInfo"
|
||||
import { WikiCombatTechniqueInfo } from "./WikiCombatTechniqueInfo"
|
||||
import { WikiCultureInfo } from "./WikiCultureInfo"
|
||||
import { WikiEquipmentInfo } from "./WikiEquipmentInfo"
|
||||
import { WikiInfoSelector } from "./WikiInfo"
|
||||
import { WikiInfoContentWrapper } from "./WikiInfoContentWrapper"
|
||||
import { WikiLiturgicalChantInfo } from "./WikiLiturgicalChantInfo"
|
||||
import { WikiProfessionInfo } from "./WikiProfessionInfo"
|
||||
@@ -110,6 +111,7 @@ const getEntry =
|
||||
|
||||
export interface WikiInfoContentOwnProps {
|
||||
currentId: Maybe<string>
|
||||
currentSelector: Maybe<WikiInfoSelector>
|
||||
noWrapper?: boolean
|
||||
}
|
||||
|
||||
@@ -136,6 +138,7 @@ export type WikiInfoContentProps =
|
||||
export const WikiInfoContent: React.FC<WikiInfoContentProps> = props => {
|
||||
const {
|
||||
currentId: mid,
|
||||
currentSelector,
|
||||
noWrapper,
|
||||
languages,
|
||||
liturgicalChantExtensions,
|
||||
@@ -165,6 +168,7 @@ export const WikiInfoContent: React.FC<WikiInfoContentProps> = props => {
|
||||
return (
|
||||
<WikiInfoContentWrapper noWrapper={noWrapper}>
|
||||
<WikiActivatableInfo
|
||||
selector={currentSelector}
|
||||
staticData={staticData}
|
||||
x={x}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
import React, { useState } from "react"
|
||||
import { isNothing, Maybe } from "../../../Data/Maybe"
|
||||
import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { translate } from "../../Utilities/I18n"
|
||||
import { Dialog } from "../Universal/Dialog"
|
||||
import { Markdown } from "../Universal/Markdown"
|
||||
import { TextArea } from "../Universal/TextArea"
|
||||
import { WikiInfoSelector } from "./WikiInfo"
|
||||
|
||||
export interface WikiInfoCustomRuleStateProps {
|
||||
savedRule: string
|
||||
}
|
||||
|
||||
export interface WikiInfoCustomRuleOwnProps {
|
||||
staticData: StaticDataRecord
|
||||
selector: Maybe<WikiInfoSelector>
|
||||
}
|
||||
|
||||
export interface WikiInfoCustomRuleDispatchProps {
|
||||
saveRule (selector: WikiInfoSelector, rule: string): void
|
||||
}
|
||||
|
||||
export type WikiInfoCustomRuleProps = WikiInfoCustomRuleStateProps & WikiInfoCustomRuleDispatchProps & WikiInfoCustomRuleOwnProps
|
||||
|
||||
export const WikiInfoCustomRule: React.FC<WikiInfoCustomRuleProps> = props => {
|
||||
const { staticData, selector, saveRule, savedRule } = props
|
||||
|
||||
const [ isEditing, setIsEditing ] = useState<boolean> (false)
|
||||
const [ rule, setRule ] = useState<string> (savedRule)
|
||||
|
||||
if (isNothing (selector)) {
|
||||
return (
|
||||
<p>
|
||||
<strong>{`${translate (staticData) ("inlinewiki.rule")}: `}</strong>
|
||||
<i>{translate (staticData) ("inlinewiki.custom.inactive")}</i>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
const ruleDisplay = () => {
|
||||
if (savedRule === "") {
|
||||
return `*${translate (staticData) ("inlinewiki.custom.norule")}*`
|
||||
}
|
||||
|
||||
return savedRule
|
||||
}
|
||||
|
||||
const startEditing = () => {
|
||||
if (isEditing) {
|
||||
return
|
||||
}
|
||||
|
||||
setRule (savedRule)
|
||||
setIsEditing (true)
|
||||
}
|
||||
|
||||
const saveEdit = () => {
|
||||
if (!isEditing) {
|
||||
return
|
||||
}
|
||||
|
||||
saveRule (selector.value, rule)
|
||||
}
|
||||
const closeDialog = () => {
|
||||
if (!isEditing) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!rule) {
|
||||
setRule (savedRule)
|
||||
}
|
||||
|
||||
setIsEditing (false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<i
|
||||
className="icon"
|
||||
style={{ float: "right", cursor: "pointer", marginTop: ".6rem", userSelect: "none" }}
|
||||
onClick={startEditing}
|
||||
>
|
||||
{"\uE90c"}
|
||||
</i>
|
||||
|
||||
<p>
|
||||
<Markdown
|
||||
source={`**${translate (staticData) ("inlinewiki.rule")}:** ${ruleDisplay ()}`}
|
||||
noWrapper
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Dialog
|
||||
id="edit-custom-rule"
|
||||
close={closeDialog}
|
||||
isOpen={isEditing}
|
||||
title={translate (staticData) ("inlinewiki.custom.dialog.title")}
|
||||
buttons={[
|
||||
{
|
||||
autoWidth: true,
|
||||
label: translate (staticData) ("inlinewiki.custom.dialog.saveBtn"),
|
||||
disabled: false,
|
||||
onClick: saveEdit,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<small>{translate (staticData) ("inlinewiki.custom.dialog.markdownInfo")}</small>
|
||||
<TextArea
|
||||
value={rule}
|
||||
onChange={setRule}
|
||||
fullWidth
|
||||
autoFocus
|
||||
resize="vertical"
|
||||
/>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import { connect } from "react-redux"
|
||||
import { fmap } from "../../../Data/Functor"
|
||||
import { subscriptF } from "../../../Data/List"
|
||||
import { bind, bindF, ensure, isNothing } from "../../../Data/Maybe"
|
||||
import { lookup } from "../../../Data/OrderedMap"
|
||||
import { Record } from "../../../Data/Record"
|
||||
import { ReduxDispatch } from "../../Actions/Actions"
|
||||
import { setRule } from "../../Actions/DisAdvActions"
|
||||
import { ActivatableDependent } from "../../Models/ActiveEntries/ActivatableDependent"
|
||||
import { toActiveObjectWithId } from "../../Models/ActiveEntries/ActiveObjectWithId"
|
||||
import { AppStateRecord } from "../../Models/AppState"
|
||||
import { HeroModel } from "../../Models/Hero/HeroModel"
|
||||
import { Advantage, isAdvantage } from "../../Models/Wiki/Advantage"
|
||||
import { Disadvantage, isDisadvantage } from "../../Models/Wiki/Disadvantage"
|
||||
import { SpecialAbility } from "../../Models/Wiki/SpecialAbility"
|
||||
import { getCurrentHeroPresent, getWiki } from "../../Selectors/stateSelectors"
|
||||
import { pipe } from "../../Utilities/pipe"
|
||||
import { getWikiEntry } from "../../Utilities/WikiUtils"
|
||||
import { WikiInfoSelector } from "./WikiInfo"
|
||||
import {
|
||||
WikiInfoCustomRule, WikiInfoCustomRuleDispatchProps,
|
||||
WikiInfoCustomRuleOwnProps,
|
||||
WikiInfoCustomRuleStateProps,
|
||||
} from "./WikiInfoCustomRule"
|
||||
|
||||
|
||||
const mapStateToProps =
|
||||
(state: AppStateRecord, ownProps: WikiInfoCustomRuleOwnProps): WikiInfoCustomRuleStateProps => ({
|
||||
savedRule: ((): string => {
|
||||
if (isNothing (ownProps.selector)) {
|
||||
return ""
|
||||
}
|
||||
const selectorVal = ownProps.selector.value
|
||||
|
||||
const mhero = getCurrentHeroPresent (state)
|
||||
|
||||
if (isNothing (mhero)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
const hero = mhero.value
|
||||
const current_id = selectorVal.currentId
|
||||
const current_index = selectorVal.index
|
||||
|
||||
const mwiki_entry =
|
||||
bind (getWikiEntry (getWiki (state)) (current_id))
|
||||
(ensure ((x): x is Record<Advantage> | Record<Disadvantage> | Record<SpecialAbility> =>
|
||||
isAdvantage (x) || isDisadvantage (x) || SpecialAbility.is (x)))
|
||||
|
||||
console.log (mwiki_entry)
|
||||
|
||||
const mhero_entry =
|
||||
bind (mwiki_entry)
|
||||
(x => lookup (current_id)
|
||||
(isAdvantage (x)
|
||||
? HeroModel.AL.advantages (hero)
|
||||
: isDisadvantage (x)
|
||||
? HeroModel.AL.disadvantages (hero)
|
||||
: HeroModel.AL.specialAbilities (hero)))
|
||||
console.log (mhero_entry)
|
||||
|
||||
const mactive_entry =
|
||||
pipe (
|
||||
bindF (pipe (
|
||||
ActivatableDependent.A.active,
|
||||
subscriptF (current_index)
|
||||
)),
|
||||
fmap (toActiveObjectWithId (current_index) (current_id))
|
||||
)
|
||||
(mhero_entry)
|
||||
|
||||
if (isNothing (mactive_entry)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (isNothing (mactive_entry.value.values.sid2)) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return mactive_entry.value.values.sid2.value.toString ()
|
||||
}) (),
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch: ReduxDispatch): WikiInfoCustomRuleDispatchProps => ({
|
||||
saveRule (selector: WikiInfoSelector, rule: string) {
|
||||
dispatch (setRule (selector, rule))
|
||||
},
|
||||
})
|
||||
|
||||
const connectWikiInfo =
|
||||
connect<WikiInfoCustomRuleStateProps, WikiInfoCustomRuleDispatchProps, WikiInfoCustomRuleOwnProps, AppStateRecord> (
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)
|
||||
|
||||
export const WikiInfoCustomRuleContainer = connectWikiInfo (WikiInfoCustomRule)
|
||||
@@ -3,3 +3,17 @@
|
||||
@import "NavigationBarRight";
|
||||
@import "NavigationBarTabs";
|
||||
@import "NavigationBarWrapper";
|
||||
|
||||
.fork-badge {
|
||||
align-self: center;
|
||||
background-color: #b33636;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
line-height: 1;
|
||||
margin: 0 6px;
|
||||
padding: 4px 7px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { translate, translateP } from "../../Utilities/I18n"
|
||||
import { TabId } from "../../Utilities/LocationUtils"
|
||||
import { signNeg } from "../../Utilities/NumberUtils"
|
||||
import { pipe, pipe_ } from "../../Utilities/pipe"
|
||||
import { current_version } from "../../Selectors/envSelectors"
|
||||
import { AvatarWrapper } from "../Universal/AvatarWrapper"
|
||||
import { BorderButton } from "../Universal/BorderButton"
|
||||
import { IconButton } from "../Universal/IconButton"
|
||||
@@ -167,6 +168,9 @@ export const NavigationBar: React.FC<NavigationBarProps> = props => {
|
||||
</>
|
||||
)
|
||||
: null}
|
||||
<Text className="fork-badge">
|
||||
{`FORK ${current_version}`}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon=""
|
||||
onClick={openSettings}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#rule-sheet {
|
||||
table.rules {
|
||||
|
||||
max-width: 100%;
|
||||
white-space: break-spaces;
|
||||
|
||||
tbody {
|
||||
|
||||
tr:not(.category-display) {
|
||||
td {
|
||||
padding-top: 0.2rem;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
vertical-align: baseline;
|
||||
padding-right: .1rem;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
tr.category-display {
|
||||
td {
|
||||
height: 6mm;
|
||||
border-width: 0.75pt 0;
|
||||
font: bold 10px/1 "Alegreya SC";
|
||||
border-color: #424242;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
import { createRef, RefObject } from "react"
|
||||
import * as React from "react"
|
||||
import { List } from "../../../../Data/List"
|
||||
import { Record } from "../../../../Data/Record"
|
||||
import { AttributeCombined } from "../../../Models/View/AttributeCombined"
|
||||
import { StaticDataRecord } from "../../../Models/Wiki/WikiModel"
|
||||
import {
|
||||
RuleContainer,
|
||||
RuleDictionary,
|
||||
} from "../../../Selectors/derivedCharacteristicsSelectors"
|
||||
import { translate } from "../../../Utilities/I18n"
|
||||
import { Markdown } from "../../Universal/Markdown"
|
||||
import { Sheet } from "../Sheet"
|
||||
import { SheetWrapper } from "../SheetWrapper"
|
||||
|
||||
interface Props {
|
||||
attributes: List<Record<AttributeCombined>>
|
||||
staticData: StaticDataRecord
|
||||
useParchment: boolean
|
||||
rules: RuleContainer
|
||||
}
|
||||
|
||||
export class RulesSheet extends React.Component<Props> {
|
||||
private readonly tableRef: RefObject<HTMLTableElement>
|
||||
|
||||
private createdWrappers: HTMLDivElement[]
|
||||
|
||||
constructor (props: Props) {
|
||||
super (props)
|
||||
this.tableRef = createRef<HTMLTableElement> ()
|
||||
this.createdWrappers = []
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.clearCreatedWrappers ()
|
||||
const table = this.tableRef.current
|
||||
if (!table) {
|
||||
return
|
||||
}
|
||||
|
||||
const maxHeight = this.getMaxHeightForTableBody (table)
|
||||
|
||||
const tablebody = table.querySelector ("tbody")
|
||||
if (!tablebody) {
|
||||
return
|
||||
}
|
||||
|
||||
const height = tablebody.clientHeight
|
||||
if (height < maxHeight) {
|
||||
return
|
||||
}
|
||||
|
||||
const rows = this.getRows (tablebody)
|
||||
|
||||
this.recreateTableOnMultipleSheets (table, tablebody, rows, maxHeight)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.clearCreatedWrappers ()
|
||||
}
|
||||
|
||||
private recreateTableOnMultipleSheets (
|
||||
table: HTMLTableElement,
|
||||
tablebody: HTMLTableSectionElement,
|
||||
rows: { row: HTMLTableRowElement; height: number }[],
|
||||
maxHeight: number
|
||||
) {
|
||||
const originalWrapper = table.closest (".sheet-wrapper")
|
||||
if (!originalWrapper) {
|
||||
return
|
||||
}
|
||||
const wrapperParent = originalWrapper.parentElement
|
||||
if (!wrapperParent) {
|
||||
return
|
||||
}
|
||||
|
||||
const cloneWrapper = originalWrapper.cloneNode (true)
|
||||
|
||||
let currentHeight = 0
|
||||
let currentTableBody = tablebody
|
||||
|
||||
for (const row of rows) {
|
||||
const newHeight = currentHeight + row.height
|
||||
if (newHeight > maxHeight) {
|
||||
// @ts-ignore
|
||||
const newWrapper: HTMLDivElement = cloneWrapper.cloneNode (true)
|
||||
const newTableBody: HTMLTableSectionElement | null = newWrapper.querySelector ("table.rules tbody")
|
||||
|
||||
if (!newTableBody) {
|
||||
throw new Error ("No tbody found.")
|
||||
}
|
||||
|
||||
wrapperParent.append (newWrapper)
|
||||
this.createdWrappers.push (newWrapper)
|
||||
|
||||
currentHeight = 0
|
||||
currentTableBody = newTableBody
|
||||
}
|
||||
|
||||
currentHeight += row.height
|
||||
currentTableBody.append (row.row)
|
||||
}
|
||||
}
|
||||
|
||||
private getRows (tablebody: HTMLTableSectionElement) {
|
||||
const rows: {
|
||||
row: HTMLTableRowElement
|
||||
height: number
|
||||
}[] = []
|
||||
|
||||
for (let i = tablebody.rows.length; i >= 0; i--) {
|
||||
const row = tablebody.rows.item (i)
|
||||
if (!row) {
|
||||
continue
|
||||
}
|
||||
|
||||
rows.push ({
|
||||
row,
|
||||
height: row.clientHeight,
|
||||
})
|
||||
row.remove ()
|
||||
}
|
||||
|
||||
return rows.reverse ()
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
attributes,
|
||||
staticData,
|
||||
useParchment,
|
||||
rules,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<SheetWrapper>
|
||||
<Sheet
|
||||
id="rule-sheet"
|
||||
title={translate (staticData) ("sheets.rulessheet.title")}
|
||||
attributes={attributes}
|
||||
staticData={staticData}
|
||||
useParchment={useParchment}
|
||||
>
|
||||
<table className="rules" ref={this.tableRef}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{translate (staticData) ("sheets.rulessheet.header.name")}</th>
|
||||
<th>{translate (staticData) ("sheets.rulessheet.header.rule")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{this.displayRules ("advantages", translate (staticData) ("sheets.rulessheet.advantages"), rules.advantages)}
|
||||
{this.displayRules ("disadvantages", translate (staticData) ("sheets.rulessheet.disadvantages"), rules.disadvantages)}
|
||||
{this.displayRules ("specialAbilities", translate (staticData) ("sheets.rulessheet.specialabilities"), rules.specialAbilities)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</Sheet>
|
||||
</SheetWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
displayRules (
|
||||
ruleKey: string,
|
||||
displayName: string,
|
||||
dictionary: RuleDictionary
|
||||
) {
|
||||
if (!Object.keys (dictionary).length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const rows = []
|
||||
for (const dictionaryKey in dictionary) {
|
||||
const name = dictionaryKey
|
||||
const rule = dictionary[dictionaryKey]
|
||||
|
||||
rows.push (
|
||||
<tr key={`${ruleKey}_${dictionaryKey}`}>
|
||||
<td>{name}</td>
|
||||
<td>
|
||||
<Markdown
|
||||
source={rule}
|
||||
noWrapper
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
return [
|
||||
(
|
||||
<tr className="category-display" key={`${ruleKey}_displayName`}>
|
||||
<td colSpan={2}>{displayName}</td>
|
||||
</tr>
|
||||
),
|
||||
...rows,
|
||||
]
|
||||
}
|
||||
|
||||
private getMaxHeightForTableBody (table: HTMLTableElement): number {
|
||||
// This is a number, chosen to account for margins, etc.
|
||||
const ADDITIONAL_OFFSET = 40
|
||||
|
||||
const sheetWrapper = table.closest (".sheet")
|
||||
|
||||
if (!sheetWrapper) {
|
||||
return table.clientHeight
|
||||
}
|
||||
|
||||
const sheet = table.closest (".sheet")
|
||||
if (!sheet) {
|
||||
return table.clientHeight
|
||||
}
|
||||
const sheetPadding = parseFloat (window.getComputedStyle (sheet, null).getPropertyValue ("padding-left"))
|
||||
|
||||
const sheetHeight = sheetWrapper.clientHeight - (sheetPadding * 2)
|
||||
const header = sheetWrapper.querySelector (".sheet-header")
|
||||
if (!header) {
|
||||
return table.clientHeight
|
||||
}
|
||||
const headerHeight = header.clientHeight
|
||||
|
||||
if (!table.tHead) {
|
||||
return table.clientHeight
|
||||
}
|
||||
const tableHeaderHeight = table.tHead.clientHeight
|
||||
|
||||
const result = sheetHeight - headerHeight - tableHeaderHeight - ADDITIONAL_OFFSET
|
||||
|
||||
console.log (sheetHeight, headerHeight, tableHeaderHeight, result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private clearCreatedWrappers () {
|
||||
this.createdWrappers.forEach (elem => {
|
||||
elem.remove ()
|
||||
})
|
||||
|
||||
this.createdWrappers = []
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,12 @@ import { DerivedCharacteristicId } from "../../../../app/Database/Schema/Derived
|
||||
import { equals } from "../../../Data/Eq"
|
||||
import { fmapF } from "../../../Data/Functor"
|
||||
import { find, List } from "../../../Data/List"
|
||||
import { bindF, Just, Maybe, maybeRNull } from "../../../Data/Maybe"
|
||||
import {
|
||||
bindF,
|
||||
Just,
|
||||
Maybe,
|
||||
maybeRNull,
|
||||
} from "../../../Data/Maybe"
|
||||
import { OrderedMap } from "../../../Data/OrderedMap"
|
||||
import { Record } from "../../../Data/Record"
|
||||
import { fst, Pair, snd } from "../../../Data/Tuple"
|
||||
@@ -41,7 +46,10 @@ import { Race } from "../../Models/Wiki/Race"
|
||||
import { SpecialAbility } from "../../Models/Wiki/SpecialAbility"
|
||||
import { State } from "../../Models/Wiki/State"
|
||||
import { StaticData, StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { DCPair } from "../../Selectors/derivedCharacteristicsSelectors"
|
||||
import {
|
||||
DCPair,
|
||||
getCustomRules,
|
||||
} from "../../Selectors/derivedCharacteristicsSelectors"
|
||||
import { classListMaybe } from "../../Utilities/CSS"
|
||||
import { translate } from "../../Utilities/I18n"
|
||||
import { Maybe as NewMaybe } from "../../Utilities/Maybe"
|
||||
@@ -55,6 +63,7 @@ import { Scroll } from "../Universal/Scroll"
|
||||
import { BelongingsSheet } from "./BelongingsSheet/BelongingsSheet"
|
||||
import { CombatSheet } from "./CombatSheet/CombatSheet"
|
||||
import { CombatSheetZones } from "./CombatSheet/CombatSheetZones"
|
||||
import { RulesSheet } from "./RulesSheet/RulesSheet"
|
||||
import { LiturgicalChantsSheet } from "./LiturgicalChantsSheet/LiturgicalChantsSheet"
|
||||
import { MainSheet } from "./MainSheet/MainSheet"
|
||||
import { SkillsSheet } from "./SkillsSheet/SkillsSheet"
|
||||
@@ -85,6 +94,7 @@ export interface SheetsStateProps {
|
||||
name: Maybe<string>
|
||||
professionName: Maybe<string>
|
||||
useParchment: boolean
|
||||
showRules: boolean
|
||||
zoomFactor: number
|
||||
|
||||
// profession: Maybe<Record<Profession>>
|
||||
@@ -128,12 +138,12 @@ export interface SheetsDispatchProps {
|
||||
exportAsRptok (): void
|
||||
switchAttributeValueVisibility (): void
|
||||
switchUseParchment (): void
|
||||
switchShowRules (): void
|
||||
setSheetZoomFactor (zoomFactor: number): void
|
||||
}
|
||||
|
||||
type Props = SheetsStateProps & SheetsDispatchProps & SheetsOwnProps
|
||||
|
||||
|
||||
export const Sheets: React.FC<Props> = props => {
|
||||
const {
|
||||
derivedCharacteristics,
|
||||
@@ -199,6 +209,8 @@ export const Sheets: React.FC<Props> = props => {
|
||||
blessedTradition,
|
||||
blessings,
|
||||
liturgicalChants,
|
||||
showRules,
|
||||
switchShowRules,
|
||||
} = props
|
||||
|
||||
const maybeArcaneEnergy =
|
||||
@@ -212,6 +224,15 @@ export const Sheets: React.FC<Props> = props => {
|
||||
const nArmorZones = armorZones.map (xs => xs.length).sum ()
|
||||
const nArmors = Maybe.sum (fmapF (armors) (xs => xs.length))
|
||||
|
||||
const customRules = getCustomRules (
|
||||
advantagesActive,
|
||||
disadvantagesActive,
|
||||
generalsaActive,
|
||||
combatSpecialAbilities
|
||||
)
|
||||
const hasRules = customRules.total > 0
|
||||
const displayRulePage = hasRules && showRules
|
||||
|
||||
return (
|
||||
<Page id="sheets">
|
||||
<Options>
|
||||
@@ -247,6 +268,13 @@ export const Sheets: React.FC<Props> = props => {
|
||||
>
|
||||
{translate (staticData) ("sheets.showattributevalues")}
|
||||
</Checkbox>
|
||||
<Checkbox
|
||||
checked={showRules}
|
||||
onClick={switchShowRules}
|
||||
disabled={!hasRules}
|
||||
>
|
||||
{translate (staticData) ("sheets.usecustomrules")}
|
||||
</Checkbox>
|
||||
<Dropdown
|
||||
label={translate (staticData) ("sheets.zoomfactor")}
|
||||
value={Just (zoomFactor)}
|
||||
@@ -401,6 +429,18 @@ export const Sheets: React.FC<Props> = props => {
|
||||
/>
|
||||
))
|
||||
)}
|
||||
{
|
||||
displayRulePage
|
||||
? (
|
||||
<RulesSheet
|
||||
attributes={attributes}
|
||||
staticData={staticData}
|
||||
useParchment={useParchment}
|
||||
rules={customRules}
|
||||
/>
|
||||
)
|
||||
: null
|
||||
}
|
||||
</Scroll>
|
||||
</Page>
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ import { StaticDataRecord } from "../../Models/Wiki/WikiModel"
|
||||
import { translate } from "../../Utilities/I18n"
|
||||
import { ActivatableAddList } from "../Activatable/ActivatableAddList"
|
||||
import { ActivatableRemoveList } from "../Activatable/ActivatableRemoveList"
|
||||
import { WikiInfoSelector } from "../InlineWiki/WikiInfo"
|
||||
import { BorderButton } from "../Universal/BorderButton"
|
||||
import { Checkbox } from "../Universal/Checkbox"
|
||||
import { ListHeader } from "../Universal/ListHeader"
|
||||
@@ -76,7 +77,7 @@ export const SpecialAbilities: React.FC<Props> = props => {
|
||||
} = props
|
||||
|
||||
const [ isSlideinOpen, setIsSlideinOpen ] = React.useState (false)
|
||||
const [ currentId, setCurrentId ] = React.useState<Maybe<string>> (Nothing)
|
||||
const [ currentWikiSelector, setCurrentWikiSelector ] = React.useState<Maybe<WikiInfoSelector>> (Nothing)
|
||||
const [ currentSlideinId, setCurrentSlideinId ] = React.useState<Maybe<string>> (Nothing)
|
||||
|
||||
const handleShowSlidein = React.useCallback (
|
||||
@@ -91,10 +92,11 @@ export const SpecialAbilities: React.FC<Props> = props => {
|
||||
},
|
||||
[ setIsSlideinOpen, setInactiveFilterText ]
|
||||
)
|
||||
|
||||
const handleInfo = React.useCallback (
|
||||
(id: string) => setCurrentId (Just (id)),
|
||||
[ setCurrentId ]
|
||||
(selector: WikiInfoSelector) => {
|
||||
setCurrentWikiSelector (Just (selector))
|
||||
},
|
||||
[ setCurrentWikiSelector ]
|
||||
)
|
||||
|
||||
const handleSlideinInfo = React.useCallback (
|
||||
@@ -195,10 +197,10 @@ export const SpecialAbilities: React.FC<Props> = props => {
|
||||
removeFromList={removeFromList}
|
||||
setLevel={setLevel}
|
||||
selectForInfo={handleInfo}
|
||||
selectedForInfo={currentId}
|
||||
selectedForInfo={currentWikiSelector}
|
||||
/>
|
||||
</MainContent>
|
||||
<WikiInfoContainer currentId={currentId} />
|
||||
<WikiInfoContainer currentSelector={currentWikiSelector} />
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -20,3 +20,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
.icon {
|
||||
font: 20px/2pt TDE Heroes;
|
||||
font-size: 2rem;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import * as React from "react"
|
||||
import { Either } from "../../../Data/Either"
|
||||
import { Maybe, orN } from "../../../Data/Maybe"
|
||||
import { InputKeyEvent } from "../../Models/Hero/heroTypeHelpers"
|
||||
import { TextFieldContainer } from "./TextFieldContainer"
|
||||
|
||||
export interface TextAreaProps {
|
||||
autoFocus?: boolean | Maybe<boolean>
|
||||
className?: string
|
||||
countCurrent?: number
|
||||
countMax?: number
|
||||
disabled?: boolean
|
||||
error?: Maybe<string> | Either<string, any>
|
||||
fullWidth?: boolean
|
||||
hint?: Maybe<string> | string
|
||||
label?: Maybe<string> | string
|
||||
type?: string
|
||||
value?: string
|
||||
valid?: boolean
|
||||
resize?: "both"|"vertical"|"horizontal"
|
||||
initialHeight?: string|number
|
||||
onChange (newText: string): void
|
||||
onKeyDown? (event: InputKeyEvent): void
|
||||
onKeyUp? (event: InputKeyEvent): void
|
||||
}
|
||||
|
||||
export const TextArea: React.FC<TextAreaProps> = props => {
|
||||
const {
|
||||
autoFocus,
|
||||
className,
|
||||
countCurrent,
|
||||
countMax,
|
||||
disabled,
|
||||
error,
|
||||
fullWidth,
|
||||
label,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onKeyUp,
|
||||
valid,
|
||||
value = "",
|
||||
resize = "both",
|
||||
initialHeight = "150px",
|
||||
hint,
|
||||
} = props
|
||||
|
||||
const inputRef = React.useRef<HTMLTextAreaElement | null> (null)
|
||||
|
||||
React.useEffect (
|
||||
() => {
|
||||
if (Maybe.elem (true) (Maybe.normalize (autoFocus)) && inputRef.current !== null) {
|
||||
inputRef.current.focus ()
|
||||
}
|
||||
},
|
||||
[ autoFocus ]
|
||||
)
|
||||
|
||||
const handleChange =
|
||||
React.useCallback (
|
||||
(e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
if (!orN (disabled)) {
|
||||
onChange (e.target.value)
|
||||
}
|
||||
},
|
||||
[ disabled, onChange ]
|
||||
)
|
||||
|
||||
return (
|
||||
<TextFieldContainer
|
||||
className={className}
|
||||
countCurrent={countCurrent}
|
||||
countMax={countMax}
|
||||
disabled={disabled}
|
||||
error={error}
|
||||
fullWidth={fullWidth}
|
||||
hint={hint}
|
||||
isFieldEmpty={value.length === 0}
|
||||
label={label}
|
||||
valid={valid}
|
||||
>
|
||||
<textarea
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onKeyPress={orN (disabled) ? undefined : onKeyDown}
|
||||
onKeyUp={orN (disabled) ? undefined : onKeyUp}
|
||||
readOnly={disabled}
|
||||
ref={inputRef}
|
||||
style={{ height: initialHeight, resize }}
|
||||
|
||||
/>
|
||||
</TextFieldContainer>
|
||||
)
|
||||
}
|
||||
@@ -30,10 +30,10 @@
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
border: 1px solid var(--accent-color);
|
||||
padding: 0 11px;
|
||||
padding: 5px 11px;
|
||||
margin: 0;
|
||||
color: var(--headings-color);
|
||||
font: 500 13px/30px Alegreya Sans;
|
||||
font: 500 13px/20px Alegreya Sans;
|
||||
display: block;
|
||||
outline: 0 none;
|
||||
background: none;
|
||||
@@ -79,28 +79,4 @@
|
||||
color: var(--uncommon-bright-color);
|
||||
}
|
||||
}
|
||||
|
||||
// hr {
|
||||
// width: 100%;
|
||||
// height: 0px;
|
||||
// border: 0 none;
|
||||
// margin: 0;
|
||||
//
|
||||
// &.default {
|
||||
// border-bottom: 1px solid #182424;
|
||||
// }
|
||||
//
|
||||
// &.accent {
|
||||
// border-bottom: 2px solid $highlight;
|
||||
// transform: scaleX(0);
|
||||
// margin-top: -2px;
|
||||
// @include defaultEasing (all);
|
||||
// }
|
||||
// }
|
||||
|
||||
// &.focused {
|
||||
// hr.accent {
|
||||
// transform: scaleX(1);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -44,6 +44,12 @@ p {
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.hide {
|
||||
display: none !important;
|
||||
}
|
||||
.d-block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
%label {
|
||||
label {
|
||||
@@ -126,6 +132,7 @@ p {
|
||||
@import "App/Views/Sheets/CombatSheet/CombatSheet";
|
||||
@import "App/Views/Sheets/BelongingsSheet/BelongingsSheet";
|
||||
@import "App/Views/Sheets/MainSheet/MainSheet";
|
||||
@import "App/Views/Sheets/RulesSheet/RulesSheet";
|
||||
@import "App/Views/Sheets/Sheets";
|
||||
@import "App/Views/Sheets/SpellsLiturgiesSheet";
|
||||
@import "App/Views/Sheets/SkillsSheet/SkillsSheet";
|
||||
|
||||
+20
-9
@@ -3,7 +3,7 @@ import { app, BrowserWindow, ipcMain, shell } from "electron"
|
||||
import * as log from "electron-log"
|
||||
import { autoUpdater, CancellationToken, UpdateInfo } from "electron-updater"
|
||||
import windowStateKeeper from "electron-window-state"
|
||||
import { promises } from "fs"
|
||||
import { existsSync, promises } from "fs"
|
||||
import * as path from "path"
|
||||
import { prerelease } from "semver"
|
||||
import * as url from "url"
|
||||
@@ -14,7 +14,12 @@ remote.initialize ()
|
||||
|
||||
app.setAppUserModelId ("lukasobermann.optolith")
|
||||
|
||||
const isUpdaterEnabled = autoUpdater.isUpdaterActive ()
|
||||
// Ohne app-update.yml (lokale Test-Builds, unsignierte macOS-Builds) schlägt
|
||||
// checkForUpdates immer fehl und zeigt beim Start einen Fehlerdialog —
|
||||
// isUpdaterActive() prüft nur isPackaged, nicht ob eine Update-Konfig existiert.
|
||||
const hasUpdateConfig = existsSync (path.join (process.resourcesPath, "app-update.yml"))
|
||||
|
||||
const isUpdaterEnabled = hasUpdateConfig && autoUpdater.isUpdaterActive ()
|
||||
|
||||
ipcMain.on (IPCChannels.IsUpdaterEnabled, event => {
|
||||
event.returnValue = isUpdaterEnabled
|
||||
@@ -55,7 +60,7 @@ const createWindow = async () => {
|
||||
icon: path.join (app.getAppPath (), "app", "icon.png"),
|
||||
frame: false,
|
||||
center: true,
|
||||
title: "Optolith",
|
||||
title: "Optolith Fork",
|
||||
acceptFirstMouse: true,
|
||||
backgroundColor: "#111111",
|
||||
show: false,
|
||||
@@ -182,14 +187,20 @@ const main = async () => {
|
||||
|
||||
console.log ("main: Install extensions ...")
|
||||
|
||||
const installExtension = require ("electron-devtools-installer")
|
||||
|
||||
const installedExtensions = await installExtension.default ([
|
||||
installExtension.REACT_DEVELOPER_TOOLS,
|
||||
installExtension.REDUX_DEVTOOLS,
|
||||
])
|
||||
try {
|
||||
const installExtension = require ("electron-devtools-installer")
|
||||
|
||||
console.log (`main: Installed extensions: ${installedExtensions}`)
|
||||
const installedExtensions = await installExtension.default ([
|
||||
installExtension.REACT_DEVELOPER_TOOLS,
|
||||
installExtension.REDUX_DEVTOOLS,
|
||||
])
|
||||
|
||||
console.log (`main: Installed extensions: ${installedExtensions}`)
|
||||
}
|
||||
catch (error) {
|
||||
console.error ("main: Installing extensions failed! Skipping extensions...")
|
||||
}
|
||||
|
||||
console.log ("main: Create Window ...")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user