Work on column-based print layout

This commit is contained in:
Stefan Zermatten
2022-11-07 00:07:42 +02:00
parent 5d57a74667
commit c436309ba8
7 changed files with 1167 additions and 0 deletions

View File

@@ -0,0 +1,124 @@
<template>
<div class="character-sheet-printed fill-height">
<v-fade-transition mode="out-in">
<div
v-if="!$subReady.singleCharacter"
key="character-loading"
class="fill-height layout justify-center align-center"
>
<v-progress-circular
indeterminate
color="primary"
size="64"
/>
</div>
<div v-else-if="!creature">
<v-layout
column
align-center
justify-center
>
<h2 style="margin: 48px 28px 16px">
Character not found
</h2>
<h3>
Either this character does not exist, or you don't have permission
to view it.
</h3>
</v-layout>
</div>
<v-theme-provider
v-else
light
>
<printed-stats :creature-id="creatureId" />
<printed-features :creature-id="creatureId" />
<printed-inventory :creature-id="creatureId" />
<printed-spells
v-if="!creature.settings.hideSpellsTab"
:creature-id="creatureId"
/>
<printed-character :creature-id="creatureId" />
</v-theme-provider>
</v-fade-transition>
</div>
</template>
<script lang="js">
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import PrintedStats from '/imports/ui/creature/character/printedCharacterSheet/PrintedStats.vue';
import PrintedFeatures from '/imports/ui/creature/character/printedCharacterSheet/PrintedFeatures.vue';
import PrintedInventory from '/imports/ui/creature/character/printedCharacterSheet/PrintedInventory.vue';
import PrintedSpells from '/imports/ui/creature/character/printedCharacterSheet/PrintedSpells.vue';
import PrintedCharacter from '/imports/ui/creature/character/printedCharacterSheet/PrintedCharacter.vue';
import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js';
export default {
components: {
PrintedStats,
PrintedFeatures,
PrintedInventory,
PrintedSpells,
PrintedCharacter,
},
computed: {
creatureId() {
return this.$route.params.id
}
},
reactiveProvide: {
name: 'context',
include: ['creatureId', 'editPermission'],
},
watch: {
'creature.name'(value) {
this.$store.commit('setPageTitle', value ? ('Print ' + value) : 'Print Character Sheet');
},
},
mounted() {
this.$store.commit('setPageTitle',
(this.creature && this.creature.name) ?
('Print ' + this.creature.name) :
'Print Character Sheet'
);
this.nameObserver = Creatures.find({
creatureId: this.creatureId,
}, {
fields: { name: 1 },
}).observe({
added: ({ name }) =>
this.$store.commit('setPageTitle', name ? ('Print ' + name) : 'Print Character Sheet'),
changed: ({ name }) =>
this.$store.commit('setPageTitle', name ? ('Print ' + name) : 'Print Character Sheet'),
});
},
beforeDestroy() {
this.nameObserver.stop();
},
meteor: {
$subscribe: {
'singleCharacter'() {
return [this.creatureId];
},
},
creature() {
return Creatures.findOne(this.creatureId);
},
editPermission() {
try {
assertEditPermission(this.creature, Meteor.userId());
return true;
} catch (e) {
return false;
}
},
},
}
</script>
<style>
.character-sheet-printed {
background: white;
color: black;
}
</style>

View File

@@ -0,0 +1,58 @@
<template>
<div class="build-tab">
<column-layout wide-columns>
<div>
<creature-summary :creature="creature" />
</div>
<div
v-for="note in notes"
:key="note._id"
>
<note-card
:model="note"
/>
</div>
</column-layout>
</div>
</template>
<script lang="js">
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import NoteCard from '/imports/ui/properties/components/persona/NoteCard.vue';
import CreatureSummary from '/imports/ui/creature/character/CreatureSummary.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
export default {
components: {
ColumnLayout,
CreatureSummary,
NoteCard,
},
props: {
creatureId: {
type: String,
required: true,
},
},
meteor: {
notes(){
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'note',
removed: {$ne: true},
inactive: {$ne: true},
}, {
sort: {order: 1},
});
},
creature(){
return Creatures.findOne(this.creatureId);
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,60 @@
<template lang="html">
<div class="features">
<column-layout wide-columns>
<div
v-for="feature in features"
:key="feature._id"
>
<feature-card
:model="feature"
:data-id="feature._id"
@click="featureClicked(feature)"
/>
</div>
</column-layout>
</div>
</template>
<script lang="js">
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import FeatureCard from '/imports/ui/properties/components/features/FeatureCard.vue';
export default {
components: {
ColumnLayout,
FeatureCard,
},
props: {
creatureId: {
type: String,
required: true,
},
},
meteor: {
features() {
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'feature',
removed: { $ne: true },
inactive: { $ne: true },
}, {
sort: { order: 1 }
});
},
},
methods: {
featureClicked({ _id }) {
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `${_id}`,
data: { _id },
});
},
},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,233 @@
<template lang="html">
<div class="inventory">
<column-layout wide-columns>
<div>
<v-card>
<v-list>
<v-list-item>
<v-list-item-avatar>
<v-icon>$vuetify.icons.injustice</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>
Weight Carried
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-list-item-title>
{{ weightCarried }} lb
</v-list-item-title>
</v-list-item-action>
</v-list-item>
<v-list-item>
<v-list-item-avatar>
<v-icon>$vuetify.icons.cash</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>
Net worth
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-list-item-title>
<coin-value :value="variables && variables.valueTotal && variables.valueTotal.value|| 0" />
</v-list-item-title>
</v-list-item-action>
</v-list-item>
<v-list-item v-if="variables && variables.itemsAttuned && variables.itemsAttuned.value">
<v-list-item-avatar>
<v-icon>$vuetify.icons.spell</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>
Items attuned
</v-list-item-title>
</v-list-item-content>
<v-list-item-action>
<v-list-item-title>
{{ variables.itemsAttuned.value }}
</v-list-item-title>
</v-list-item-action>
</v-list-item>
</v-list>
</v-card>
</div>
<div>
<toolbar-card transparent-toolbar>
<v-toolbar-title slot="toolbar">
Equipped
</v-toolbar-title>
<v-card-text class="px-0">
<item-list
equipment
:items="equippedItems"
:parent-ref="equipmentParentRef"
/>
</v-card-text>
</toolbar-card>
</div>
<div>
<toolbar-card transparent-toolbar>
<v-toolbar-title slot="toolbar">
Carried
</v-toolbar-title>
<v-card-text class="px-0">
<item-list
:items="carriedItems"
:parent-ref="carriedParentRef"
/>
</v-card-text>
</toolbar-card>
</div>
<div
v-for="container in containersWithoutAncestorContainers"
:key="container._id"
>
<container-card :model="container" />
</div>
</column-layout>
</div>
</template>
<script lang="js">
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import ContainerCard from '/imports/ui/properties/components/inventory/ContainerCard.vue';
import ToolbarCard from '/imports/ui/components/ToolbarCard.vue';
import ItemList from '/imports/ui/properties/components/inventory/ItemList.vue';
import getParentRefByTag from '/imports/api/creature/creatureProperties/methods/getParentRefByTag.js';
import BUILT_IN_TAGS from '/imports/constants/BUILT_IN_TAGS.js';
import CoinValue from '/imports/ui/components/CoinValue.vue';
import stripFloatingPointOddities from '/imports/api/engine/computation/utility/stripFloatingPointOddities.js';
import CreatureVariables from '../../../../api/creature/creatures/CreatureVariables';
export default {
components: {
ColumnLayout,
ContainerCard,
ToolbarCard,
ItemList,
CoinValue,
},
props: {
creatureId: {
type: String,
required: true,
},
},
data() {
return {
organize: false,
}
},
meteor: {
containers() {
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'container',
removed: { $ne: true },
inactive: { $ne: true },
}, {
sort: { order: 1 },
});
},
creature() {
return Creatures.findOne(this.creatureId, {
fields: {
color: 1,
variables: 1,
}
});
},
variables() {
return CreatureVariables.findOne({ _creatureId: this.creatureId }) || {};
},
containersWithoutAncestorContainers() {
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.containerIds
},
type: 'container',
removed: { $ne: true },
inactive: { $ne: true },
}, {
sort: { order: 1 },
});
},
carriedItems() {
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.containerIds
},
type: 'item',
equipped: { $ne: true },
removed: { $ne: true },
deactivatedByAncestor: { $ne: true },
}, {
sort: { order: 1 },
});
},
equippedItems() {
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
},
type: 'item',
equipped: true,
removed: { $ne: true },
inactive: { $ne: true },
}, {
sort: { order: 1 },
});
},
equipmentParentRef() {
return getParentRefByTag(
this.creatureId, BUILT_IN_TAGS.equipment
) || getParentRefByTag(
this.creatureId, BUILT_IN_TAGS.inventory
) || {
id: this.creatureId,
collection: 'creatures'
};
},
carriedParentRef() {
return getParentRefByTag(
this.creatureId, BUILT_IN_TAGS.carried
) || getParentRefByTag(
this.creatureId, BUILT_IN_TAGS.inventory
) || {
id: this.creatureId,
collection: 'creatures'
};
},
},
computed: {
containerIds() {
return this.containers.map(container => container._id);
},
weightCarried() {
return stripFloatingPointOddities(
this.variables &&
this.variables.weightCarried &&
this.variables.weightCarried.value || 0
);
},
},
methods: {
clickProperty(_id) {
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `tree-node-${_id}`,
data: { _id },
});
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,109 @@
<template lang="html">
<div class="spells">
<column-layout wide-columns>
<div v-if="spellsWithoutList.length">
<v-card>
<spell-list
:spells="spellsWithoutList"
:parent-ref="{id: creatureId, collection: 'creatures'}"
/>
</v-card>
</div>
<div
v-for="spellList in spellListsWithoutAncestorSpellLists"
:key="spellList._id"
>
<spellList-card
:model="spellList"
:organize="organize"
/>
</div>
</column-layout>
</div>
</template>
<script lang="js">
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import SpellListCard from '/imports/ui/properties/components/spells/SpellListCard.vue';
import SpellList from '/imports/ui/properties/components/spells/SpellList.vue';
export default {
components: {
ColumnLayout,
SpellList,
SpellListCard,
},
props: {
creatureId: {
type: String,
required: true,
}
},
data() {
return {
organize: false,
}
},
meteor: {
spellLists() {
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'spellList',
removed: { $ne: true },
inactive: { $ne: true },
}, {
sort: { order: 1 }
});
},
spellsWithoutList() {
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.spellListIds,
},
type: 'spell',
removed: { $ne: true },
deactivatedByAncestor: { $ne: true },
deactivatedByToggle: { $ne: true },
}, {
sort: {
level: 1,
order: 1,
}
});
},
spellListsWithoutAncestorSpellLists() {
return CreatureProperties.find({
'ancestors.id': {
$eq: this.creatureId,
$nin: this.spellListIds,
},
type: 'spellList',
removed: { $ne: true },
inactive: { $ne: true },
}, {
sort: { order: 1 }
});
},
},
computed: {
spellListIds() {
return this.spellLists.map(spellList => spellList._id);
},
},
methods: {
clickProperty(_id) {
this.$store.commit('pushDialogStack', {
component: 'creature-property-dialog',
elementId: `spell-list-tile-${_id}`,
data: { _id },
});
},
},
}
</script>
<style lang="css" scoped>
</style>

