forked from profectus/Profectus
Remove processedPropType and convert all components to composition API
This commit is contained in:
parent
ccd685cb9c
commit
1e5411d279
19 changed files with 1058 additions and 1046 deletions
|
@ -29,14 +29,23 @@ import player from "game/player";
|
||||||
import { computed, toRef, unref } from "vue";
|
import { computed, toRef, unref } from "vue";
|
||||||
import Layer from "./Layer.vue";
|
import Layer from "./Layer.vue";
|
||||||
import Nav from "./Nav.vue";
|
import Nav from "./Nav.vue";
|
||||||
|
import { deepUnref } from "util/vue";
|
||||||
|
|
||||||
const tabs = toRef(player, "tabs");
|
const tabs = toRef(player, "tabs");
|
||||||
const layerKeys = computed(() => Object.keys(layers));
|
const layerKeys = computed(() => Object.keys(layers));
|
||||||
const useHeader = projInfo.useHeader;
|
const useHeader = projInfo.useHeader;
|
||||||
|
|
||||||
function gatherLayerProps(layer: GenericLayer) {
|
function gatherLayerProps(layer: GenericLayer) {
|
||||||
const { display, minimized, name, color, minimizable, nodes, minimizedDisplay } = layer;
|
const { display, name, color, minimizable, minimizedDisplay } = deepUnref(layer);
|
||||||
return { display, minimized, name, color, minimizable, nodes, minimizedDisplay };
|
return {
|
||||||
|
display,
|
||||||
|
name,
|
||||||
|
color,
|
||||||
|
minimizable,
|
||||||
|
minimizedDisplay,
|
||||||
|
minimized: layer.minimized,
|
||||||
|
nodes: layer.nodes
|
||||||
|
};
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -23,80 +23,48 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import projInfo from "data/projInfo.json";
|
import projInfo from "data/projInfo.json";
|
||||||
import type { CoercableComponent } from "features/feature";
|
import type { CoercableComponent } from "features/feature";
|
||||||
import type { FeatureNode } from "game/layers";
|
import type { FeatureNode } from "game/layers";
|
||||||
import player from "game/player";
|
import player from "game/player";
|
||||||
import { computeComponent, computeOptionalComponent, processedPropType, unwrapRef } from "util/vue";
|
import { computeComponent, computeOptionalComponent } from "util/vue";
|
||||||
import { PropType, Ref, computed, defineComponent, onErrorCaptured, ref, toRefs, unref } from "vue";
|
import { Ref, computed, onErrorCaptured, ref, toRef, unref } from "vue";
|
||||||
import Context from "./Context.vue";
|
import Context from "./Context.vue";
|
||||||
import ErrorVue from "./Error.vue";
|
import ErrorVue from "./Error.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
components: { Context, ErrorVue },
|
index: number;
|
||||||
props: {
|
display: CoercableComponent;
|
||||||
index: {
|
minimizedDisplay?: CoercableComponent;
|
||||||
type: Number,
|
minimized: Ref<boolean>;
|
||||||
required: true
|
name: string;
|
||||||
},
|
color?: string;
|
||||||
display: {
|
minimizable?: boolean;
|
||||||
type: processedPropType<CoercableComponent>(Object, String, Function),
|
nodes: Ref<Record<string, FeatureNode | undefined>>;
|
||||||
required: true
|
}>();
|
||||||
},
|
|
||||||
minimizedDisplay: processedPropType<CoercableComponent>(Object, String, Function),
|
|
||||||
minimized: {
|
|
||||||
type: Object as PropType<Ref<boolean>>,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: processedPropType<string>(String),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
color: processedPropType<string>(String),
|
|
||||||
minimizable: processedPropType<boolean>(Boolean),
|
|
||||||
nodes: {
|
|
||||||
type: Object as PropType<Ref<Record<string, FeatureNode | undefined>>>,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ["setMinimized"],
|
|
||||||
setup(props) {
|
|
||||||
const { display, index, minimized, minimizedDisplay } = toRefs(props);
|
|
||||||
|
|
||||||
const component = computeComponent(display);
|
const component = computeComponent(toRef(props, "display"));
|
||||||
const minimizedComponent = computeOptionalComponent(minimizedDisplay);
|
const minimizedComponent = computeOptionalComponent(toRef(props, "minimizedDisplay"));
|
||||||
const showGoBack = computed(
|
const showGoBack = computed(
|
||||||
() => projInfo.allowGoBack && index.value > 0 && !unwrapRef(minimized)
|
() => projInfo.allowGoBack && props.index > 0 && !unref(props.minimized)
|
||||||
);
|
);
|
||||||
|
|
||||||
function goBack() {
|
function goBack() {
|
||||||
player.tabs.splice(unref(props.index), Infinity);
|
player.tabs.splice(unref(props.index), Infinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateNodes(nodes: Record<string, FeatureNode | undefined>) {
|
function updateNodes(nodes: Record<string, FeatureNode | undefined>) {
|
||||||
props.nodes.value = nodes;
|
props.nodes.value = nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
const errors = ref<Error[]>([]);
|
const errors = ref<Error[]>([]);
|
||||||
onErrorCaptured((err, instance, info) => {
|
onErrorCaptured((err, instance, info) => {
|
||||||
console.warn(`Error caught in "${props.name}" layer`, err, instance, info);
|
console.warn(`Error caught in "${props.name}" layer`, err, instance, info);
|
||||||
errors.value.push(
|
errors.value.push(
|
||||||
err instanceof Error ? (err as Error) : new Error(JSON.stringify(err))
|
err instanceof Error ? (err as Error) : new Error(JSON.stringify(err))
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
component,
|
|
||||||
minimizedComponent,
|
|
||||||
showGoBack,
|
|
||||||
updateNodes,
|
|
||||||
unref,
|
|
||||||
goBack,
|
|
||||||
errors
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "components/common/fields.css";
|
import "components/common/fields.css";
|
||||||
import type { CoercableComponent } from "features/feature";
|
import type { CoercableComponent } from "features/feature";
|
||||||
import { computeOptionalComponent, unwrapRef } from "util/vue";
|
import { computeOptionalComponent } from "util/vue";
|
||||||
import { ref, toRef, watch } from "vue";
|
import { ref, toRef, unref, watch } from "vue";
|
||||||
import VueNextSelect from "vue-next-select";
|
import VueNextSelect from "vue-next-select";
|
||||||
import "vue-next-select/dist/index.css";
|
import "vue-next-select/dist/index.css";
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ const value = ref<SelectOption | null>(
|
||||||
props.options.find(option => option.value === props.modelValue) ?? null
|
props.options.find(option => option.value === props.modelValue) ?? null
|
||||||
);
|
);
|
||||||
watch(toRef(props, "modelValue"), modelValue => {
|
watch(toRef(props, "modelValue"), modelValue => {
|
||||||
if (unwrapRef(value) !== modelValue) {
|
if (unref(value) !== modelValue) {
|
||||||
value.value = props.options.find(option => option.value === modelValue) ?? null;
|
value.value = props.options.find(option => option.value === modelValue) ?? null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,89 +23,62 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import "components/common/features.css";
|
import "components/common/features.css";
|
||||||
import MarkNode from "components/MarkNode.vue";
|
|
||||||
import Node from "components/Node.vue";
|
|
||||||
import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
||||||
import { displayRequirements, Requirements } from "game/requirements";
|
import { displayRequirements, Requirements } from "game/requirements";
|
||||||
import { coerceComponent, isCoercableComponent, processedPropType, unwrapRef } from "util/vue";
|
import { coerceComponent, isCoercableComponent } from "util/vue";
|
||||||
import { Component, defineComponent, shallowRef, StyleValue, toRefs, unref, UnwrapRef, watchEffect } from "vue";
|
import { Component, shallowRef, StyleValue, unref, UnwrapRef, watchEffect } from "vue";
|
||||||
import { GenericAchievement } from "./achievement";
|
import { GenericAchievement } from "./achievement";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
visibility: {
|
display?: UnwrapRef<GenericAchievement["display"]>;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
earned: boolean;
|
||||||
required: true
|
requirements?: Requirements;
|
||||||
},
|
image?: string;
|
||||||
display: processedPropType<UnwrapRef<GenericAchievement["display"]>>(Object, String, Function),
|
style?: StyleValue;
|
||||||
earned: {
|
classes?: Record<string, boolean>;
|
||||||
type: processedPropType<boolean>(Boolean),
|
mark?: boolean | string;
|
||||||
required: true
|
small?: boolean;
|
||||||
},
|
id: string;
|
||||||
requirements: processedPropType<Requirements>(Object, Array),
|
}>();
|
||||||
image: processedPropType<string>(String),
|
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
mark: processedPropType<boolean | string>(Boolean, String),
|
|
||||||
small: processedPropType<boolean>(Boolean),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Node,
|
|
||||||
MarkNode
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { display, requirements, earned } = toRefs(props);
|
|
||||||
|
|
||||||
const comp = shallowRef<Component | string>("");
|
const comp = shallowRef<Component | string>("");
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const currDisplay = unwrapRef(display);
|
const currDisplay = props.display;
|
||||||
if (currDisplay == null) {
|
if (currDisplay == null) {
|
||||||
comp.value = "";
|
comp.value = "";
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (isCoercableComponent(currDisplay)) {
|
|
||||||
comp.value = coerceComponent(currDisplay);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const Requirement = coerceComponent(currDisplay.requirement ? currDisplay.requirement : jsx(() => displayRequirements(unwrapRef(requirements) ?? [])), "h3");
|
|
||||||
const EffectDisplay = coerceComponent(currDisplay.effectDisplay || "", "b");
|
|
||||||
const OptionsDisplay = unwrapRef(earned) ?
|
|
||||||
coerceComponent(currDisplay.optionsDisplay || "", "span") :
|
|
||||||
"";
|
|
||||||
comp.value = coerceComponent(
|
|
||||||
jsx(() => (
|
|
||||||
<span>
|
|
||||||
<Requirement />
|
|
||||||
{currDisplay.effectDisplay != null ? (
|
|
||||||
<div>
|
|
||||||
<EffectDisplay />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{currDisplay.optionsDisplay != null ? (
|
|
||||||
<div class="equal-spaced">
|
|
||||||
<OptionsDisplay />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
comp,
|
|
||||||
unref,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (isCoercableComponent(currDisplay)) {
|
||||||
|
comp.value = coerceComponent(currDisplay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Requirement = coerceComponent(currDisplay.requirement ? currDisplay.requirement :
|
||||||
|
jsx(() => displayRequirements(props.requirements ?? [])), "h3");
|
||||||
|
const EffectDisplay = coerceComponent(currDisplay.effectDisplay || "", "b");
|
||||||
|
const OptionsDisplay = props.earned ?
|
||||||
|
coerceComponent(currDisplay.optionsDisplay || "", "span") :
|
||||||
|
"";
|
||||||
|
comp.value = coerceComponent(
|
||||||
|
jsx(() => (
|
||||||
|
<span>
|
||||||
|
<Requirement />
|
||||||
|
{currDisplay.effectDisplay != null ? (
|
||||||
|
<div>
|
||||||
|
<EffectDisplay />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{currDisplay.optionsDisplay != null ? (
|
||||||
|
<div class="equal-spaced">
|
||||||
|
<OptionsDisplay />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -41,107 +41,68 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import MarkNode from "components/MarkNode.vue";
|
|
||||||
import Node from "components/Node.vue";
|
|
||||||
import { CoercableComponent, isHidden, isVisible, Visibility } from "features/feature";
|
import { CoercableComponent, isHidden, isVisible, Visibility } from "features/feature";
|
||||||
import type { DecimalSource } from "util/bignum";
|
import type { DecimalSource } from "util/bignum";
|
||||||
import Decimal from "util/bignum";
|
import Decimal from "util/bignum";
|
||||||
import { Direction } from "util/common";
|
import { Direction } from "util/common";
|
||||||
import { computeOptionalComponent, processedPropType, unwrapRef } from "util/vue";
|
import { computeOptionalComponent } from "util/vue";
|
||||||
import type { CSSProperties, StyleValue } from "vue";
|
import type { CSSProperties, StyleValue } from "vue";
|
||||||
import { computed, defineComponent, toRefs, unref } from "vue";
|
import { computed, toRef, unref } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
progress: DecimalSource;
|
||||||
progress: {
|
width: number;
|
||||||
type: processedPropType<DecimalSource>(String, Object, Number),
|
height: number;
|
||||||
required: true
|
direction: Direction;
|
||||||
},
|
display?: CoercableComponent;
|
||||||
width: {
|
visibility: Visibility | boolean;
|
||||||
type: processedPropType<number>(Number),
|
style?: StyleValue;
|
||||||
required: true
|
classes?: Record<string, boolean>;
|
||||||
},
|
borderStyle?: StyleValue;
|
||||||
height: {
|
textStyle?: StyleValue;
|
||||||
type: processedPropType<number>(Number),
|
baseStyle?: StyleValue;
|
||||||
required: true
|
fillStyle?: StyleValue;
|
||||||
},
|
mark?: boolean | string;
|
||||||
direction: {
|
id: string;
|
||||||
type: processedPropType<Direction>(String),
|
}>();
|
||||||
required: true
|
|
||||||
},
|
|
||||||
display: processedPropType<CoercableComponent>(Object, String, Function),
|
|
||||||
visibility: {
|
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
style: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
borderStyle: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
textStyle: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
baseStyle: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
fillStyle: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
mark: processedPropType<boolean | string>(Boolean, String),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MarkNode,
|
|
||||||
Node
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { progress, width, height, direction, display } = toRefs(props);
|
|
||||||
|
|
||||||
const normalizedProgress = computed(() => {
|
const normalizedProgress = computed(() => {
|
||||||
let progressNumber =
|
let progressNumber =
|
||||||
progress.value instanceof Decimal
|
props.progress instanceof Decimal
|
||||||
? progress.value.toNumber()
|
? props.progress.toNumber()
|
||||||
: Number(progress.value);
|
: Number(props.progress);
|
||||||
return (1 - Math.min(Math.max(progressNumber, 0), 1)) * 100;
|
return (1 - Math.min(Math.max(progressNumber, 0), 1)) * 100;
|
||||||
});
|
|
||||||
|
|
||||||
const barStyle = computed(() => {
|
|
||||||
const barStyle: Partial<CSSProperties> = {
|
|
||||||
width: unwrapRef(width) + 0.5 + "px",
|
|
||||||
height: unwrapRef(height) + 0.5 + "px"
|
|
||||||
};
|
|
||||||
switch (unref(direction)) {
|
|
||||||
case Direction.Up:
|
|
||||||
barStyle.clipPath = `inset(${normalizedProgress.value}% 0% 0% 0%)`;
|
|
||||||
barStyle.width = unwrapRef(width) + 1 + "px";
|
|
||||||
break;
|
|
||||||
case Direction.Down:
|
|
||||||
barStyle.clipPath = `inset(0% 0% ${normalizedProgress.value}% 0%)`;
|
|
||||||
barStyle.width = unwrapRef(width) + 1 + "px";
|
|
||||||
break;
|
|
||||||
case Direction.Right:
|
|
||||||
barStyle.clipPath = `inset(0% ${normalizedProgress.value}% 0% 0%)`;
|
|
||||||
break;
|
|
||||||
case Direction.Left:
|
|
||||||
barStyle.clipPath = `inset(0% 0% 0% ${normalizedProgress.value}%)`;
|
|
||||||
break;
|
|
||||||
case Direction.Default:
|
|
||||||
barStyle.clipPath = "inset(0% 50% 0% 0%)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return barStyle;
|
|
||||||
});
|
|
||||||
|
|
||||||
const component = computeOptionalComponent(display);
|
|
||||||
|
|
||||||
return {
|
|
||||||
normalizedProgress,
|
|
||||||
barStyle,
|
|
||||||
component,
|
|
||||||
unref,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const barStyle = computed(() => {
|
||||||
|
const barStyle: Partial<CSSProperties> = {
|
||||||
|
width: props.width + 0.5 + "px",
|
||||||
|
height: props.height + 0.5 + "px"
|
||||||
|
};
|
||||||
|
switch (props.direction) {
|
||||||
|
case Direction.Up:
|
||||||
|
barStyle.clipPath = `inset(${normalizedProgress.value}% 0% 0% 0%)`;
|
||||||
|
barStyle.width = props.width + 1 + "px";
|
||||||
|
break;
|
||||||
|
case Direction.Down:
|
||||||
|
barStyle.clipPath = `inset(0% 0% ${normalizedProgress.value}% 0%)`;
|
||||||
|
barStyle.width = props.width + 1 + "px";
|
||||||
|
break;
|
||||||
|
case Direction.Right:
|
||||||
|
barStyle.clipPath = `inset(0% ${normalizedProgress.value}% 0% 0%)`;
|
||||||
|
break;
|
||||||
|
case Direction.Left:
|
||||||
|
barStyle.clipPath = `inset(0% 0% 0% ${normalizedProgress.value}%)`;
|
||||||
|
break;
|
||||||
|
case Direction.Default:
|
||||||
|
barStyle.clipPath = "inset(0% 50% 0% 0%)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return barStyle;
|
||||||
|
});
|
||||||
|
|
||||||
|
const component = computeOptionalComponent(toRef(props, "display"));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import "components/common/features.css";
|
import "components/common/features.css";
|
||||||
import MarkNode from "components/MarkNode.vue";
|
import MarkNode from "components/MarkNode.vue";
|
||||||
import Node from "components/Node.vue";
|
import Node from "components/Node.vue";
|
||||||
|
@ -39,139 +39,92 @@ import type { StyleValue } from "features/feature";
|
||||||
import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
||||||
import { getHighNotifyStyle, getNotifyStyle } from "game/notifications";
|
import { getHighNotifyStyle, getNotifyStyle } from "game/notifications";
|
||||||
import { displayRequirements, Requirements } from "game/requirements";
|
import { displayRequirements, Requirements } from "game/requirements";
|
||||||
import { coerceComponent, isCoercableComponent, processedPropType, unwrapRef } from "util/vue";
|
import { coerceComponent, isCoercableComponent } from "util/vue";
|
||||||
import type { Component, PropType, UnwrapRef } from "vue";
|
import type { Component, UnwrapRef } from "vue";
|
||||||
import { computed, defineComponent, shallowRef, toRefs, unref, watchEffect } from "vue";
|
import { computed, shallowRef, unref, watchEffect } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
active: boolean;
|
||||||
active: {
|
maxed: boolean;
|
||||||
type: processedPropType<boolean>(Boolean),
|
canComplete: boolean;
|
||||||
required: true
|
display?: UnwrapRef<GenericChallenge["display"]>;
|
||||||
},
|
requirements?: Requirements;
|
||||||
maxed: {
|
visibility: Visibility | boolean;
|
||||||
type: processedPropType<boolean>(Boolean),
|
style?: StyleValue;
|
||||||
required: true
|
classes?: Record<string, boolean>;
|
||||||
},
|
completed: boolean;
|
||||||
canComplete: {
|
canStart: boolean;
|
||||||
type: processedPropType<boolean>(Boolean),
|
mark?: boolean | string;
|
||||||
required: true
|
id: string;
|
||||||
},
|
toggle: VoidFunction;
|
||||||
display: processedPropType<UnwrapRef<GenericChallenge["display"]>>(
|
}>();
|
||||||
String,
|
|
||||||
Object,
|
|
||||||
Function
|
|
||||||
),
|
|
||||||
requirements: processedPropType<Requirements>(Object, Array),
|
|
||||||
visibility: {
|
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
completed: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
canStart: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
mark: processedPropType<boolean | string>(Boolean, String),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
toggle: {
|
|
||||||
type: Function as PropType<VoidFunction>,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MarkNode,
|
|
||||||
Node
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { active, maxed, canComplete, display, requirements } = toRefs(props);
|
|
||||||
|
|
||||||
const buttonText = computed(() => {
|
const buttonText = computed(() => {
|
||||||
if (active.value) {
|
if (props.active) {
|
||||||
return canComplete.value ? "Finish" : "Exit Early";
|
return props.canComplete ? "Finish" : "Exit Early";
|
||||||
}
|
|
||||||
if (maxed.value) {
|
|
||||||
return "Completed";
|
|
||||||
}
|
|
||||||
return "Start";
|
|
||||||
});
|
|
||||||
|
|
||||||
const comp = shallowRef<Component | string>("");
|
|
||||||
|
|
||||||
const notifyStyle = computed(() => {
|
|
||||||
const currActive = unwrapRef(active);
|
|
||||||
const currCanComplete = unwrapRef(canComplete);
|
|
||||||
if (currActive) {
|
|
||||||
if (currCanComplete) {
|
|
||||||
return getHighNotifyStyle();
|
|
||||||
}
|
|
||||||
return getNotifyStyle();
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
});
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
const currDisplay = unwrapRef(display);
|
|
||||||
if (currDisplay == null) {
|
|
||||||
comp.value = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isCoercableComponent(currDisplay)) {
|
|
||||||
comp.value = coerceComponent(currDisplay);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const Title = coerceComponent(currDisplay.title || "", "h3");
|
|
||||||
const Description = coerceComponent(currDisplay.description, "div");
|
|
||||||
const Goal = coerceComponent(currDisplay.goal != null ? currDisplay.goal : jsx(() => displayRequirements(unwrapRef(requirements) ?? [])), "h3");
|
|
||||||
const Reward = coerceComponent(currDisplay.reward || "");
|
|
||||||
const EffectDisplay = coerceComponent(currDisplay.effectDisplay || "");
|
|
||||||
comp.value = coerceComponent(
|
|
||||||
jsx(() => (
|
|
||||||
<span>
|
|
||||||
{currDisplay.title != null ? (
|
|
||||||
<div>
|
|
||||||
<Title />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<Description />
|
|
||||||
<div>
|
|
||||||
<br />
|
|
||||||
Goal: <Goal />
|
|
||||||
</div>
|
|
||||||
{currDisplay.reward != null ? (
|
|
||||||
<div>
|
|
||||||
<br />
|
|
||||||
Reward: <Reward />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{currDisplay.effectDisplay != null ? (
|
|
||||||
<div>
|
|
||||||
Currently: <EffectDisplay />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
buttonText,
|
|
||||||
notifyStyle,
|
|
||||||
comp,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden,
|
|
||||||
unref
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (props.maxed) {
|
||||||
|
return "Completed";
|
||||||
|
}
|
||||||
|
return "Start";
|
||||||
|
});
|
||||||
|
|
||||||
|
const comp = shallowRef<Component | string>("");
|
||||||
|
|
||||||
|
const notifyStyle = computed(() => {
|
||||||
|
const currActive = props.active;
|
||||||
|
const currCanComplete = props.canComplete;
|
||||||
|
if (currActive) {
|
||||||
|
if (currCanComplete) {
|
||||||
|
return getHighNotifyStyle();
|
||||||
|
}
|
||||||
|
return getNotifyStyle();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const currDisplay = props.display;
|
||||||
|
if (currDisplay == null) {
|
||||||
|
comp.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isCoercableComponent(currDisplay)) {
|
||||||
|
comp.value = coerceComponent(currDisplay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Title = coerceComponent(currDisplay.title || "", "h3");
|
||||||
|
const Description = coerceComponent(currDisplay.description, "div");
|
||||||
|
const Goal = coerceComponent(currDisplay.goal != null ? currDisplay.goal : jsx(() => displayRequirements(props.requirements ?? [])), "h3");
|
||||||
|
const Reward = coerceComponent(currDisplay.reward || "");
|
||||||
|
const EffectDisplay = coerceComponent(currDisplay.effectDisplay || "");
|
||||||
|
comp.value = coerceComponent(
|
||||||
|
jsx(() => (
|
||||||
|
<span>
|
||||||
|
{currDisplay.title != null ? (
|
||||||
|
<div>
|
||||||
|
<Title />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<Description />
|
||||||
|
<div>
|
||||||
|
<br />
|
||||||
|
Goal: <Goal />
|
||||||
|
</div>
|
||||||
|
{currDisplay.reward != null ? (
|
||||||
|
<div>
|
||||||
|
<br />
|
||||||
|
Reward: <Reward />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{currDisplay.effectDisplay != null ? (
|
||||||
|
<div>
|
||||||
|
Currently: <EffectDisplay />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import "components/common/features.css";
|
import "components/common/features.css";
|
||||||
import MarkNode from "components/MarkNode.vue";
|
import MarkNode from "components/MarkNode.vue";
|
||||||
import Node from "components/Node.vue";
|
import Node from "components/Node.vue";
|
||||||
|
@ -37,90 +37,53 @@ import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
||||||
import {
|
import {
|
||||||
coerceComponent,
|
coerceComponent,
|
||||||
isCoercableComponent,
|
isCoercableComponent,
|
||||||
processedPropType,
|
setupHoldToClick
|
||||||
setupHoldToClick,
|
|
||||||
unwrapRef
|
|
||||||
} from "util/vue";
|
} from "util/vue";
|
||||||
import type { Component, PropType, UnwrapRef } from "vue";
|
import type { Component, UnwrapRef } from "vue";
|
||||||
import { defineComponent, shallowRef, toRefs, unref, watchEffect } from "vue";
|
import { shallowRef, toRef, unref, watchEffect } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
display: UnwrapRef<GenericClickable["display"]>;
|
||||||
display: {
|
visibility: Visibility | boolean;
|
||||||
type: processedPropType<UnwrapRef<GenericClickable["display"]>>(
|
style?: StyleValue;
|
||||||
Object,
|
classes?: Record<string, boolean>;
|
||||||
String,
|
onClick?: (e?: MouseEvent | TouchEvent) => void;
|
||||||
Function
|
onHold?: VoidFunction;
|
||||||
),
|
canClick: boolean;
|
||||||
required: true
|
small?: boolean;
|
||||||
},
|
mark?: boolean | string;
|
||||||
visibility: {
|
id: string;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
}>();
|
||||||
required: true
|
|
||||||
},
|
|
||||||
style: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
onClick: Function as PropType<(e?: MouseEvent | TouchEvent) => void>,
|
|
||||||
onHold: Function as PropType<VoidFunction>,
|
|
||||||
canClick: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
small: Boolean,
|
|
||||||
mark: processedPropType<boolean | string>(Boolean, String),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Node,
|
|
||||||
MarkNode
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { display, onClick, onHold } = toRefs(props);
|
|
||||||
|
|
||||||
const comp = shallowRef<Component | string>("");
|
const comp = shallowRef<Component | string>("");
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const currDisplay = unwrapRef(display);
|
const currDisplay = props.display;
|
||||||
if (currDisplay == null) {
|
if (currDisplay == null) {
|
||||||
comp.value = "";
|
comp.value = "";
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (isCoercableComponent(currDisplay)) {
|
|
||||||
comp.value = coerceComponent(currDisplay);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const Title = coerceComponent(currDisplay.title ?? "", "h3");
|
|
||||||
const Description = coerceComponent(currDisplay.description, "div");
|
|
||||||
comp.value = coerceComponent(
|
|
||||||
jsx(() => (
|
|
||||||
<span>
|
|
||||||
{currDisplay.title != null ? (
|
|
||||||
<div>
|
|
||||||
<Title />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<Description />
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const { start, stop } = setupHoldToClick(onClick, onHold);
|
|
||||||
|
|
||||||
return {
|
|
||||||
start,
|
|
||||||
stop,
|
|
||||||
comp,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden,
|
|
||||||
unref
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (isCoercableComponent(currDisplay)) {
|
||||||
|
comp.value = coerceComponent(currDisplay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Title = coerceComponent(currDisplay.title ?? "", "h3");
|
||||||
|
const Description = coerceComponent(currDisplay.description, "div");
|
||||||
|
comp.value = coerceComponent(
|
||||||
|
jsx(() => (
|
||||||
|
<span>
|
||||||
|
{currDisplay.title != null ? (
|
||||||
|
<div>
|
||||||
|
<Title />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<Description />
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { start, stop } = setupHoldToClick(toRef(props, "onClick"), toRef(props, "onHold"));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
class="table-grid"
|
class="table-grid"
|
||||||
>
|
>
|
||||||
<div v-for="row in unref(rows)" class="row-grid" :class="{ mergeAdjacent }" :key="row">
|
<div v-for="row in unref(rows)" class="row-grid" :class="{ mergeAdjacent }" :key="row">
|
||||||
<GridCell
|
<GridCellVue
|
||||||
v-for="col in unref(cols)"
|
v-for="col in unref(cols)"
|
||||||
:key="col"
|
:key="col"
|
||||||
v-bind="gatherCellProps(unref(cells)[row * 100 + col])"
|
v-bind="gatherCellProps(unref(cells)[row * 100 + col])"
|
||||||
|
@ -16,45 +16,26 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import "components/common/table.css";
|
import "components/common/table.css";
|
||||||
import themes from "data/themes";
|
import themes from "data/themes";
|
||||||
import { isHidden, isVisible, Visibility } from "features/feature";
|
import { isHidden, isVisible, Visibility } from "features/feature";
|
||||||
import type { GridCell } from "features/grids/grid";
|
import type { GridCell } from "features/grids/grid";
|
||||||
import settings from "game/settings";
|
import settings from "game/settings";
|
||||||
import { processedPropType } from "util/vue";
|
import { computed, unref } from "vue";
|
||||||
import { computed, defineComponent, unref } from "vue";
|
|
||||||
import GridCellVue from "./GridCell.vue";
|
import GridCellVue from "./GridCell.vue";
|
||||||
|
|
||||||
export default defineComponent({
|
defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
visibility: {
|
rows: number;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
cols: number;
|
||||||
required: true
|
cells: Record<string, GridCell>;
|
||||||
},
|
}>();
|
||||||
rows: {
|
|
||||||
type: processedPropType<number>(Number),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
cols: {
|
|
||||||
type: processedPropType<number>(Number),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
cells: {
|
|
||||||
type: processedPropType<Record<string, GridCell>>(Object),
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: { GridCell: GridCellVue },
|
|
||||||
setup() {
|
|
||||||
const mergeAdjacent = computed(() => themes[settings.theme].mergeAdjacent);
|
|
||||||
|
|
||||||
function gatherCellProps(cell: GridCell) {
|
const mergeAdjacent = computed(() => themes[settings.theme].mergeAdjacent);
|
||||||
const { visibility, onClick, onHold, display, title, style, canClick, id } = cell;
|
|
||||||
return { visibility, onClick, onHold, display, title, style, canClick, id };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { unref, gatherCellProps, Visibility, mergeAdjacent, isVisible, isHidden };
|
function gatherCellProps(cell: GridCell) {
|
||||||
}
|
const { visibility, onClick, onHold, display, title, style, canClick, id } = cell;
|
||||||
});
|
return { visibility, onClick, onHold, display, title, style, canClick, id };
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import "components/common/features.css";
|
import "components/common/features.css";
|
||||||
import Node from "components/Node.vue";
|
import Node from "components/Node.vue";
|
||||||
import type { CoercableComponent, StyleValue } from "features/feature";
|
import type { CoercableComponent, StyleValue } from "features/feature";
|
||||||
|
@ -30,58 +30,26 @@ import { isHidden, isVisible, Visibility } from "features/feature";
|
||||||
import {
|
import {
|
||||||
computeComponent,
|
computeComponent,
|
||||||
computeOptionalComponent,
|
computeOptionalComponent,
|
||||||
processedPropType,
|
|
||||||
setupHoldToClick
|
setupHoldToClick
|
||||||
} from "util/vue";
|
} from "util/vue";
|
||||||
import type { PropType } from "vue";
|
import { toRef, unref } from "vue";
|
||||||
import { defineComponent, toRefs, unref } from "vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
visibility: {
|
onClick?: (e?: MouseEvent | TouchEvent) => void;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
onHold?: VoidFunction;
|
||||||
required: true
|
display: CoercableComponent;
|
||||||
},
|
title?: CoercableComponent;
|
||||||
onClick: Function as PropType<(e?: MouseEvent | TouchEvent) => void>,
|
style?: StyleValue;
|
||||||
onHold: Function as PropType<VoidFunction>,
|
canClick: boolean;
|
||||||
display: {
|
id: string;
|
||||||
type: processedPropType<CoercableComponent>(Object, String, Function),
|
}>();
|
||||||
required: true
|
|
||||||
},
|
|
||||||
title: processedPropType<CoercableComponent>(Object, String, Function),
|
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
|
||||||
canClick: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Node
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { onClick, onHold, title, display } = toRefs(props);
|
|
||||||
|
|
||||||
const { start, stop } = setupHoldToClick(onClick, onHold);
|
|
||||||
|
|
||||||
const titleComponent = computeOptionalComponent(title);
|
const { start, stop } = setupHoldToClick(toRef(props, "onClick"), toRef(props, "onHold"));
|
||||||
const component = computeComponent(display);
|
|
||||||
|
|
||||||
return {
|
const titleComponent = computeOptionalComponent(toRef(props, "title"));
|
||||||
start,
|
const component = computeComponent(toRef(props, "display"));
|
||||||
stop,
|
|
||||||
titleComponent,
|
|
||||||
component,
|
|
||||||
Visibility,
|
|
||||||
unref,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -28,67 +28,33 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import CollapseTransition from "@ivanv/vue-collapse-transition/src/CollapseTransition.vue";
|
import CollapseTransition from "@ivanv/vue-collapse-transition/src/CollapseTransition.vue";
|
||||||
import Node from "components/Node.vue";
|
import Node from "components/Node.vue";
|
||||||
import themes from "data/themes";
|
import themes from "data/themes";
|
||||||
import type { CoercableComponent } from "features/feature";
|
import type { CoercableComponent } from "features/feature";
|
||||||
import { isHidden, isVisible, Visibility } from "features/feature";
|
import { isHidden, isVisible, Visibility } from "features/feature";
|
||||||
import settings from "game/settings";
|
import settings from "game/settings";
|
||||||
import { computeComponent, processedPropType } from "util/vue";
|
import { computeComponent } from "util/vue";
|
||||||
import type { PropType, Ref, StyleValue } from "vue";
|
import type { Ref, StyleValue } from "vue";
|
||||||
import { computed, defineComponent, toRefs, unref } from "vue";
|
import { computed, toRef, unref } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
visibility: {
|
display: CoercableComponent;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
title: CoercableComponent;
|
||||||
required: true
|
color?: string;
|
||||||
},
|
collapsed: Ref<boolean>;
|
||||||
display: {
|
style?: StyleValue;
|
||||||
type: processedPropType<CoercableComponent>(Object, String, Function),
|
titleStyle?: StyleValue;
|
||||||
required: true
|
bodyStyle?: StyleValue;
|
||||||
},
|
classes?: Record<string, boolean>;
|
||||||
title: {
|
id: string;
|
||||||
type: processedPropType<CoercableComponent>(Object, String, Function),
|
}>();
|
||||||
required: true
|
|
||||||
},
|
|
||||||
color: processedPropType<string>(String),
|
|
||||||
collapsed: {
|
|
||||||
type: Object as PropType<Ref<boolean>>,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
style: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
titleStyle: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
bodyStyle: processedPropType<StyleValue>(Object, String, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Node,
|
|
||||||
CollapseTransition
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { title, display } = toRefs(props);
|
|
||||||
|
|
||||||
const titleComponent = computeComponent(title);
|
const titleComponent = computeComponent(toRef(props, "title"));
|
||||||
const bodyComponent = computeComponent(display);
|
const bodyComponent = computeComponent(toRef(props, "display"));
|
||||||
const stacked = computed(() => themes[settings.theme].mergeAdjacent);
|
const stacked = computed(() => themes[settings.theme].mergeAdjacent);
|
||||||
|
|
||||||
return {
|
|
||||||
titleComponent,
|
|
||||||
bodyComponent,
|
|
||||||
stacked,
|
|
||||||
unref,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -7,78 +7,61 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { Application } from "@pixi/app";
|
import { Application } from "@pixi/app";
|
||||||
import type { StyleValue } from "features/feature";
|
import type { StyleValue } from "features/feature";
|
||||||
import { globalBus } from "game/events";
|
import { globalBus } from "game/events";
|
||||||
import "lib/pixi";
|
import "lib/pixi";
|
||||||
import { processedPropType } from "util/vue";
|
import { nextTick, onBeforeUnmount, onMounted, shallowRef, unref } from "vue";
|
||||||
import type { PropType } from "vue";
|
|
||||||
import { defineComponent, nextTick, onBeforeUnmount, onMounted, shallowRef, unref } from "vue";
|
|
||||||
|
|
||||||
// TODO get typing support on the Particles component
|
const props = defineProps<{
|
||||||
export default defineComponent({
|
style?: StyleValue;
|
||||||
props: {
|
classes?: Record<string, boolean>;
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
onInit: (app: Application) => void;
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
id: string;
|
||||||
onInit: {
|
onContainerResized?: (rect: DOMRect) => void;
|
||||||
type: Function as PropType<(app: Application) => void>,
|
onHotReload?: VoidFunction;
|
||||||
required: true
|
}>();
|
||||||
},
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
onContainerResized: Function as PropType<(rect: DOMRect) => void>,
|
|
||||||
onHotReload: Function as PropType<VoidFunction>
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const app = shallowRef<null | Application>(null);
|
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(updateBounds);
|
const app = shallowRef<null | Application>(null);
|
||||||
const resizeListener = shallowRef<HTMLElement | null>(null);
|
|
||||||
|
|
||||||
onMounted(() => {
|
const resizeObserver = new ResizeObserver(updateBounds);
|
||||||
// ResizeListener exists because ResizeObserver's don't work when told to observe an SVG element
|
const resizeListener = shallowRef<HTMLElement | null>(null);
|
||||||
const resListener = resizeListener.value;
|
|
||||||
if (resListener != null) {
|
onMounted(() => {
|
||||||
resizeObserver.observe(resListener);
|
// ResizeListener exists because ResizeObserver's don't work when told to observe an SVG element
|
||||||
app.value = new Application({
|
const resListener = resizeListener.value;
|
||||||
resizeTo: resListener,
|
if (resListener != null) {
|
||||||
backgroundAlpha: 0
|
resizeObserver.observe(resListener);
|
||||||
});
|
app.value = new Application({
|
||||||
resizeListener.value?.appendChild(app.value.view);
|
resizeTo: resListener,
|
||||||
props.onInit?.(app.value as Application);
|
backgroundAlpha: 0
|
||||||
}
|
|
||||||
updateBounds();
|
|
||||||
if (props.onHotReload) {
|
|
||||||
nextTick(props.onHotReload);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
onBeforeUnmount(() => {
|
resizeListener.value?.appendChild(app.value.view);
|
||||||
app.value?.destroy();
|
props.onInit?.(app.value as Application);
|
||||||
});
|
}
|
||||||
|
updateBounds();
|
||||||
let isDirty = true;
|
if (props.onHotReload) {
|
||||||
function updateBounds() {
|
nextTick(props.onHotReload);
|
||||||
if (isDirty) {
|
|
||||||
isDirty = false;
|
|
||||||
nextTick(() => {
|
|
||||||
if (resizeListener.value != null) {
|
|
||||||
props.onContainerResized?.(resizeListener.value.getBoundingClientRect());
|
|
||||||
}
|
|
||||||
isDirty = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
globalBus.on("fontsLoaded", updateBounds);
|
|
||||||
|
|
||||||
return {
|
|
||||||
unref,
|
|
||||||
resizeListener
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
app.value?.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
let isDirty = true;
|
||||||
|
function updateBounds() {
|
||||||
|
if (isDirty) {
|
||||||
|
isDirty = false;
|
||||||
|
nextTick(() => {
|
||||||
|
if (resizeListener.value != null) {
|
||||||
|
props.onContainerResized?.(resizeListener.value.getBoundingClientRect());
|
||||||
|
}
|
||||||
|
isDirty = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalBus.on("fontsLoaded", updateBounds);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -19,61 +19,43 @@
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CoercableComponent, StyleValue } from "features/feature";
|
import type { CoercableComponent, StyleValue } from "features/feature";
|
||||||
import { isHidden, isVisible, Visibility } from "features/feature";
|
import { isHidden, isVisible, Visibility } from "features/feature";
|
||||||
import { getNotifyStyle } from "game/notifications";
|
import { getNotifyStyle } from "game/notifications";
|
||||||
import { computeComponent, processedPropType, unwrapRef } from "util/vue";
|
import { computeComponent } from "util/vue";
|
||||||
import { computed, defineComponent, toRefs, unref } from "vue";
|
import { computed, toRef, unref } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
visibility: {
|
display: CoercableComponent;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
style?: StyleValue;
|
||||||
required: true
|
classes?: Record<string, boolean>;
|
||||||
},
|
glowColor?: string;
|
||||||
display: {
|
active?: boolean;
|
||||||
type: processedPropType<CoercableComponent>(Object, String, Function),
|
floating?: boolean;
|
||||||
required: true
|
}>();
|
||||||
},
|
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
glowColor: processedPropType<string>(String),
|
|
||||||
active: Boolean,
|
|
||||||
floating: Boolean
|
|
||||||
},
|
|
||||||
emits: ["selectTab"],
|
|
||||||
setup(props, { emit }) {
|
|
||||||
const { display, glowColor, floating } = toRefs(props);
|
|
||||||
|
|
||||||
const component = computeComponent(display);
|
const emit = defineEmits<{
|
||||||
|
selectTab: [];
|
||||||
|
}>();
|
||||||
|
|
||||||
const glowColorStyle = computed(() => {
|
const component = computeComponent(toRef(props, "display"));
|
||||||
const color = unwrapRef(glowColor);
|
|
||||||
if (color == null || color === "") {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (unref(floating)) {
|
|
||||||
return getNotifyStyle(color);
|
|
||||||
}
|
|
||||||
return { boxShadow: `0px 9px 5px -6px ${color}` };
|
|
||||||
});
|
|
||||||
|
|
||||||
function selectTab() {
|
const glowColorStyle = computed(() => {
|
||||||
emit("selectTab");
|
const color = props.glowColor;
|
||||||
}
|
if (color == null || color === "") {
|
||||||
|
return {};
|
||||||
return {
|
|
||||||
selectTab,
|
|
||||||
component,
|
|
||||||
glowColorStyle,
|
|
||||||
unref,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (props.floating) {
|
||||||
|
return getNotifyStyle(color);
|
||||||
|
}
|
||||||
|
return { boxShadow: `0px 9px 5px -6px ${color}` };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function selectTab() {
|
||||||
|
emit("selectTab");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import Sticky from "components/layout/Sticky.vue";
|
import Sticky from "components/layout/Sticky.vue";
|
||||||
import themes from "data/themes";
|
import themes from "data/themes";
|
||||||
import type { CoercableComponent, StyleValue } from "features/feature";
|
import type { CoercableComponent, StyleValue } from "features/feature";
|
||||||
|
@ -42,93 +42,60 @@ import type { GenericTab } from "features/tabs/tab";
|
||||||
import TabButton from "features/tabs/TabButton.vue";
|
import TabButton from "features/tabs/TabButton.vue";
|
||||||
import type { GenericTabButton } from "features/tabs/tabFamily";
|
import type { GenericTabButton } from "features/tabs/tabFamily";
|
||||||
import settings from "game/settings";
|
import settings from "game/settings";
|
||||||
import { coerceComponent, isCoercableComponent, processedPropType, unwrapRef } from "util/vue";
|
import { coerceComponent, deepUnref, isCoercableComponent } from "util/vue";
|
||||||
import type { Component, PropType, Ref } from "vue";
|
import type { Component, Ref } from "vue";
|
||||||
import { computed, defineComponent, shallowRef, toRefs, unref, watchEffect } from "vue";
|
import { computed, shallowRef, unref, watchEffect } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
visibility: {
|
activeTab: GenericTab | CoercableComponent | null;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
selected: Ref<string>;
|
||||||
required: true
|
tabs: Record<string, GenericTabButton>;
|
||||||
},
|
style?: StyleValue;
|
||||||
activeTab: {
|
classes?: Record<string, boolean>;
|
||||||
type: processedPropType<GenericTab | CoercableComponent | null>(Object),
|
buttonContainerStyle?: StyleValue;
|
||||||
required: true
|
buttonContainerClasses?: Record<string, boolean>;
|
||||||
},
|
}>();
|
||||||
selected: {
|
|
||||||
type: Object as PropType<Ref<string>>,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
tabs: {
|
|
||||||
type: processedPropType<Record<string, GenericTabButton>>(Object),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
|
||||||
buttonContainerStyle: processedPropType<StyleValue>(String, Object, Array),
|
|
||||||
buttonContainerClasses: processedPropType<Record<string, boolean>>(Object)
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Sticky,
|
|
||||||
TabButton
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { activeTab } = toRefs(props);
|
|
||||||
|
|
||||||
const floating = computed(() => {
|
const floating = computed(() => {
|
||||||
return themes[settings.theme].floatingTabs;
|
return themes[settings.theme].floatingTabs;
|
||||||
});
|
|
||||||
|
|
||||||
const component = shallowRef<Component | string>("");
|
|
||||||
|
|
||||||
watchEffect(() => {
|
|
||||||
const currActiveTab = unwrapRef(activeTab);
|
|
||||||
if (currActiveTab == null) {
|
|
||||||
component.value = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isCoercableComponent(currActiveTab)) {
|
|
||||||
component.value = coerceComponent(currActiveTab);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
component.value = coerceComponent(unref(currActiveTab.display));
|
|
||||||
});
|
|
||||||
|
|
||||||
const tabClasses = computed(() => {
|
|
||||||
const currActiveTab = unwrapRef(activeTab);
|
|
||||||
const tabClasses =
|
|
||||||
isCoercableComponent(currActiveTab) || !currActiveTab
|
|
||||||
? undefined
|
|
||||||
: unref(currActiveTab.classes);
|
|
||||||
return tabClasses;
|
|
||||||
});
|
|
||||||
|
|
||||||
const tabStyle = computed(() => {
|
|
||||||
const currActiveTab = unwrapRef(activeTab);
|
|
||||||
return isCoercableComponent(currActiveTab) || !currActiveTab
|
|
||||||
? undefined
|
|
||||||
: unref(currActiveTab.style);
|
|
||||||
});
|
|
||||||
|
|
||||||
function gatherButtonProps(button: GenericTabButton) {
|
|
||||||
const { display, style, classes, glowColor, visibility } = button;
|
|
||||||
return { display, style: unref(style), classes, glowColor, visibility };
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
floating,
|
|
||||||
tabClasses,
|
|
||||||
tabStyle,
|
|
||||||
Visibility,
|
|
||||||
component,
|
|
||||||
gatherButtonProps,
|
|
||||||
unref,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const component = shallowRef<Component | string>("");
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const currActiveTab = props.activeTab;
|
||||||
|
if (currActiveTab == null) {
|
||||||
|
component.value = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isCoercableComponent(currActiveTab)) {
|
||||||
|
component.value = coerceComponent(currActiveTab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
component.value = coerceComponent(unref(currActiveTab.display));
|
||||||
|
});
|
||||||
|
|
||||||
|
const tabClasses = computed(() => {
|
||||||
|
const currActiveTab = props.activeTab;
|
||||||
|
const tabClasses =
|
||||||
|
isCoercableComponent(currActiveTab) || !currActiveTab
|
||||||
|
? undefined
|
||||||
|
: unref(currActiveTab.classes);
|
||||||
|
return tabClasses;
|
||||||
|
});
|
||||||
|
|
||||||
|
const tabStyle = computed(() => {
|
||||||
|
const currActiveTab = props.activeTab;
|
||||||
|
return isCoercableComponent(currActiveTab) || !currActiveTab
|
||||||
|
? undefined
|
||||||
|
: unref(currActiveTab.style);
|
||||||
|
});
|
||||||
|
|
||||||
|
function gatherButtonProps(button: GenericTabButton) {
|
||||||
|
const { display, style, classes, glowColor, visibility } = deepUnref(button);
|
||||||
|
return { display, style, classes, glowColor, visibility };
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import themes from "data/themes";
|
import themes from "data/themes";
|
||||||
import type { CoercableComponent } from "features/feature";
|
import type { CoercableComponent } from "features/feature";
|
||||||
import { jsx, StyleValue } from "features/feature";
|
import { jsx, StyleValue } from "features/feature";
|
||||||
|
@ -45,66 +45,45 @@ import type { VueFeature } from "util/vue";
|
||||||
import {
|
import {
|
||||||
coerceComponent,
|
coerceComponent,
|
||||||
computeOptionalComponent,
|
computeOptionalComponent,
|
||||||
processedPropType,
|
renderJSX
|
||||||
renderJSX,
|
|
||||||
unwrapRef
|
|
||||||
} from "util/vue";
|
} from "util/vue";
|
||||||
import type { Component, PropType } from "vue";
|
import type { Component } from "vue";
|
||||||
import { computed, defineComponent, ref, shallowRef, toRefs, unref } from "vue";
|
import { computed, ref, shallowRef, toRef, unref } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
element?: VueFeature;
|
||||||
element: Object as PropType<VueFeature>,
|
display: CoercableComponent;
|
||||||
display: {
|
style?: StyleValue;
|
||||||
type: processedPropType<CoercableComponent>(Object, String, Function),
|
classes?: Record<string, boolean>;
|
||||||
required: true
|
direction?: Direction;
|
||||||
},
|
xoffset?: string;
|
||||||
style: processedPropType<StyleValue>(Object, String, Array),
|
yoffset?: string;
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
pinned?: Persistent<boolean>;
|
||||||
direction: processedPropType<Direction>(String),
|
}>();
|
||||||
xoffset: processedPropType<string>(String),
|
|
||||||
yoffset: processedPropType<string>(String),
|
|
||||||
pinned: Object as PropType<Persistent<boolean>>
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { element, display, pinned } = toRefs(props);
|
|
||||||
|
|
||||||
const isHovered = ref(false);
|
const isHovered = ref(false);
|
||||||
const isShown = computed(() => (unwrapRef(pinned) || isHovered.value) && comp.value);
|
const isShown = computed(() => (props.pinned?.value === true || isHovered.value) && comp.value);
|
||||||
const comp = computeOptionalComponent(display);
|
const comp = computeOptionalComponent(toRef(props, "display"));
|
||||||
|
|
||||||
const elementComp = shallowRef<Component | "" | null>(
|
const elementComp = shallowRef<Component | "" | null>(
|
||||||
coerceComponent(
|
coerceComponent(
|
||||||
jsx(() => {
|
jsx(() => {
|
||||||
const currComponent = unwrapRef(element);
|
const currComponent = props.element;
|
||||||
return currComponent == null ? "" : renderJSX(currComponent);
|
return currComponent == null ? "" : renderJSX(currComponent);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
function togglePinned(e: MouseEvent) {
|
function togglePinned(e: MouseEvent) {
|
||||||
const isPinned = pinned as unknown as Persistent<boolean> | undefined; // Vue typing :/
|
const isPinned = props.pinned;
|
||||||
if (e.shiftKey && isPinned) {
|
if (e.shiftKey && isPinned != null) {
|
||||||
isPinned.value = !isPinned.value;
|
isPinned.value = !isPinned.value;
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const showPin = computed(() => unwrapRef(pinned) && themes[settings.theme].showPin);
|
|
||||||
|
|
||||||
return {
|
|
||||||
Direction,
|
|
||||||
isHovered,
|
|
||||||
isShown,
|
|
||||||
comp,
|
|
||||||
elementComp,
|
|
||||||
unref,
|
|
||||||
togglePinned,
|
|
||||||
showPin
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const showPin = computed(() => props.pinned?.value === true && themes[settings.theme].showPin);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -5,74 +5,58 @@
|
||||||
<Links v-if="branches" :links="unref(branches)" />
|
<Links v-if="branches" :links="unref(branches)" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import "components/common/table.css";
|
import "components/common/table.css";
|
||||||
import { jsx } from "features/feature";
|
import { jsx } from "features/feature";
|
||||||
import Links from "features/links/Links.vue";
|
import Links from "features/links/Links.vue";
|
||||||
import type { GenericTreeNode, TreeBranch } from "features/trees/tree";
|
import type { GenericTreeNode, TreeBranch } from "features/trees/tree";
|
||||||
import { coerceComponent, processedPropType, renderJSX, unwrapRef } from "util/vue";
|
import { coerceComponent, renderJSX } from "util/vue";
|
||||||
import type { Component } from "vue";
|
import type { Component } from "vue";
|
||||||
import { defineComponent, shallowRef, toRefs, unref, watchEffect } from "vue";
|
import { shallowRef, unref, watchEffect } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
nodes: GenericTreeNode[][];
|
||||||
nodes: {
|
leftSideNodes?: GenericTreeNode[];
|
||||||
type: processedPropType<GenericTreeNode[][]>(Array),
|
rightSideNodes?: GenericTreeNode[];
|
||||||
required: true
|
branches?: TreeBranch[];
|
||||||
},
|
}>();
|
||||||
leftSideNodes: processedPropType<GenericTreeNode[]>(Array),
|
|
||||||
rightSideNodes: processedPropType<GenericTreeNode[]>(Array),
|
|
||||||
branches: processedPropType<TreeBranch[]>(Array)
|
|
||||||
},
|
|
||||||
components: { Links },
|
|
||||||
setup(props) {
|
|
||||||
const { nodes, leftSideNodes, rightSideNodes } = toRefs(props);
|
|
||||||
|
|
||||||
const nodesComp = shallowRef<Component | "">();
|
const nodesComp = shallowRef<Component | "">();
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const currNodes = unwrapRef(nodes);
|
const currNodes = props.nodes;
|
||||||
nodesComp.value = coerceComponent(
|
nodesComp.value = coerceComponent(
|
||||||
|
jsx(() => (
|
||||||
|
<>
|
||||||
|
{currNodes.map(row => (
|
||||||
|
<span class="row tree-row" style="margin: 50px auto;">
|
||||||
|
{row.map(renderJSX)}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const leftNodesComp = shallowRef<Component | "">();
|
||||||
|
watchEffect(() => {
|
||||||
|
const currNodes = props.leftSideNodes;
|
||||||
|
leftNodesComp.value = currNodes
|
||||||
|
? coerceComponent(
|
||||||
jsx(() => (
|
jsx(() => (
|
||||||
<>
|
<span class="left-side-nodes small">{currNodes.map(renderJSX)}</span>
|
||||||
{currNodes.map(row => (
|
|
||||||
<span class="row tree-row" style="margin: 50px auto;">
|
|
||||||
{row.map(renderJSX)}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
))
|
))
|
||||||
);
|
)
|
||||||
});
|
: "";
|
||||||
|
});
|
||||||
|
|
||||||
const leftNodesComp = shallowRef<Component | "">();
|
const rightNodesComp = shallowRef<Component | "">();
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const currNodes = unwrapRef(leftSideNodes);
|
const currNodes = props.rightSideNodes;
|
||||||
leftNodesComp.value = currNodes
|
rightNodesComp.value = currNodes
|
||||||
? coerceComponent(
|
? coerceComponent(
|
||||||
jsx(() => (
|
jsx(() => <span class="side-nodes small">{currNodes.map(renderJSX)}</span>)
|
||||||
<span class="left-side-nodes small">{currNodes.map(renderJSX)}</span>
|
)
|
||||||
))
|
: "";
|
||||||
)
|
|
||||||
: "";
|
|
||||||
});
|
|
||||||
|
|
||||||
const rightNodesComp = shallowRef<Component | "">();
|
|
||||||
watchEffect(() => {
|
|
||||||
const currNodes = unwrapRef(rightSideNodes);
|
|
||||||
rightNodesComp.value = currNodes
|
|
||||||
? coerceComponent(
|
|
||||||
jsx(() => <span class="side-nodes small">{currNodes.map(renderJSX)}</span>)
|
|
||||||
)
|
|
||||||
: "";
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
unref,
|
|
||||||
nodesComp,
|
|
||||||
leftNodesComp,
|
|
||||||
rightNodesComp
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -33,66 +33,32 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import MarkNode from "components/MarkNode.vue";
|
import type { CoercableComponent, StyleValue, Visibility } from "features/feature";
|
||||||
import Node from "components/Node.vue";
|
import { isHidden, isVisible } from "features/feature";
|
||||||
import type { CoercableComponent, StyleValue } from "features/feature";
|
|
||||||
import { isHidden, isVisible, Visibility } from "features/feature";
|
|
||||||
import {
|
import {
|
||||||
computeOptionalComponent,
|
computeOptionalComponent,
|
||||||
isCoercableComponent,
|
|
||||||
processedPropType,
|
|
||||||
setupHoldToClick
|
setupHoldToClick
|
||||||
} from "util/vue";
|
} from "util/vue";
|
||||||
import type { PropType } from "vue";
|
import { toRef, unref } from "vue";
|
||||||
import { defineComponent, toRefs, unref } from "vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
visibility: Visibility | boolean;
|
||||||
display: processedPropType<CoercableComponent>(Object, String, Function),
|
canClick: boolean;
|
||||||
visibility: {
|
id: string;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
display?: CoercableComponent;
|
||||||
required: true
|
style?: StyleValue;
|
||||||
},
|
classes?: Record<string, boolean>;
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
onClick?: (e?: MouseEvent | TouchEvent) => void;
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
onHold?: VoidFunction;
|
||||||
onClick: Function as PropType<(e?: MouseEvent | TouchEvent) => void>,
|
color?: string;
|
||||||
onHold: Function as PropType<VoidFunction>,
|
glowColor?: string;
|
||||||
color: processedPropType<string>(String),
|
mark?: boolean | string;
|
||||||
glowColor: processedPropType<string>(String),
|
}>();
|
||||||
canClick: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
mark: processedPropType<boolean | string>(Boolean, String),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
MarkNode,
|
|
||||||
Node
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { onClick, onHold, display } = toRefs(props);
|
|
||||||
|
|
||||||
const comp = computeOptionalComponent(display);
|
const comp = computeOptionalComponent(toRef(props, "display"));
|
||||||
|
|
||||||
const { start, stop } = setupHoldToClick(onClick, onHold);
|
const { start, stop } = setupHoldToClick(toRef(props, "onClick"), toRef(props, "onHold"));
|
||||||
|
|
||||||
return {
|
|
||||||
start,
|
|
||||||
stop,
|
|
||||||
comp,
|
|
||||||
unref,
|
|
||||||
Visibility,
|
|
||||||
isCoercableComponent,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="tsx">
|
<script setup lang="tsx">
|
||||||
import "components/common/features.css";
|
import "components/common/features.css";
|
||||||
import MarkNode from "components/MarkNode.vue";
|
import MarkNode from "components/MarkNode.vue";
|
||||||
import Node from "components/Node.vue";
|
import Node from "components/Node.vue";
|
||||||
|
@ -32,94 +32,56 @@ import type { StyleValue } from "features/feature";
|
||||||
import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
import { isHidden, isVisible, jsx, Visibility } from "features/feature";
|
||||||
import type { GenericUpgrade } from "features/upgrades/upgrade";
|
import type { GenericUpgrade } from "features/upgrades/upgrade";
|
||||||
import { displayRequirements, Requirements } from "game/requirements";
|
import { displayRequirements, Requirements } from "game/requirements";
|
||||||
import { coerceComponent, isCoercableComponent, processedPropType, unwrapRef } from "util/vue";
|
import { coerceComponent, isCoercableComponent } from "util/vue";
|
||||||
import type { Component, PropType, UnwrapRef } from "vue";
|
import type { Component, UnwrapRef } from "vue";
|
||||||
import { defineComponent, shallowRef, toRefs, unref, watchEffect } from "vue";
|
import { shallowRef, unref, watchEffect } from "vue";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
display: UnwrapRef<GenericUpgrade["display"]>;
|
||||||
display: {
|
visibility: Visibility | boolean;
|
||||||
type: processedPropType<UnwrapRef<GenericUpgrade["display"]>>(String, Object, Function),
|
style?: StyleValue;
|
||||||
required: true
|
classes?: Record<string, boolean>;
|
||||||
},
|
requirements: Requirements;
|
||||||
visibility: {
|
canPurchase: boolean;
|
||||||
type: processedPropType<Visibility | boolean>(Number, Boolean),
|
bought: boolean;
|
||||||
required: true
|
mark?: boolean | string;
|
||||||
},
|
id: string;
|
||||||
style: processedPropType<StyleValue>(String, Object, Array),
|
purchase?: VoidFunction;
|
||||||
classes: processedPropType<Record<string, boolean>>(Object),
|
}>();
|
||||||
requirements: {
|
|
||||||
type: Object as PropType<Requirements>,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
canPurchase: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
bought: {
|
|
||||||
type: processedPropType<boolean>(Boolean),
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
mark: processedPropType<boolean | string>(Boolean, String),
|
|
||||||
id: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
purchase: {
|
|
||||||
type: Function as PropType<VoidFunction>,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
Node,
|
|
||||||
MarkNode
|
|
||||||
},
|
|
||||||
setup(props) {
|
|
||||||
const { display, requirements, bought } = toRefs(props);
|
|
||||||
|
|
||||||
const component = shallowRef<Component | string>("");
|
const component = shallowRef<Component | string>("");
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const currDisplay = unwrapRef(display);
|
const currDisplay = props.display;
|
||||||
if (currDisplay == null) {
|
if (currDisplay == null) {
|
||||||
component.value = "";
|
component.value = "";
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (isCoercableComponent(currDisplay)) {
|
|
||||||
component.value = coerceComponent(currDisplay);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const Title = coerceComponent(currDisplay.title || "", "h3");
|
|
||||||
const Description = coerceComponent(currDisplay.description, "div");
|
|
||||||
const EffectDisplay = coerceComponent(currDisplay.effectDisplay || "");
|
|
||||||
component.value = coerceComponent(
|
|
||||||
jsx(() => (
|
|
||||||
<span>
|
|
||||||
{currDisplay.title != null ? (
|
|
||||||
<div>
|
|
||||||
<Title />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<Description />
|
|
||||||
{currDisplay.effectDisplay != null ? (
|
|
||||||
<div>
|
|
||||||
Currently: <EffectDisplay />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
{bought.value ? null : <><br />{displayRequirements(requirements.value)}</>}
|
|
||||||
</span>
|
|
||||||
))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
component,
|
|
||||||
unref,
|
|
||||||
Visibility,
|
|
||||||
isVisible,
|
|
||||||
isHidden
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (isCoercableComponent(currDisplay)) {
|
||||||
|
component.value = coerceComponent(currDisplay);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const Title = coerceComponent(currDisplay.title || "", "h3");
|
||||||
|
const Description = coerceComponent(currDisplay.description, "div");
|
||||||
|
const EffectDisplay = coerceComponent(currDisplay.effectDisplay || "");
|
||||||
|
component.value = coerceComponent(
|
||||||
|
jsx(() => (
|
||||||
|
<span>
|
||||||
|
{currDisplay.title != null ? (
|
||||||
|
<div>
|
||||||
|
<Title />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<Description />
|
||||||
|
{currDisplay.effectDisplay != null ? (
|
||||||
|
<div>
|
||||||
|
Currently: <EffectDisplay />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{props.bought ? null : <><br />{displayRequirements(props.requirements)}</>}
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from "features/feature";
|
} from "features/feature";
|
||||||
import type { ProcessedComputable } from "util/computed";
|
import type { ProcessedComputable } from "util/computed";
|
||||||
import { DoNotCache } from "util/computed";
|
import { DoNotCache } from "util/computed";
|
||||||
import type { Component, ComputedRef, DefineComponent, PropType, Ref, ShallowRef } from "vue";
|
import type { Component, DefineComponent, Ref, ShallowRef, UnwrapRef } from "vue";
|
||||||
import {
|
import {
|
||||||
computed,
|
computed,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
|
@ -175,22 +175,22 @@ export function getFirstFeature<
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeComponent(
|
export function computeComponent(
|
||||||
component: Ref<ProcessedComputable<CoercableComponent>>,
|
component: Ref<CoercableComponent>,
|
||||||
defaultWrapper = "div"
|
defaultWrapper = "div"
|
||||||
): ShallowRef<Component | ""> {
|
): ShallowRef<Component | ""> {
|
||||||
const comp = shallowRef<Component | "">();
|
const comp = shallowRef<Component | "">();
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
comp.value = coerceComponent(unwrapRef(component), defaultWrapper);
|
comp.value = coerceComponent(unref(component), defaultWrapper);
|
||||||
});
|
});
|
||||||
return comp as ShallowRef<Component | "">;
|
return comp as ShallowRef<Component | "">;
|
||||||
}
|
}
|
||||||
export function computeOptionalComponent(
|
export function computeOptionalComponent(
|
||||||
component: Ref<ProcessedComputable<CoercableComponent | undefined> | undefined>,
|
component: Ref<CoercableComponent | undefined>,
|
||||||
defaultWrapper = "div"
|
defaultWrapper = "div"
|
||||||
): ShallowRef<Component | "" | null> {
|
): ShallowRef<Component | "" | null> {
|
||||||
const comp = shallowRef<Component | "" | null>(null);
|
const comp = shallowRef<Component | "" | null>(null);
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
const currComponent = unwrapRef(component);
|
const currComponent = unref(component);
|
||||||
comp.value =
|
comp.value =
|
||||||
currComponent === "" || currComponent == null
|
currComponent === "" || currComponent == null
|
||||||
? null
|
? null
|
||||||
|
@ -199,12 +199,14 @@ export function computeOptionalComponent(
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapRef<T>(ref: Ref<ProcessedComputable<T>>): ComputedRef<T> {
|
export function deepUnref<T extends object>(refObject: T): { [K in keyof T]: UnwrapRef<T[K]> } {
|
||||||
return computed(() => unwrapRef(ref));
|
return (Object.keys(refObject) as (keyof T)[]).reduce(
|
||||||
}
|
(acc, curr) => {
|
||||||
|
acc[curr] = unref(refObject[curr]) as UnwrapRef<T[keyof T]>;
|
||||||
export function unwrapRef<T>(ref: Ref<ProcessedComputable<T>>): T {
|
return acc;
|
||||||
return unref<T>(unref(ref));
|
},
|
||||||
|
{} as { [K in keyof T]: UnwrapRef<T[K]> }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setRefValue<T>(ref: Ref<T | Ref<T>>, value: T) {
|
export function setRefValue<T>(ref: Ref<T | Ref<T>>, value: T) {
|
||||||
|
@ -222,14 +224,6 @@ export type PropTypes =
|
||||||
| typeof Function
|
| typeof Function
|
||||||
| typeof Object
|
| typeof Object
|
||||||
| typeof Array;
|
| typeof Array;
|
||||||
// TODO Unfortunately, the typescript engine gives up on typing completely when you use this method,
|
|
||||||
// Even though it has the same typing as when doing it manually
|
|
||||||
export function processedPropType<T>(...types: PropTypes[]): PropType<ProcessedComputable<T>> {
|
|
||||||
if (!types.includes(Object)) {
|
|
||||||
types.push(Object);
|
|
||||||
}
|
|
||||||
return types as PropType<ProcessedComputable<T>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function trackHover(element: VueFeature): Ref<boolean> {
|
export function trackHover(element: VueFeature): Ref<boolean> {
|
||||||
const isHovered = ref(false);
|
const isHovered = ref(false);
|
||||||
|
@ -245,8 +239,11 @@ export function trackHover(element: VueFeature): Ref<boolean> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function kebabifyObject(object: Record<string, unknown>) {
|
export function kebabifyObject(object: Record<string, unknown>) {
|
||||||
return Object.keys(object).reduce((acc, curr) => {
|
return Object.keys(object).reduce(
|
||||||
acc[camelToKebab(curr)] = object[curr];
|
(acc, curr) => {
|
||||||
return acc;
|
acc[camelToKebab(curr)] = object[curr];
|
||||||
}, {} as Record<string, unknown>);
|
return acc;
|
||||||
|
},
|
||||||
|
{} as Record<string, unknown>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue