Merge branch 'version-2' into version-2-tabletop

This commit is contained in:
Stefan Zermatten
2022-10-22 19:29:31 +02:00
437 changed files with 18762 additions and 8849 deletions

View File

@@ -4,7 +4,10 @@
Delete {{ typeName }}
</v-toolbar-title>
<div>
<v-alert type="warning" outlined>
<v-alert
type="warning"
outlined
>
This can't be undone
</v-alert>
<p v-if="name">
@@ -13,6 +16,8 @@
<v-text-field
v-if="name"
v-model="inputName"
label="Confirmation"
outlined
/>
<div class="layout justify-center">
<v-btn
@@ -39,26 +44,35 @@
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
export default {
components: {
DialogBase,
},
props: {
typeName: String,
name: String,
},
data(){return {
inputName: undefined,
}},
computed: {
nameMatch(){
if (!this.name) return true;
let uppername = this.name.toUpperCase();
let upperInputName = this.inputName && this.inputName.toUpperCase();
return uppername === upperInputName;
},
},
components: {
DialogBase,
},
props: {
typeName: {
type: String,
default: undefined,
},
name: {
type: String,
default: undefined,
},
},
data() {
return {
inputName: undefined,
}
},
computed: {
nameMatch() {
if (!this.name) return true;
let uppername = this.name.toUpperCase();
let upperInputName = this.inputName && this.inputName.toUpperCase();
return uppername === upperInputName;
},
},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -50,63 +50,69 @@
</template>
<script lang="js">
import getThemeColor from '/imports/ui/utility/getThemeColor.js';
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import getThemeColor from '/imports/ui/utility/getThemeColor.js';
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
export default {
props: {
color: {
type: String,
default: undefined,
},
overrideBackButton: {
type: Function,
default: undefined,
},
darkBody: Boolean,
},
data(){ return {
offsetTop: 0,
}},
computed: {
isDark(){
return isDarkColor(this.computedColor);
},
computedColor(){
return this.color || getThemeColor('secondary');
export default {
props: {
color: {
type: String,
default: undefined,
},
overrideBackButton: {
type: Function,
default: undefined,
},
darkBody: Boolean,
},
data() {
return {
offsetTop: 0,
}
},
computed: {
isDark() {
return isDarkColor(this.computedColor);
},
computedColor() {
return this.color || getThemeColor('secondary');
}
},
methods: {
onScroll(e) {
this.offsetTop = e.target.scrollTop
},
back() {
if (this.overrideBackButton) {
this.overrideBackButton();
} else {
this.close();
}
},
methods: {
onScroll(e){
this.offsetTop = e.target.scrollTop
},
back(){
if (this.overrideBackButton){
this.overrideBackButton();
} else {
this.close();
}
},
close(){
this.$store.dispatch('popDialogStack');
},
},
}
close() {
this.$store.dispatch('popDialogStack');
},
},
}
</script>
<style scoped>
.base-dialog-toolbar {
z-index: 2;
border-radius: 2px 2px 0 0;
}
#base-dialog-body, .unwrapped-content {
flex-grow: 1;
overflow: auto;
}
#base-dialog-body.dark-body {
background-color: #fafafa;
}
.theme--dark #base-dialog-body.dark-body {
background-color: #303030;
}
.base-dialog-toolbar {
z-index: 2;
border-radius: 2px 2px 0 0;
}
#base-dialog-body,
.unwrapped-content {
flex-grow: 1;
overflow: auto;
}
#base-dialog-body.dark-body {
background-color: #fafafa;
}
.theme--dark #base-dialog-body.dark-body {
background-color: #303030;
}
</style>

View File