View File

@@ -0,0 +1,572 @@
<template lang="html">
<div class="stats-tab ma-2">
<health-bar-card-container :creature-id="creatureId" />
<column-layout>
<div
v-if="abilities.length"
class="ability-scores"
>
<div class="layout flex column">
<div
v-for="ability in abilities"
:key="ability._id"
class="ability"
>
<div class="score">
<div class="double-border top big-number">
<template v-if="creature.settings.swapScoresAndMods">
{{ ability.total }}
</template>
<template v-else>
{{ numberToSignedString(ability.modifier) }}
</template>
</div>
<div class="bottom">
<template v-if="creature.settings.swapScoresAndMods">
{{ numberToSignedString(ability.modifier) }}
</template>
<template v-else>
{{ ability.total }}
</template>
</div>
</div>
<div class="double-border name label">
{{ ability.name }}
</div>
</div>
</div>
</div>
<div
v-for="toggle in toggles"
:key="toggle._id"
class="number-label"
>
<div class="box double-border" />
<div class="label double-border">
{{ toggle.name }}
</div>
</div>
<div
v-for="stat in stats"
:key="stat._id"
class="number-label"
:class="stat.variableName == 'armor' && 'shield-number-label'"
>
<div
:class="stat.variableName == 'armor' ? 'shield-border' : 'octogon-border'"
class="number big-number"
>
{{ stat.value }}
</div>
<div class="label double-border">
{{ stat.name }}
</div>
</div>
<div
v-for="modifier in modifiers"
:key="modifier._id"
class="number-label"
>
<div class="number octogon-border big-number">
{{ numberToSignedString(modifier.value) }}
</div>
<div class="label double-border">
{{ modifier.name }}
</div>
</div>
<div
v-for="check in checks"
:key="check._id"
class="number-label"
>
<div class="number octogon-border big-number">
{{ numberToSignedString(check.value) }}
</div>
<div class="label double-border">
{{ check.name }}
</div>
</div>
<div
v-if="hitDice.length"
class="hit-dice m-2"
>
<div class="double-border">
<div>
<span class="label">
Total:
</span>
<span
v-for="hitDie in hitDice"
:key="hitDie._id"
style="margin-right: 4px;"
>
{{ hitDie.total }}{{ hitDie.hitDiceSize }}
</span>
</div>
<div style="height: 80px;" />
<div
style="text-align: center;"
class="label"
>
Hit Dice
</div>
</div>
</div>
<div
v-for="resource in resources"
:key="resource._id"
class="resource"
>
<div>{{ resource.total }}</div>
<div>{{ resource.name }}</div>
</div>
<damage-multiplier-card
v-if="multipliers && multipliers.length"
:multipliers="multipliers"
/>
<div
v-if="spellSlots && spellSlots.length"
>
<div>Spell Slots</div>
<div
v-for="spellSlot in spellSlots"
:key="spellSlot._id"
>
<div>
{{ spellSlot.name }}
</div>
<div
v-if="spellSlot.total > 6"
>
{{ spellSlot.total }}
</div>
<div
v-else
>
<v-icon
v-for="i in spellSlot.total"
:key="i"
>
mdi-radiobox-blank
</v-icon>
</div>
</div>
</div>
<div
v-if="savingThrows.length"
class="saving-throws"
>
<div>
<v-list>
<v-subheader>Saving Throws</v-subheader>
<skill-list-tile
v-for="save in savingThrows"
:key="save._id"
:model="save"
:data-id="save._id"
/>
</v-list>
</div>
</div>
<div
v-if="skills.length"
class="skills"
>
<div>
<v-list>
<v-subheader>Skills</v-subheader>
<skill-list-tile
v-for="skill in skills"
:key="skill._id"
:model="skill"
:data-id="skill._id"
/>
</v-list>
</div>
</div>
<div
v-for="action in actions"
:key="action._id"
class="action"
>
<action-card
:model="action"
:data-id="action._id"
/>
</div>
<div
v-if="weapons && weapons.length"
class="weapon-proficiencies"
>
<v-card>
<v-list>
<v-subheader>
Weapons
</v-subheader>
<skill-list-tile
v-for="weapon in weapons"
:key="weapon._id"
hide-modifier
:model="weapon"
:data-id="weapon._id"
/>
</v-list>
</v-card>
</div>
<div
v-if="armors && armors.length"
class="armor-proficiencies"
>
<v-card>
<v-list>
<v-subheader>
Armor
</v-subheader>
<skill-list-tile
v-for="armor in armors"
:key="armor._id"
hide-modifier
:model="armor"
:data-id="armor._id"
/>
</v-list>
</v-card>
</div>
<div
v-if="tools && tools.length"
class="tool-proficiencies"
>
<v-card>
<v-list>
<v-subheader>
Tools
</v-subheader>
<skill-list-tile
v-for="tool in tools"
:key="tool._id"
hide-modifier
:model="tool"
:data-id="tool._id"
/>
</v-list>
</v-card>
</div>
<div
v-if="languages && languages.length"
class="language-proficiencies"
>
<v-card>
<v-list>
<v-subheader>
Languages
</v-subheader>
<skill-list-tile
v-for="language in languages"
:key="language._id"
hide-modifier
:model="language"
:data-id="language._id"
/>
</v-list>
</v-card>
</div>
</column-layout>
</div>
</column-layout>
</div>
</template>
<script lang="js">
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import ColumnLayout from '/imports/ui/components/ColumnLayout.vue';
import DamageMultiplierCard from '/imports/ui/properties/components/damageMultipliers/DamageMultiplierCard.vue';
import HealthBarCardContainer from '/imports/ui/properties/components/attributes/HealthBarCardContainer.vue';
import SkillListTile from '/imports/ui/properties/components/skills/SkillListTile.vue';
import ActionCard from '/imports/ui/properties/components/actions/ActionCard.vue';
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
import numberToSignedString from '/imports/ui/utility/numberToSignedString.js';
const getProperties = function (creature, filter, options = {
sort: { order: 1 }
}) {
if (!creature) return;
if (creature.settings.hideUnusedStats) {
filter.hide = { $ne: true };
}
filter['ancestors.id'] = creature._id;
filter.removed = { $ne: true };
filter.inactive = { $ne: true };
filter.overridden = { $ne: true };
filter.$nor = [
{ hideWhenTotalZero: true, total: 0 },
{ hideWhenValueZero: true, value: 0 },
];
return CreatureProperties.find(filter, options);
};
const getAttributeOfType = function (creature, type) {
return getProperties(creature, {
type: 'attribute',
attributeType: type,
});
};
const getSkillOfType = function (creature, type) {
return getProperties(creature, {
type: 'skill',
skillType: type,
});
}
export default {
components: {
ColumnLayout,
DamageMultiplierCard,
HealthBarCardContainer,
SkillListTile,
ActionCard,
},
props: {
creatureId: {
type: String,
required: true,
},
},
data() {
return {
doCheckLoading: false,
}
},
meteor: {
creature() {
return Creatures.findOne(this.creatureId, { fields: { settings: 1 } });
},
abilities() {
return getAttributeOfType(this.creature, 'ability');
},
stats() {
return getAttributeOfType(this.creature, 'stat');
},
toggles() {
return CreatureProperties.find({
'ancestors.id': this.creatureId,
type: 'toggle',
removed: { $ne: true },
deactivatedByAncestor: { $ne: true },
showUI: true,
}, {
sort: { order: 1 }
});
},
modifiers() {
return getAttributeOfType(this.creature, 'modifier');
},
resources() {
return getAttributeOfType(this.creature, 'resource');
},
spellSlots() {
return getAttributeOfType(this.creature, 'spellSlot');
},
hasSpells() {
const cursor = getProperties(this.creature, {
type: 'spell',
})
return cursor && cursor.count();
},
hitDice() {
return getAttributeOfType(this.creature, 'hitDice');
},
checks() {
return getSkillOfType(this.creature, 'check');
},
savingThrows() {
return getSkillOfType(this.creature, 'save');
},
skills() {
return getSkillOfType(this.creature, 'skill');
},
tools() {
return getSkillOfType(this.creature, 'tool');
},
weapons() {
return getSkillOfType(this.creature, 'weapon');
},
armors() {
return getSkillOfType(this.creature, 'armor');
},
languages() {
return getSkillOfType(this.creature, 'language');
},
actions() {
return getProperties(this.creature, { type: 'action' });
},
appliedBuffs() {
return getProperties(this.creature, { type: 'buff' });
},
multipliers() {
return getProperties(this.creature, {
type: 'damageMultiplier'
}, {
sort: { value: 1, order: 1 }
});
},
},
methods: {
numberToSignedString,
},
};
</script>
<style lang="css" scoped>
.double-border {
position: relative;
padding: 11px 10px;
}
.double-border::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border-image-source: url(/images/print/doubleLineImageBorder.png);
border-image-slice: 110 126 fill;
border-image-width: 16px;
border-image-repeat: stretch;
box-sizing: content-box;
z-index: -1;
}
.octogon-border {
position: relative;
padding: 4px 20px;
}
.octogon-border::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border-image: url(/images/print/octogonBorder.png) 124 118 fill;
border-image-width: 22px;
z-index: -1;
}
.shield-border {
min-width: 64px !important;
display: flex;
align-items: center;
justify-content: center;
position: relative;
aspect-ratio: 0.87;
padding: 12px;
}
.shield-border::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: url(/images/print/shieldBorder.png);
background-size: contain;
background-position: center;
background-repeat: no-repeat;
z-index: -1;
}
.shield-number-label {
align-items: center !important;
}
.big-number {
font-size: 20pt;
}
.ability {
display: flex;
align-items: start;
margin: 4px 0;
}
.ability .score {
display: flex;
flex-direction: column;
align-items: center;
}
.ability .top {
min-width: 64px;
text-align: center;
margin-bottom: -10px;
padding: 14px;
z-index: 1;
}
.ability .bottom {
font-size: 10pt;
position: relative;
padding: 0 16px;
z-index: 2;
}
.ability .bottom::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border: solid white;
border-image-source: url(/images/print/upwardPointingBorder.png);
border-image-slice: 0 85 fill;
border-image-width: 0 16px;
border-image-outset: 0px 0px;
border-image-repeat: stretch;
box-sizing: content-box;
z-index: -1;
}
.ability .name {
margin-top: 10px;
margin-left: -16px;
padding-left: 20px;
}
.number-label {
display: flex;
align-items: flex-start;
}
.label {
font-size: 10pt;
font-variant: small-caps;
flex-grow: 1;
}
.number-label .label {
margin-top: 4px;
margin-left: -30px;
padding-left: 34px;
z-index: -1;
}
.number-label .number {
min-width: 72px;
text-align: center;
z-index: 1;
}
.number-label .box {
width: 48px;
height: 48px;
margin-left: 10px;
z-index: 1;
}
</style>

View File

@@ -12,6 +12,7 @@ const LibraryCollectionToolbar = () => import('/imports/ui/library/LibraryCollec
const CharacterSheetPage = () => import('/imports/ui/pages/CharacterSheetPage.vue');
const CharacterSheetToolbar = () => import('/imports/ui/creature/character/CharacterSheetToolbar.vue');
const CharacterSheetRightDrawer = () => import('/imports/ui/creature/character/CharacterSheetRightDrawer.vue');
const CharacterSheetPrinted = () => import('/imports/ui/creature/character/printedCharacterSheet/CharacterSheetPrinted.vue');
const SignIn = () => import('/imports/ui/pages/SignIn.vue');
const Register = () => import('/imports/ui/pages/Register.vue');
const IconAdmin = () => import('/imports/ui/icons/IconAdmin.vue');
@@ -177,6 +178,16 @@ RouterFactory.configure(router => {
meta: {
title: 'Character Sheet',
},
}, {
name: 'printCharacterSheet',
path: '/print-character/:id',
alias: '/print-character/:id/:urlName',
components: {
default: CharacterSheetPrinted,
},
meta: {
title: 'Print Character Sheet',
},
}, {
path: '/tabletops',
name: 'tabletops',