merge: PR #1613 custom entries (Neintonine) — homebrew-eintraege

Upstream: https://github.com/elyukai/optolith-client/pull/1613
Basis develop-V1, mergeable. Fuegt eigene Sonderregeln/Eintraege hinzu.
Ref: Alex-Wunsch 'man kann nichts selbst ergaenzen'.
This commit is contained in:
2026-07-16 17:57:33 +02:00
36 changed files with 997 additions and 67 deletions
+1
View File
@@ -22,6 +22,7 @@ export interface RawConfig {
equipmentGroupVisibilityFilter: number
sheetCheckAttributeValueVisibility?: boolean
sheetUseParchment?: boolean
sheetShowRules?: boolean
sheetZoomFactor?: number
enableActiveItemHints: boolean
locale?: string
+3
View File
@@ -76,6 +76,9 @@
"sheetUseParchment": {
"type": "boolean"
},
"sheetShowRules": {
"type": "boolean"
},
"sheetZoomFactor": {
"type": "number"
},
+17
View File
@@ -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
}
}
+2
View File
@@ -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)),
+13 -1
View File
@@ -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: {
+6
View File
@@ -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"
+10 -1
View File
@@ -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))
},
+2
View File
@@ -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,
+3 -2
View File
@@ -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
+2
View File
@@ -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,
+14
View File
@@ -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": "",
+17 -1
View File
@@ -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
}
+2
View File
@@ -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:
+11 -1
View File
@@ -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
}
+2
View File
@@ -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
+3
View File
@@ -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={
+3 -2
View File
@@ -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)}`} />
+35 -5
View File
@@ -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)
@@ -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 = []
}
}
+43 -3
View File
@@ -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>
)
}
+4
View File
@@ -20,3 +20,7 @@
}
}
}
.icon {
font: 20px/2pt TDE Heroes;
font-size: 2rem;
}
+93
View File
@@ -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>
)
}
+2 -26
View File
@@ -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);
// }
// }
}
+7
View File
@@ -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";