@@ -1,4 +1,23 @@
const AddCreaturePropertyDialog = () => import('/imports/ui/creature/creatureProperties/AddCreaturePropertyDialog.vue');
// Load commonly used dialogs immediately
import AddCreaturePropertyDialog from '/imports/ui/creature/creatureProperties/AddCreaturePropertyDialog.vue';
import CharacterCreationDialog from '/imports/ui/creature/character/CharacterCreationDialog.vue';
import CastSpellWithSlotDialog from '/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue';
import CreatureFormDialog from '/imports/ui/creature/CreatureFormDialog.vue';
import CreaturePropertyCreationDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue';
import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue';
import CreaturePropertyFromLibraryDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue';
import CreatureRootDialog from '/imports/ui/creature/character/CreatureRootDialog.vue';
import DeleteConfirmationDialog from '/imports/ui/dialogStack/DeleteConfirmationDialog.vue';
import ExperienceInsertDialog from '/imports/ui/creature/experiences/ExperienceInsertDialog.vue';
import ExperienceListDialog from '/imports/ui/creature/experiences/ExperienceListDialog.vue';
import HelpDialog from '/imports/ui/dialogStack/HelpDialog.vue';
import LevelUpDialog from '/imports/ui/creature/slots/LevelUpDialog.vue';
import SelectLibraryNodeDialog from '/imports/ui/library/SelectLibraryNodeDialog.vue';
import SlotFillDialog from '/imports/ui/creature/slots/SlotFillDialog.vue';
import TierTooLowDialog from '/imports/ui/user/TierTooLowDialog.vue';
import TransferOwnershipDialog from '/imports/ui/sharing/TransferOwnershipDialog.vue';
// Lazily load less common dialogs
const ArchiveDialog = () => import('/imports/ui/creature/archive/ArchiveDialog.vue');
const CastSpellWithSlotDialog = () => import('/imports/ui/properties/components/spells/CastSpellWithSlotDialog.vue');
const CharacterSheetDialog = () => import('/imports/ui/tabletop/CharacterSheetDialog.vue');
@@ -8,21 +27,16 @@ const CreaturePropertyDialog = () => import('/imports/ui/creature/creatureProper
const CreaturePropertyFromLibraryDialog = () => import('/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue');
const DeleteConfirmationDialog = () => import('/imports/ui/dialogStack/DeleteConfirmationDialog.vue');
const DeleteUserAccountDialog = () => import('/imports/ui/user/DeleteUserAccountDialog.vue');
const ExperienceInsertDialog = () => import( '/imports/ui/creature/experiences/ExperienceInsertDialog.vue');
const ExperienceListDialog = () => import( '/imports/ui/creature/experiences/ExperienceListDialog.vue');
const InviteDialog = () => import('/imports/ui/user/InviteDialog.vue');
const LibraryCollectionCreationDialog = () => import('/imports/ui/library/LibraryCollectionCreationDialog.vue');
const LibraryCollectionEditDialog = () => import('/imports/ui/library/LibraryCollectionEditDialog.vue');
const LibraryCreationDialog = () => import('/imports/ui/library/LibraryCreationDialog.vue');
const LibraryEditDialog = () => import('/imports/ui/library/LibraryEditDialog.vue');
const LibraryNodeCreationDialog = () => import('/imports/ui/library/LibraryNodeCreationDialog.vue');
const LibraryNodeDialog = () => import('/imports/ui/library/LibraryNodeDialog.vue');
const MoveLibraryNodeDialog = () => import('/imports/ui/library/MoveLibraryNodeDialog.vue');
const SelectCreaturesDialog = () => import('/imports/ui/tabletop/SelectCreaturesDialog.vue');
const SelectLibraryNodeDialog = () => import('/imports/ui/library/SelectLibraryNodeDialog.vue');
const ShareDialog = () => import('/imports/ui/sharing/ShareDialog.vue');
const SlotDetailsDialog = () => import('/imports/ui/creature/slots/SlotDetailsDialog.vue');
const SlotFillDialog = () => import('/imports/ui/creature/slots/SlotFillDialog.vue');
const TierTooLowDialog = () => import('/imports/ui/user/TierTooLowDialog.vue');
const TransferOwnershipDialog = () => import('/imports/ui/sharing/TransferOwnershipDialog.vue');
const UsernameDialog = () => import('/imports/ui/user/UsernameDialog.vue');
export default {
@@ -30,15 +44,21 @@ export default {
ArchiveDialog,
CastSpellWithSlotDialog,
CharacterSheetDialog,
CharacterCreationDialog,
CreatureFormDialog,
CreaturePropertyCreationDialog,
CreaturePropertyDialog,
CreaturePropertyFromLibraryDialog,
CreatureRootDialog,
DeleteConfirmationDialog,
DeleteUserAccountDialog,
ExperienceInsertDialog,
ExperienceListDialog,
HelpDialog,
InviteDialog,
LevelUpDialog,
LibraryCollectionCreationDialog,
LibraryCollectionEditDialog,
LibraryCreationDialog,
LibraryEditDialog,
LibraryNodeCreationDialog,
@@ -47,7 +67,6 @@ export default {
SelectCreaturesDialog,
SelectLibraryNodeDialog,
ShareDialog,
SlotDetailsDialog,
SlotFillDialog,
TierTooLowDialog,
TransferOwnershipDialog,

View File

@@ -0,0 +1,108 @@
<template lang="html">
<dialog-base>
<v-icon
slot="toolbar"
class="mr-2"
>
mdi-help
</v-icon>
<v-toolbar-title slot="toolbar">
Help: {{ title }}
</v-toolbar-title>
<div>
<v-progress-circular
v-if="!doc && !$subReady.docs"
indeterminate
color="primary"
size="32"
/>
<div v-else-if="!doc">
Help document not found for {{ title }}
</div>
<markdown-text
v-else
:markdown="doc"
@click="linkClick"
/>
</div>
<v-spacer slot="actions" />
<v-btn
slot="actions"
text
@click="$store.dispatch('popDialogStack')"
>
Close
</v-btn>
</dialog-base>
</template>
<script lang="js">
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import { propsByDocsPath } from '/imports/constants/PROPERTIES.js';
import MarkdownText from '/imports/ui/components/MarkdownText.vue';
import Docs from '/imports/api/docs/Docs.js';
export default {
components: {
DialogBase,
MarkdownText,
},
props: {
path: {
type: String,
required: true,
}
},
computed: {
prop() {
return propsByDocsPath.get(this.path);
},
title() {
if (this.prop) {
return this.prop.name;
} else {
const titleCase = this.path.replace(
/(\w*)(\W+)/g,
function (txt, word) {
return word.charAt(0).toUpperCase() + word.substr(1).toLowerCase() + ' ';
}
);
return titleCase || 'Character Sheet';
}
}
},
meteor: {
$subscribe: {
'docs'() {
return [this.path];
},
},
doc() {
const doc = Docs.findOne(this.path);
return doc && doc.text;
},
},
methods: {
linkClick(e) {
const target = e.target || e.srcElement;
const href = target && target.href;
if (!href) return;
const path = href.split('/docs/')[1];
if (!path) return;
e.preventDefault();
target.dataset.id = path;
this.$store.commit('pushDialogStack', {
component: 'help-dialog',
elementId: path,
data: {
path,
},
});
},
},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -2,42 +2,42 @@ import { parse, stringify } from 'css-box-shadow';
// Only supports border radius defined like "20px" or "100%"
const transformedRadius = (radiusString, deltaWidth, deltaHeight) => {
if (/^\d+\.?\d*px$/.test(radiusString)){
//The radius is defined in pixel units, so get the radius as a number
const rad = +radiusString.match(/\d+\.?\d*/)[0];
// Set the x and y radius of the "to" element, compensating for scale
return `${rad / deltaWidth}px / ${rad / deltaHeight}px`;
} else if (/^\d+\.?\d*%$/.test(radiusString)) {
//The radius is defined as a percentage, so just use it as is
return radiusString;
}
if (/^\d+\.?\d*px$/.test(radiusString)) {
//The radius is defined in pixel units, so get the radius as a number
const rad = +radiusString.match(/\d+\.?\d*/)[0];
// Set the x and y radius of the "to" element, compensating for scale
return `${rad / deltaWidth}px / ${rad / deltaHeight}px`;
} else if (/^\d+\.?\d*%$/.test(radiusString)) {
//The radius is defined as a percentage, so just use it as is
return radiusString;
}
};
const transformedBoxShadow = (shadowString, deltaWidth, deltaHeight) => {
if (shadowString === 'none') return shadowString;
if (shadowString[0] === 'r'){
let strings = shadowString.match(/rgba\([^)]+\)[^,]+/g);
strings = strings.map(string => {
// Move color to end
let m = string.match(/(rgba\([^)]+\))([^,]+)/);
return `${m[2].trim()} ${m[1]}`;
});
shadowString = strings.join(', ');
}
let scaleAverage = (deltaWidth + deltaHeight) / 2;
let shadows = parse(shadowString);
shadows.forEach(shadow => {
shadow.offsetX /= deltaWidth;
shadow.offsetY /= deltaHeight;
shadow.blurRadius /= scaleAverage;
shadow.spreadRadius /= scaleAverage;
})
return stringify(shadows);
if (shadowString === 'none') return shadowString;
if (shadowString[0] === 'r') {
let strings = shadowString.match(/rgba\([^)]+\)[^,]+/g);
strings = strings.map(string => {
// Move color to end
let m = string.match(/(rgba\([^)]+\))([^,]+)/);
return `${m[2].trim()} ${m[1]}`;
});
shadowString = strings.join(', ');
}
let scaleAverage = (deltaWidth + deltaHeight) / 2;
let shadows = parse(shadowString);
shadows.forEach(shadow => {
shadow.offsetX /= deltaWidth;
shadow.offsetY /= deltaHeight;
shadow.blurRadius /= scaleAverage;
shadow.spreadRadius /= scaleAverage;
})
return stringify(shadows);
}
export default function mockElement({source, target, offset = {x: 0, y: 0}}){
if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}` ;
let sourceRect = source.getBoundingClientRect();
export default function mockElement({ source, target, offset = { x: 0, y: 0 } }) {
if (!source || !target) throw `Can't mock without ${source ? 'target' : 'source'}`;
let sourceRect = source.getBoundingClientRect();
let targetRect = target.getBoundingClientRect();
// Get how must the target change to become the source
@@ -47,20 +47,20 @@ export default function mockElement({source, target, offset = {x: 0, y: 0}}){
const deltaTop = sourceRect.top - targetRect.top + offset.y;
// Mock the source
target.style.transform = `translate(${deltaLeft}px, ${deltaTop}px) ` +
`scale(${deltaWidth}, ${deltaHeight})`;
`scale(${deltaWidth}, ${deltaHeight})`;
// Mock the background color unless it's completely transparent
let backgroundColor = getComputedStyle(source).backgroundColor
if (backgroundColor !== 'rgba(0, 0, 0, 0)'){
if (backgroundColor !== 'rgba(0, 0, 0, 0)') {
target.style.backgroundColor = backgroundColor;
}
// Edge might not combine all border radii into a single value,
// So we just sample the top left one if we need to
let oldRadius = getComputedStyle(source).borderRadius ||
getComputedStyle(source).borderTopLeftRadius;
let borderRadius = transformedRadius(oldRadius, deltaWidth, deltaHeight);
target.style.borderRadius = borderRadius;
let boxShadow = transformedBoxShadow(
getComputedStyle(source).boxShadow, deltaWidth, deltaHeight
);
target.style.setProperty('box-shadow', boxShadow, 'important');
// Edge might not combine all border radii into a single value,
// So we just sample the top left one if we need to
let oldRadius = getComputedStyle(source).borderRadius ||
getComputedStyle(source).borderTopLeftRadius;
let borderRadius = transformedRadius(oldRadius, deltaWidth, deltaHeight);
target.style.borderRadius = borderRadius;
let boxShadow = transformedBoxShadow(
getComputedStyle(source).boxShadow, deltaWidth, deltaHeight
);
target.style.setProperty('box-shadow', boxShadow, 'important');
}