Merge remote-tracking branch 'template-fork/main' into feat/board-feature-rewrite
Some checks failed
Run Tests / test (pull_request) Failing after 2m29s
Some checks failed
Run Tests / test (pull_request) Failing after 2m29s
This commit is contained in:
commit
05dc162ec1
46 changed files with 268 additions and 212 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -9,18 +9,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [0.7.0] - 2024-12-31
|
||||
### Additions
|
||||
- Added modal to take a mental health break (can be disabled via projInfo.json)
|
||||
- Added `ConversionType` symbol
|
||||
- Added `isType` function that uses a type symbol to check
|
||||
- Added `MaybeGetter` utility type for something that may be a getter function or a static value (but not a ref)
|
||||
|
||||
### Changes
|
||||
- **BREAKING** Replaced Board feature with generic Board system
|
||||
- **BREAKING** Replaced Board feature with generic Board system that works with SVG and DOM elements
|
||||
- **BREAKING** Rewrote how features are written, simplifying them greatly
|
||||
- **BREAKING** Replaced decorators with mixins and wrappers
|
||||
- **BREAKING** Moved modals to `src/components/modals`
|
||||
- **BREAKING** Updated a very large amount of dependencies, making any necessary adjustments
|
||||
- **BREAKING** Removed Grid component
|
||||
- **BREAKING** `dontMerge` is now a property on rows and columns rather than an undocumented css class you'd have to include on every feature within the row or column
|
||||
- **BREAKING** Moved all features that use the clickable component into the clickable folder
|
||||
- **BREAKING** Removed small property from clickable, since its a single css rule (min-height: unset)
|
||||
- **BREAKING** Removed `setDefault`, just use `??=`
|
||||
- **BREAKING** Made Achievement.vue use a Renderable for the display. The object of components can still be passed to createAchievement
|
||||
- **BREAKING** Made Challenge.vue use a Renderable for the display. The object of components can still be passed to createChallenge
|
||||
- Upgrades now use the clickable component
|
||||
|
||||
### Fixes
|
||||
- Hotkey descriptions were not being wrapped in `unref`
|
||||
- Links wouldn't check if the end node existed when determining valid links
|
||||
- `forceHideGoBack` was not being respected
|
||||
- Saves manager not being imported in addiction warning component
|
||||
|
||||
Contributors: thepaperpilot
|
||||
|
||||
|
|
|
@ -25,22 +25,23 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import projInfo from "data/projInfo.json";
|
||||
import { Layer, type FeatureNode } from "game/layers";
|
||||
import { type FeatureNode } from "game/layers";
|
||||
import player from "game/player";
|
||||
import { render } from "util/vue";
|
||||
import { computed, onErrorCaptured, ref, unref } from "vue";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import { computed, MaybeRef, onErrorCaptured, Ref, ref, unref } from "vue";
|
||||
import Context from "./Context.vue";
|
||||
import ErrorVue from "./Error.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
display: Layer["display"];
|
||||
minimizedDisplay: Layer["minimizedDisplay"];
|
||||
minimized: Layer["minimized"];
|
||||
name: Layer["name"];
|
||||
color: Layer["color"];
|
||||
minimizable: Layer["minimizable"];
|
||||
nodes: Layer["nodes"];
|
||||
forceHideGoBack: Layer["forceHideGoBack"];
|
||||
display: MaybeGetter<Renderable>;
|
||||
minimizedDisplay?: MaybeGetter<Renderable>;
|
||||
minimized: Ref<boolean>;
|
||||
name?: MaybeRef<string>;
|
||||
color?: MaybeRef<string>;
|
||||
minimizable?: MaybeRef<boolean>;
|
||||
nodes: Ref<Record<string, FeatureNode | undefined>>;
|
||||
forceHideGoBack?: MaybeRef<boolean>;
|
||||
index: number;
|
||||
}>();
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<Info ref="info" :changelog="changelog" />
|
||||
<Info ref="info" @open-changelog="changelog?.open()" />
|
||||
<SavesManager ref="savesManager" />
|
||||
<Options ref="options" />
|
||||
<Changelog ref="changelog" />
|
||||
|
@ -97,22 +97,19 @@
|
|||
<script setup lang="ts">
|
||||
import Changelog from "data/Changelog.vue";
|
||||
import projInfo from "data/projInfo.json";
|
||||
import Tooltip from "wrappers/tooltips/Tooltip.vue";
|
||||
import settings from "game/settings";
|
||||
import { Direction } from "util/common";
|
||||
import { galaxy, syncedSaves } from "util/galaxy";
|
||||
import type { ComponentPublicInstance } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import Tooltip from "wrappers/tooltips/Tooltip.vue";
|
||||
import Info from "./modals/Info.vue";
|
||||
import Options from "./modals/Options.vue";
|
||||
import SavesManager from "./modals/SavesManager.vue";
|
||||
|
||||
const info = ref<ComponentPublicInstance<typeof Info> | null>(null);
|
||||
const savesManager = ref<ComponentPublicInstance<typeof SavesManager> | null>(null);
|
||||
const options = ref<ComponentPublicInstance<typeof Options> | null>(null);
|
||||
// For some reason Info won't accept the changelog unless I do this:
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const changelog = ref<ComponentPublicInstance<any> | null>(null);
|
||||
const info = ref<typeof Info | null>(null);
|
||||
const savesManager = ref<typeof SavesManager | null>(null);
|
||||
const options = ref<typeof Options | null>(null);
|
||||
const changelog = ref<typeof Changelog | null>(null);
|
||||
|
||||
const { useHeader, banner, title, discordName, discordLink, versionNumber } = projInfo;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
Made in Profectus, by thepaperpilot with inspiration from Acameada and Jacorb
|
||||
</div>
|
||||
<br />
|
||||
<div class="link" @click="openChangelog">Changelog</div>
|
||||
<div class="link" @click="emits('openChangelog')">Changelog</div>
|
||||
<br />
|
||||
<div>
|
||||
<a
|
||||
|
@ -53,14 +53,13 @@
|
|||
</div>
|
||||
<br />
|
||||
<div>Time Played: {{ timePlayed }}</div>
|
||||
<Info />
|
||||
<InfoComponents />
|
||||
</div>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import type Changelog from "data/Changelog.vue";
|
||||
import projInfo from "data/projInfo.json";
|
||||
import player from "game/player";
|
||||
import { infoComponents } from "game/settings";
|
||||
|
@ -71,23 +70,21 @@ import Modal from "./Modal.vue";
|
|||
|
||||
const { title, logo, author, discordName, discordLink, versionNumber, versionTitle } = projInfo;
|
||||
|
||||
const props = defineProps<{ changelog: typeof Changelog | null }>();
|
||||
const emits = defineEmits<{
|
||||
(e: "openChangelog"): void;
|
||||
}>();
|
||||
|
||||
const isOpen = ref(false);
|
||||
|
||||
const timePlayed = computed(() => formatTime(player.timePlayed));
|
||||
|
||||
const Info = () => infoComponents.map(f => render(f));
|
||||
const InfoComponents = () => infoComponents.map(f => render(f));
|
||||
|
||||
defineExpose({
|
||||
open() {
|
||||
isOpen.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
function openChangelog() {
|
||||
props.changelog?.open();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -15,14 +15,26 @@
|
|||
<div class="modal-wrapper">
|
||||
<div class="modal-container" :width="width">
|
||||
<div class="modal-header">
|
||||
<slot name="header" :shown="isOpen"> default header </slot>
|
||||
<!--
|
||||
@slot Modal Header
|
||||
@binding {boolean} shown Whether the modal is currently open or animating
|
||||
-->
|
||||
<slot name="header" :shown="isOpen" />
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<Context ref="contextRef">
|
||||
<slot name="body" :shown="isOpen"> default body </slot>
|
||||
<!--
|
||||
@slot Modal Body
|
||||
@binding {boolean} shown Whether the modal is currently open or animating
|
||||
-->
|
||||
<slot name="body" :shown="isOpen" />
|
||||
</Context>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<!--
|
||||
@slot Modal Footer
|
||||
@binding {boolean} shown Whether the modal is currently open or animating
|
||||
-->
|
||||
<slot name="footer" :shown="isOpen">
|
||||
<div class="modal-default-footer">
|
||||
<div class="modal-default-flex-grow"></div>
|
||||
|
|
|
@ -75,15 +75,15 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Tooltip from "wrappers/tooltips/Tooltip.vue";
|
||||
import player from "game/player";
|
||||
import { Direction } from "util/common";
|
||||
import { galaxy, syncedSaves } from "util/galaxy";
|
||||
import { LoadablePlayerData } from "util/save";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import Tooltip from "wrappers/tooltips/Tooltip.vue";
|
||||
import DangerButton from "../fields/DangerButton.vue";
|
||||
import FeedbackButton from "../fields/FeedbackButton.vue";
|
||||
import Text from "../fields/Text.vue";
|
||||
import type { LoadablePlayerData } from "./SavesManager.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
save: LoadablePlayerData;
|
||||
|
|
|
@ -72,6 +72,7 @@ import {
|
|||
decodeSave,
|
||||
getCachedSave,
|
||||
getUniqueID,
|
||||
LoadablePlayerData,
|
||||
loadSave,
|
||||
newSave,
|
||||
save
|
||||
|
@ -84,8 +85,6 @@ import Text from "../fields/Text.vue";
|
|||
import Modal from "./Modal.vue";
|
||||
import Save from "./Save.vue";
|
||||
|
||||
export type LoadablePlayerData = Omit<Partial<Player>, "id"> & { id: string; error?: unknown };
|
||||
|
||||
const isOpen = ref(false);
|
||||
const modal = ref<ComponentPublicInstance<typeof Modal> | null>(null);
|
||||
|
||||
|
|
0
src/data/layers/prestige.tsx
Normal file
0
src/data/layers/prestige.tsx
Normal file
|
@ -19,13 +19,13 @@ import Node from "components/Node.vue";
|
|||
import type { Visibility } from "features/feature";
|
||||
import { isHidden, isVisible } from "features/feature";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import { render, Renderable, Wrapper } from "util/vue";
|
||||
import { MaybeRef, unref, type CSSProperties } from "vue";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
id: string;
|
||||
components: MaybeGetter<Renderable>[];
|
||||
wrappers: ((el: () => Renderable) => Renderable)[];
|
||||
wrappers: Wrapper[];
|
||||
visibility?: MaybeRef<Visibility | boolean>;
|
||||
style?: MaybeRef<CSSProperties>;
|
||||
classes?: MaybeRef<Record<string, boolean>>;
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
<script setup lang="tsx">
|
||||
import "components/common/features.css";
|
||||
import { isJSXElement, render } from "util/vue";
|
||||
import { Component, isRef, unref } from "vue";
|
||||
import { Achievement } from "./achievement";
|
||||
import { displayRequirements } from "game/requirements";
|
||||
import { Requirements } from "game/requirements";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import { Component, MaybeRef, Ref, unref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
display: Achievement["display"];
|
||||
earned: Achievement["earned"];
|
||||
requirements: Achievement["requirements"];
|
||||
image: Achievement["image"];
|
||||
small: Achievement["small"];
|
||||
display?: MaybeGetter<Renderable>;
|
||||
earned: Ref<boolean>;
|
||||
requirements?: Requirements;
|
||||
image?: MaybeRef<string>;
|
||||
small?: MaybeRef<boolean>;
|
||||
}>();
|
||||
|
||||
const Component = () => props.display == null ? <></> : render(props.display);
|
||||
|
|
|
@ -31,23 +31,23 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Decimal from "util/bignum";
|
||||
import Decimal, { DecimalSource } from "util/bignum";
|
||||
import { Direction } from "util/common";
|
||||
import { render } from "util/vue";
|
||||
import type { CSSProperties } from "vue";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import type { CSSProperties, MaybeRef } from "vue";
|
||||
import { computed, unref } from "vue";
|
||||
import { Bar } from "./bar";
|
||||
|
||||
const props = defineProps<{
|
||||
width: Bar["width"];
|
||||
height: Bar["height"];
|
||||
direction: Bar["direction"];
|
||||
borderStyle: Bar["borderStyle"];
|
||||
baseStyle: Bar["baseStyle"];
|
||||
textStyle: Bar["textStyle"];
|
||||
fillStyle: Bar["fillStyle"];
|
||||
progress: Bar["progress"];
|
||||
display: Bar["display"];
|
||||
width: MaybeRef<number>;
|
||||
height: MaybeRef<number>;
|
||||
direction: MaybeRef<Direction>;
|
||||
borderStyle?: MaybeRef<CSSProperties>;
|
||||
baseStyle?: MaybeRef<CSSProperties>;
|
||||
textStyle?: MaybeRef<CSSProperties>;
|
||||
fillStyle?: MaybeRef<CSSProperties>;
|
||||
progress: MaybeRef<DecimalSource>;
|
||||
display?: MaybeGetter<Renderable>;
|
||||
}>();
|
||||
|
||||
const normalizedProgress = computed(() => {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
>
|
||||
<button
|
||||
class="toggleChallenge"
|
||||
@click="toggle"
|
||||
@click="emits('toggle')"
|
||||
:disabled="!unref(canStart) || unref(maxed)"
|
||||
>
|
||||
{{ buttonText }}
|
||||
|
@ -22,20 +22,25 @@
|
|||
<script setup lang="tsx">
|
||||
import "components/common/features.css";
|
||||
import { getHighNotifyStyle, getNotifyStyle } from "game/notifications";
|
||||
import { render } from "util/vue";
|
||||
import type { Component } from "vue";
|
||||
import { Requirements } from "game/requirements";
|
||||
import { DecimalSource } from "util/bignum";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import type { Component, MaybeRef, Ref } from "vue";
|
||||
import { computed, unref } from "vue";
|
||||
import { Challenge } from "./challenge";
|
||||
|
||||
const props = defineProps<{
|
||||
active: Challenge["active"];
|
||||
maxed: Challenge["maxed"];
|
||||
canComplete: Challenge["canComplete"];
|
||||
display: Challenge["display"];
|
||||
requirements: Challenge["requirements"];
|
||||
completed: Challenge["completed"];
|
||||
canStart: Challenge["canStart"];
|
||||
toggle: Challenge["toggle"];
|
||||
active: Ref<boolean>;
|
||||
maxed: Ref<boolean>;
|
||||
canComplete: Ref<DecimalSource>;
|
||||
display?: MaybeGetter<Renderable>;
|
||||
requirements: Requirements;
|
||||
completed: Ref<boolean>;
|
||||
canStart?: MaybeRef<boolean>;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: "toggle"): void;
|
||||
}>();
|
||||
|
||||
const buttonText = computed(() => {
|
||||
|
|
|
@ -129,7 +129,7 @@ export function createChallenge<T extends ChallengeOptions>(optionsFunc: () => T
|
|||
requirements={challenge.requirements}
|
||||
completed={challenge.completed}
|
||||
canStart={challenge.canStart}
|
||||
toggle={challenge.toggle}
|
||||
onToggle={challenge.toggle}
|
||||
/>
|
||||
));
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<button
|
||||
@click="onClick"
|
||||
@click="e => emits('click', e)"
|
||||
@mousedown="start"
|
||||
@mouseleave="stop"
|
||||
@mouseup="stop"
|
||||
|
@ -20,24 +20,28 @@
|
|||
|
||||
<script setup lang="tsx">
|
||||
import "components/common/features.css";
|
||||
import type { Clickable } from "features/clickables/clickable";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import {
|
||||
render,
|
||||
Renderable,
|
||||
setupHoldToClick
|
||||
} from "util/vue";
|
||||
import type { Component } from "vue";
|
||||
import { toRef, unref } from "vue";
|
||||
import type { Component, MaybeRef } from "vue";
|
||||
import { unref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
canClick: Clickable["canClick"];
|
||||
onClick: Clickable["onClick"];
|
||||
onHold?: Clickable["onHold"];
|
||||
display: Clickable["display"];
|
||||
canClick: MaybeRef<boolean>;
|
||||
display?: MaybeGetter<Renderable>;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: "click", event?: MouseEvent | TouchEvent): void;
|
||||
(e: "hold"): void;
|
||||
}>();
|
||||
|
||||
const Component = () => props.display == null ? <></> : render(props.display);
|
||||
|
||||
const { start, stop } = setupHoldToClick(toRef(props, "onClick"), toRef(props, "onHold"));
|
||||
const { start, stop } = setupHoldToClick(() => emits("hold"));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -2,8 +2,8 @@ import ClickableVue from "features/clickables/Clickable.vue";
|
|||
import { findFeatures } from "features/feature";
|
||||
import { globalBus } from "game/events";
|
||||
import { persistent } from "game/persistence";
|
||||
import Decimal, { DecimalSource } from "lib/break_eternity";
|
||||
import { Unsubscribe } from "nanoevents";
|
||||
import Decimal, { DecimalSource } from "util/bignum";
|
||||
import { Direction } from "util/common";
|
||||
import { MaybeGetter, processGetter } from "util/computed";
|
||||
import { createLazyProxy } from "util/proxies";
|
||||
|
@ -125,6 +125,7 @@ export function createAction<T extends ActionOptions>(optionsFunc?: () => T) {
|
|||
<ClickableVue
|
||||
canClick={action.canClick}
|
||||
onClick={action.onClick}
|
||||
onHold={action.onClick}
|
||||
display={action.display}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -87,6 +87,7 @@ export function createClickable<T extends ClickableOptions>(optionsFunc?: () =>
|
|||
<Clickable
|
||||
canClick={clickable.canClick}
|
||||
onClick={clickable.onClick}
|
||||
onHold={clickable.onClick}
|
||||
display={clickable.display}
|
||||
/>
|
||||
)),
|
||||
|
@ -95,7 +96,7 @@ export function createClickable<T extends ClickableOptions>(optionsFunc?: () =>
|
|||
onClick:
|
||||
onClick == null
|
||||
? undefined
|
||||
: function (e) {
|
||||
: function (e?: MouseEvent | TouchEvent) {
|
||||
if (unref(clickable.canClick) !== false) {
|
||||
onClick.call(clickable, e);
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ export function createRepeatable<T extends RepeatableOptions>(optionsFunc: () =>
|
|||
<Clickable
|
||||
canClick={repeatable.canClick}
|
||||
onClick={repeatable.onClick}
|
||||
onHold={repeatable.onClick}
|
||||
display={repeatable.display}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -23,16 +23,35 @@ export enum Visibility {
|
|||
None
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for determining if a visibility value is anything but Visibility.None.
|
||||
Booleans are allowed and false will be considered to be Visibility.None.
|
||||
* @param visibility The ref to either a visibility value or boolean
|
||||
* @returns True if the visibility is either true, Visibility.Visible, or Visibility.Hidden
|
||||
*/
|
||||
export function isVisible(visibility: MaybeRef<Visibility | boolean>) {
|
||||
const currVisibility = unref(visibility);
|
||||
return currVisibility !== Visibility.None && currVisibility !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for determining if a visibility value is Visibility.Hidden.
|
||||
Booleans are allowed but will never be considered to be Visible.Hidden.
|
||||
* @param visibility The ref to either a visibility value or boolean
|
||||
* @returns True if the visibility is Visibility.Hidden
|
||||
*/
|
||||
export function isHidden(visibility: MaybeRef<Visibility | boolean>) {
|
||||
const currVisibility = unref(visibility);
|
||||
return currVisibility === Visibility.Hidden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for narrowing something that may or may not be a specified type of feature.
|
||||
* Works off the principle that all features have a unique symbol to identify themselves with.
|
||||
* @param object The object to determine whether or not is of the specified type
|
||||
* @param type The symbol to look for in the object's "type" property
|
||||
* @returns Whether or not the object is the specified type
|
||||
*/
|
||||
export function isType<T extends symbol>(object: unknown, type: T): object is { type: T } {
|
||||
return object != null && typeof object === "object" && "type" in object && object.type === type;
|
||||
}
|
||||
|
@ -64,6 +83,12 @@ export function findFeatures(obj: object, ...types: symbol[]): unknown[] {
|
|||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for taking a list of features and filtering them out, but keeping a reference to the first filtered out feature. Used for having a collapsible of the filtered out content, with the first filtered out item remaining outside the collapsible for easy reference.
|
||||
* @param features The list of features to search through
|
||||
* @param filter The filter to use to determine features that shouldn't be collapsible
|
||||
* @returns An object containing a ref to the first filtered _out_ feature, a render function for the collapsed content, and a ref for whether or not there is any collapsed content to show
|
||||
*/
|
||||
export function getFirstFeature<T extends VueFeature>(
|
||||
features: T[],
|
||||
filter: (feature: T) => boolean
|
||||
|
|
|
@ -26,17 +26,17 @@
|
|||
import CollapseTransition from "@ivanv/vue-collapse-transition/src/CollapseTransition.vue";
|
||||
import themes from "data/themes";
|
||||
import settings from "game/settings";
|
||||
import { render } from "util/vue";
|
||||
import { computed, unref } from "vue";
|
||||
import { Infobox } from "./infobox";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import { computed, CSSProperties, MaybeRef, Ref, unref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
color: Infobox["color"];
|
||||
titleStyle: Infobox["titleStyle"];
|
||||
bodyStyle: Infobox["bodyStyle"];
|
||||
collapsed: Infobox["collapsed"];
|
||||
display: Infobox["display"];
|
||||
title: Infobox["title"];
|
||||
color?: MaybeRef<string>;
|
||||
titleStyle?: MaybeRef<CSSProperties>;
|
||||
bodyStyle?: MaybeRef<CSSProperties>;
|
||||
collapsed: Ref<boolean>;
|
||||
display: MaybeGetter<Renderable>;
|
||||
title: MaybeGetter<Renderable>;
|
||||
}>();
|
||||
|
||||
const Title = () => render(props.title);
|
||||
|
|
|
@ -15,11 +15,11 @@
|
|||
<script setup lang="ts">
|
||||
import type { FeatureNode } from "game/layers";
|
||||
import { BoundsInjectionKey, NodesInjectionKey } from "game/layers";
|
||||
import { computed, inject, onMounted, ref, shallowRef, unref, watch } from "vue";
|
||||
import { computed, inject, MaybeRef, onMounted, ref, shallowRef, unref, watch } from "vue";
|
||||
import LinkVue from "./Link.vue";
|
||||
import { Links } from "./links";
|
||||
import { Link } from "./links";
|
||||
|
||||
const props = defineProps<{ links: Links["links"] }>();
|
||||
const props = defineProps<{ links: MaybeRef<Link[]> }>();
|
||||
|
||||
function updateBounds() {
|
||||
boundingRect.value = resizeListener.value?.getBoundingClientRect();
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
import { Application } from "@pixi/app";
|
||||
import { globalBus } from "game/events";
|
||||
import "lib/pixi";
|
||||
import { nextTick, onBeforeUnmount, onMounted, shallowRef, unref } from "vue";
|
||||
import type { Particles } from "./particles";
|
||||
import { nextTick, onBeforeUnmount, onMounted, shallowRef } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
onContainerResized: Particles["onContainerResized"];
|
||||
onHotReload: Particles["onHotReload"];
|
||||
onInit: (app: Application) => void;
|
||||
const emits = defineEmits<{
|
||||
(e: "containerResized", boundingRect: DOMRect): void;
|
||||
(e: "hotReload"): void;
|
||||
(e: "init", app: Application): void;
|
||||
}>();
|
||||
|
||||
const app = shallowRef<null | Application>(null);
|
||||
|
@ -32,12 +31,10 @@ onMounted(() => {
|
|||
backgroundAlpha: 0
|
||||
});
|
||||
resizeListener.value?.appendChild(app.value.view);
|
||||
props.onInit(app.value);
|
||||
emits("init", app.value);
|
||||
}
|
||||
updateBounds();
|
||||
if (props.onHotReload) {
|
||||
nextTick(props.onHotReload);
|
||||
}
|
||||
nextTick(() => emits("hotReload"));
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
app.value?.destroy();
|
||||
|
@ -50,7 +47,7 @@ function updateBounds() {
|
|||
isDirty = false;
|
||||
nextTick(() => {
|
||||
if (resizeListener.value != null) {
|
||||
props.onContainerResized?.(resizeListener.value.getBoundingClientRect());
|
||||
emits("containerResized", resizeListener.value.getBoundingClientRect());
|
||||
}
|
||||
isDirty = true;
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ import { isRef, MaybeRef, MaybeRefOrGetter, unref } from "vue";
|
|||
export const ResetType = Symbol("Reset");
|
||||
|
||||
/**
|
||||
* An object that configures a {@link Clickable}.
|
||||
* An object that configures a {@link features/clickables/clickable.Clickable}.
|
||||
*/
|
||||
export interface ResetOptions {
|
||||
/** List of things to reset. Can include objects which will be recursed over for persistent values. */
|
||||
|
|
|
@ -21,13 +21,13 @@ import ResourceVue from "features/resources/Resource.vue";
|
|||
import Decimal from "util/bignum";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { Renderable } from "util/vue";
|
||||
import { computed, ref, StyleValue, toValue } from "vue";
|
||||
import { computed, CSSProperties, ref, toValue } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
resource: Resource;
|
||||
color?: string;
|
||||
classes?: Record<string, boolean>;
|
||||
style?: StyleValue;
|
||||
style?: CSSProperties;
|
||||
effectDisplay?: MaybeGetter<Renderable>;
|
||||
}>();
|
||||
|
||||
|
|
|
@ -5,16 +5,16 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getNotifyStyle } from "game/notifications";
|
||||
import { render } from "util/vue";
|
||||
import { computed, unref } from "vue";
|
||||
import { TabButton } from "./tabFamily";
|
||||
import themes from "data/themes";
|
||||
import { getNotifyStyle } from "game/notifications";
|
||||
import settings from "game/settings";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import { computed, MaybeRef, unref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
display: TabButton["display"];
|
||||
glowColor: TabButton["glowColor"];
|
||||
display: MaybeGetter<Renderable>;
|
||||
glowColor?: MaybeRef<string>;
|
||||
active?: boolean;
|
||||
}>();
|
||||
|
||||
|
|
|
@ -15,20 +15,21 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import Sticky from "components/layout/Sticky.vue";
|
||||
import { isType } from "features/feature";
|
||||
import { render } from "util/vue";
|
||||
import type { Component } from "vue";
|
||||
import { computed, unref } from "vue";
|
||||
import { TabType } from "./tab";
|
||||
import { TabFamily } from "./tabFamily";
|
||||
import themes from "data/themes";
|
||||
import { isType } from "features/feature";
|
||||
import settings from "game/settings";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import type { Component, CSSProperties, MaybeRef, Ref } from "vue";
|
||||
import { computed, unref } from "vue";
|
||||
import { Tab, TabType } from "./tab";
|
||||
import { TabButton } from "./tabFamily";
|
||||
|
||||
const props = defineProps<{
|
||||
activeTab: TabFamily["activeTab"];
|
||||
tabs: TabFamily["tabs"];
|
||||
buttonContainerClasses: TabFamily["buttonContainerClasses"];
|
||||
buttonContainerStyle: TabFamily["buttonContainerStyle"];
|
||||
activeTab: Ref<MaybeGetter<Renderable> | Tab | null>;
|
||||
tabs: Record<string, TabButton>;
|
||||
buttonContainerClasses?: MaybeRef<Record<string, boolean>>;
|
||||
buttonContainerStyle?: MaybeRef<CSSProperties>;
|
||||
}>();
|
||||
|
||||
const Component = () => {
|
||||
|
|
|
@ -15,7 +15,7 @@ export interface TabOptions extends VueFeatureOptions {
|
|||
|
||||
/**
|
||||
* An object representing a tab of content in a tabbed interface.
|
||||
* @see {@link TabFamily}
|
||||
* @see {@link features/tabs/tabFamily.TabFamily}
|
||||
*/
|
||||
export interface Tab extends VueFeature {
|
||||
/** The display to use for this tab. */
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
<script setup lang="tsx">
|
||||
import "components/common/table.css";
|
||||
import Links from "features/links/Links.vue";
|
||||
import type { Tree } from "features/trees/tree";
|
||||
import type { Tree, TreeBranch, TreeNode } from "features/trees/tree";
|
||||
import { render } from "util/vue";
|
||||
import { unref } from "vue";
|
||||
import { MaybeRef, unref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
nodes: Tree["nodes"];
|
||||
leftSideNodes: Tree["leftSideNodes"];
|
||||
rightSideNodes: Tree["rightSideNodes"];
|
||||
branches: Tree["branches"];
|
||||
nodes: MaybeRef<TreeNode[][]>;
|
||||
leftSideNodes?: MaybeRef<TreeNode[]>;
|
||||
rightSideNodes?: MaybeRef<TreeNode[]>;
|
||||
branches?: MaybeRef<TreeBranch[]>;
|
||||
}>();
|
||||
|
||||
const Nodes = () => unref(props.nodes).map(nodes =>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
treeNode: true,
|
||||
can: unref(canClick)
|
||||
}"
|
||||
@click="onClick"
|
||||
@click="e => emits('click', e)"
|
||||
@mousedown="start"
|
||||
@mouseleave="stop"
|
||||
@mouseup="stop"
|
||||
|
@ -23,23 +23,26 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="tsx">
|
||||
import { render, setupHoldToClick } from "util/vue";
|
||||
import { toRef, unref } from "vue";
|
||||
import { TreeNode } from "./tree";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable, setupHoldToClick } from "util/vue";
|
||||
import { MaybeRef, toRef, unref } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
canClick: TreeNode["canClick"];
|
||||
display: TreeNode["display"];
|
||||
onClick: TreeNode["onClick"];
|
||||
onHold: TreeNode["onHold"];
|
||||
color: TreeNode["color"];
|
||||
glowColor: TreeNode["glowColor"];
|
||||
canClick?: MaybeRef<boolean>;
|
||||
display?: MaybeGetter<Renderable>;
|
||||
color?: MaybeRef<string>;
|
||||
glowColor?: MaybeRef<string>;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: "click", event?: MouseEvent | TouchEvent): void;
|
||||
(e: "hold"): void;
|
||||
}>();
|
||||
|
||||
const Component = () => props.display == null ? <></> :
|
||||
render(props.display, el => <div>{el}</div>);
|
||||
|
||||
const { start, stop } = setupHoldToClick(toRef(props, "onClick"), toRef(props, "onHold"));
|
||||
const { start, stop } = setupHoldToClick(() => emits("hold"));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
class="board-node"
|
||||
:style="`transform: translate(calc(${unref(position).x}px - 50%), ${unref(position).y}px);`"
|
||||
@click.capture.stop="() => {}"
|
||||
@mousedown="mouseDown"
|
||||
@touchstart.passive="mouseDown"
|
||||
@mouseup.capture="mouseUp"
|
||||
@touchend.passive="mouseUp"
|
||||
@mousedown="e => emits('mouseDown', e)"
|
||||
@touchstart.passive="e => emits('mouseDown', e)"
|
||||
@mouseup.capture="e => emits('mouseUp', e)"
|
||||
@touchend.passive="e => emits('mouseUp', e)"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -17,8 +17,11 @@ import { Ref, unref } from "vue";
|
|||
import { NodePosition } from "./board";
|
||||
|
||||
defineProps<{
|
||||
mouseDown: (e: MouseEvent | TouchEvent) => void;
|
||||
mouseUp: (e: MouseEvent | TouchEvent) => void;
|
||||
position: Ref<NodePosition>;
|
||||
}>();
|
||||
|
||||
const emits = defineEmits<{
|
||||
(e: "mouseDown", event: MouseEvent | TouchEvent): void;
|
||||
(e: "mouseUp", event: MouseEvent | TouchEvent): void;
|
||||
}>();
|
||||
</script>
|
||||
|
|
|
@ -51,7 +51,7 @@ export function setupUniqueIds(nodes: MaybeRefOrGetter<{ id: number }[]>) {
|
|||
|
||||
/** An object that configures a {@link DraggableNode}. */
|
||||
export interface DraggableNodeOptions<T> {
|
||||
/** A ref to the specific instance of the Board vue component the node will be draggable on. Obtained by passing a suitable ref as the "ref" attribute to the <Board> element. */
|
||||
/** A ref to the specific instance of the Board vue component the node will be draggable on. Obtained by passing a suitable ref as the "ref" attribute to the Board component. */
|
||||
board: Ref<ComponentPublicInstance<typeof Board> | undefined>;
|
||||
/** Getter function to go from the node (typically ID) to the position of said node. */
|
||||
getPosition: (node: T) => NodePosition;
|
||||
|
@ -266,7 +266,7 @@ export interface Draggable<T> extends MakeDraggableOptions<T> {
|
|||
/**
|
||||
* Makes a vue feature draggable on a Board.
|
||||
* @param element The vue feature to make draggable.
|
||||
* @param options The options to configure the dragging behavior.
|
||||
* @param optionsFunc The options to configure the dragging behavior.
|
||||
*/
|
||||
export function makeDraggable<T, S extends MakeDraggableOptions<T>>(
|
||||
element: VueFeature,
|
||||
|
@ -337,8 +337,8 @@ export function makeDraggable<T, S extends MakeDraggableOptions<T>>(
|
|||
(el as VueFeature & { draggable: Draggable<T> }).draggable = draggable;
|
||||
element.wrappers.push(el => (
|
||||
<Draggable
|
||||
mouseDown={draggable.onMouseDown}
|
||||
mouseUp={draggable.onMouseUp}
|
||||
onMouseDown={draggable.onMouseDown}
|
||||
onMouseUp={draggable.onMouseUp}
|
||||
position={draggable.computedPosition}
|
||||
>
|
||||
{el}
|
||||
|
|
|
@ -27,7 +27,6 @@ export interface GlobalEvents {
|
|||
* Sent when constructing the {@link Settings} object.
|
||||
* Use it to add default values for custom properties to the object.
|
||||
* @param settings The settings object being constructed.
|
||||
* @see {@link features/features.setDefault} for setting default values.
|
||||
*/
|
||||
loadSettings: (settings: Partial<Settings>) => void;
|
||||
/**
|
||||
|
|
|
@ -1290,7 +1290,7 @@ export abstract class InternalFormula<T extends [FormulaSource] | FormulaSource[
|
|||
* A class that can be used for cost/goal functions. It can be evaluated similar to a cost function, but also provides extra features for supported formulas. For example, a lot of math functions can be inverted.
|
||||
* Typically, the use of these extra features is to support cost/goal functions that have multiple levels purchased/completed at once efficiently.
|
||||
* @see {@link calculateMaxAffordable}
|
||||
* @see {@link /game/requirements.createCostRequirement}
|
||||
* @see {@link game/requirements.createCostRequirement}
|
||||
*/
|
||||
export default class Formula<
|
||||
T extends [FormulaSource] | FormulaSource[]
|
||||
|
|
|
@ -29,22 +29,22 @@ export interface FeatureNode {
|
|||
}
|
||||
|
||||
/**
|
||||
* An injection key that a {@link ContextComponent} will use to provide a function that registers a {@link FeatureNode} with the given id and HTML element.
|
||||
* An injection key that a Context component will use to provide a function that registers a {@link FeatureNode} with the given id and HTML element.
|
||||
*/
|
||||
export const RegisterNodeInjectionKey: InjectionKey<(id: string, element: HTMLElement) => void> =
|
||||
Symbol("RegisterNode");
|
||||
/**
|
||||
* An injection key that a {@link ContextComponent} will use to provide a function that unregisters a {@link FeatureNode} with the given id.
|
||||
* An injection key that a Context component will use to provide a function that unregisters a {@link FeatureNode} with the given id.
|
||||
*/
|
||||
export const UnregisterNodeInjectionKey: InjectionKey<(id: string) => void> =
|
||||
Symbol("UnregisterNode");
|
||||
/**
|
||||
* An injection key that a {@link ContextComponent} will use to provide a ref to a map of all currently registered {@link FeatureNode}s.
|
||||
* An injection key that a Context component will use to provide a ref to a map of all currently registered {@link FeatureNode}s.
|
||||
*/
|
||||
export const NodesInjectionKey: InjectionKey<Ref<Record<string, FeatureNode | undefined>>> =
|
||||
Symbol("Nodes");
|
||||
/**
|
||||
* An injection key that a {@link ContextComponent} will use to provide a ref to a bounding rect of the Context.
|
||||
* An injection key that a Context component will use to provide a ref to a bounding rect of the Context.
|
||||
*/
|
||||
export const BoundsInjectionKey: InjectionKey<Ref<DOMRect | undefined>> = Symbol("Bounds");
|
||||
|
||||
|
@ -106,7 +106,7 @@ export interface LayerOptions {
|
|||
color?: MaybeRefOrGetter<string>;
|
||||
/**
|
||||
* The layout of this layer's features.
|
||||
* When the layer is open in {@link game/player.PlayerData.tabs}, this is the content that is displayed.
|
||||
* When the layer is open in {@link game/player.Player.tabs}, this is the content that is displayed.
|
||||
*/
|
||||
display: MaybeGetter<Renderable>;
|
||||
/** An object of classes that should be applied to the display. */
|
||||
|
@ -125,12 +125,12 @@ export interface LayerOptions {
|
|||
minimizable?: MaybeRefOrGetter<boolean>;
|
||||
/**
|
||||
* The layout of this layer's features.
|
||||
* When the layer is open in {@link game/player.PlayerData.tabs}, but the tab is {@link Layer.minimized} this is the content that is displayed.
|
||||
* When the layer is open in {@link game/player.Player.tabs}, but the tab is {@link Layer.minimized} this is the content that is displayed.
|
||||
*/
|
||||
minimizedDisplay?: MaybeGetter<Renderable>;
|
||||
/**
|
||||
* Whether or not to force the go back button to be hidden.
|
||||
* If true, go back will be hidden regardless of {@link data/projInfo.allowGoBack}.
|
||||
* If true, go back will be hidden regardless of allowGoBack value in the project settings.
|
||||
*/
|
||||
forceHideGoBack?: MaybeRefOrGetter<boolean>;
|
||||
/**
|
||||
|
@ -157,7 +157,7 @@ export interface BaseLayer {
|
|||
on: OmitThisParameter<Emitter<LayerEvents>["on"]>;
|
||||
/** A function to emit a {@link LayerEvents} event to this layer. */
|
||||
emit: <K extends keyof LayerEvents>(...args: [K, ...Parameters<LayerEvents[K]>]) => void;
|
||||
/** A map of {@link FeatureNode}s present in this layer's {@link ContextComponent} component. */
|
||||
/** A map of {@link FeatureNode}s present in this layer's Context component. */
|
||||
nodes: Ref<Record<string, FeatureNode | undefined>>;
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ export interface Layer extends BaseLayer {
|
|||
color?: MaybeRef<string>;
|
||||
/**
|
||||
* The layout of this layer's features.
|
||||
* When the layer is open in {@link game/player.PlayerData.tabs}, this is the content that is displayed.
|
||||
* When the layer is open in {@link game/player.Player.tabs}, this is the content that is displayed.
|
||||
*/
|
||||
display: MaybeGetter<Renderable>;
|
||||
/** An object of classes that should be applied to the display. */
|
||||
|
@ -186,12 +186,12 @@ export interface Layer extends BaseLayer {
|
|||
minimizable?: MaybeRef<boolean>;
|
||||
/**
|
||||
* The layout of this layer's features.
|
||||
* When the layer is open in {@link game/player.PlayerData.tabs}, but the tab is {@link Layer.minimized} this is the content that is displayed.
|
||||
* When the layer is open in {@link game/player.Player.tabs}, but the tab is {@link Layer.minimized} this is the content that is displayed.
|
||||
*/
|
||||
minimizedDisplay?: MaybeGetter<Renderable>;
|
||||
/**
|
||||
* Whether or not to force the go back button to be hidden.
|
||||
* If true, go back will be hidden regardless of {@link data/projInfo.allowGoBack}.
|
||||
* If true, go back will be hidden regardless of allowGoBack value in the project settings.
|
||||
*/
|
||||
forceHideGoBack?: MaybeRef<boolean>;
|
||||
/**
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
import { globalBus } from "game/events";
|
||||
import { processGetter } from "util/computed";
|
||||
import { trackHover, VueFeature } from "util/vue";
|
||||
import { nextTick, Ref } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { CSSProperties, nextTick, Ref, ref, watch } from "vue";
|
||||
import Toast from "vue-toastification";
|
||||
import "vue-toastification/dist/index.css";
|
||||
|
||||
globalBus.on("setupVue", vue => vue.use(Toast));
|
||||
|
||||
/**
|
||||
* Gives a {@link CSSProperties} object that makes an object glow, to bring focus to it.
|
||||
* Gives a [CSSProperties](https://vuejs.org/api/utility-types.html#cssproperties) object that makes an object glow, to bring focus to it.
|
||||
* Default values are for a "soft" white notif effect.
|
||||
* @param color The color of the glow effect.
|
||||
* @param strength The strength of the glow effect - affects its spread.
|
||||
|
@ -20,7 +19,7 @@ export function getNotifyStyle(color = "white", strength = "8px") {
|
|||
borderColor: "rgba(0, 0, 0, 0.125)",
|
||||
boxShadow: `-4px -4px 4px rgba(0, 0, 0, 0.25) inset, 0 0 ${strength} ${color}`,
|
||||
zIndex: 1
|
||||
};
|
||||
} satisfies CSSProperties;
|
||||
}
|
||||
|
||||
/** Utility function to call {@link getNotifyStyle} with "high importance" parameters. */
|
||||
|
|
|
@ -67,7 +67,7 @@ export type State =
|
|||
| { [key: number]: State };
|
||||
|
||||
/**
|
||||
* A {@link Ref} that has been augmented with properties to allow it to be saved and loaded within the player save data object.
|
||||
* A [Ref](https://vuejs.org/api/reactivity-core.html#ref) that has been augmented with properties to allow it to be saved and loaded within the player save data object.
|
||||
*/
|
||||
export type Persistent<T extends State = State> = Ref<T> & {
|
||||
value: T;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { isVisible, Visibility } from "features/feature";
|
||||
import { displayResource, Resource } from "features/resources/resource";
|
||||
import Decimal, { DecimalSource } from "lib/break_eternity";
|
||||
import Decimal, { DecimalSource } from "util/bignum";
|
||||
import { MaybeGetter, processGetter } from "util/computed";
|
||||
import { createLazyProxy } from "util/proxies";
|
||||
import { joinJSX, Renderable } from "util/vue";
|
||||
|
@ -243,7 +243,7 @@ export function createCostRequirement<T extends CostRequirementOptions>(optionsF
|
|||
|
||||
/**
|
||||
* Utility function for creating a requirement that a specified vue feature is visible
|
||||
* @param feature The feature to check the visibility of
|
||||
* @param visibility The visibility ref to check
|
||||
*/
|
||||
export function createVisibilityRequirement(
|
||||
visibility: MaybeRef<Visibility | boolean>
|
||||
|
|
|
@ -77,7 +77,7 @@ export const hardResetSettings = (window.hardResetSettings = () => {
|
|||
|
||||
/**
|
||||
* Loads the player settings from localStorage.
|
||||
* Calls the {@link GlobalEvents.loadSettings} event for custom properties to be included.
|
||||
* Calls the {@link game/events.GlobalEvents.loadSettings} event for custom properties to be included.
|
||||
* Custom properties should be added by the file they relate to, so they won't be included if the file is tree shaken away.
|
||||
* Custom properties should also register the field to modify said setting using {@link registerSettingField}.
|
||||
*/
|
||||
|
|
|
@ -9,8 +9,8 @@ import { useRegisterSW } from "virtual:pwa-register/vue";
|
|||
import type { App as VueApp } from "vue";
|
||||
import { createApp, nextTick } from "vue";
|
||||
import { useToast } from "vue-toastification";
|
||||
import { globalBus } from "./game/events";
|
||||
import { startGameLoop } from "./game/gameLoop";
|
||||
import { globalBus } from "game/events";
|
||||
import { startGameLoop } from "game/gameLoop";
|
||||
|
||||
declare global {
|
||||
/**
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import { LoadablePlayerData } from "components/modals/SavesManager.vue";
|
||||
import player, { Player, stringifySave } from "game/player";
|
||||
import settings from "game/settings";
|
||||
import LZString from "lz-string";
|
||||
import { GalaxyApi, initGalaxy } from "unofficial-galaxy-sdk";
|
||||
import { ref } from "vue";
|
||||
import { decodeSave, loadSave, save, setupInitialStore } from "./save";
|
||||
import { decodeSave, LoadablePlayerData, loadSave, save, setupInitialStore } from "./save";
|
||||
|
||||
export const galaxy = ref<GalaxyApi>();
|
||||
export const conflictingSaves = ref<
|
||||
|
|
|
@ -3,8 +3,12 @@ import { NonPersistent } from "game/persistence";
|
|||
export const ProxyState = Symbol("ProxyState");
|
||||
export const AfterEvaluation = Symbol("AfterEvaluation");
|
||||
|
||||
// Takes a function that returns an object and pretends to be that object
|
||||
// Note that the object is lazily calculated
|
||||
/**
|
||||
* Makes a lazily evaluated object through the use of a Proxy
|
||||
* @param objectFunc Function that constructs the object to be proxies
|
||||
* @param baseObject An optional base object to pass to objectFunc, which all return properties will be assigned onto
|
||||
* @returns A proxy for the object created by objectFunc
|
||||
*/
|
||||
export function createLazyProxy<T extends object, S extends T>(
|
||||
objectFunc: (this: S, baseObject: S) => T,
|
||||
baseObject: S = {} as S
|
||||
|
@ -74,6 +78,11 @@ export function createLazyProxy<T extends object, S extends T>(
|
|||
}) as S & T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback to be called on a lazily evaluated proxy once its been evaluated.
|
||||
* @param maybeProxy A value that may be a lazily evaluated proxy
|
||||
* @param callback The callback to call once the proxy has been evaluated (or immediately, if the object is not a proxy)
|
||||
*/
|
||||
export function runAfterEvaluation<T extends object>(maybeProxy: T, callback: (object: T) => void) {
|
||||
if (AfterEvaluation in maybeProxy) {
|
||||
(maybeProxy[AfterEvaluation] as (callback: (object: T) => void) => void)(callback);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { LoadablePlayerData } from "components/modals/SavesManager.vue";
|
||||
import { fixOldSave, getInitialLayers } from "data/projEntry";
|
||||
import projInfo from "data/projInfo.json";
|
||||
import { globalBus } from "game/events";
|
||||
|
@ -9,6 +8,8 @@ import settings, { loadSettings } from "game/settings";
|
|||
import LZString from "lz-string";
|
||||
import { ref, shallowReactive } from "vue";
|
||||
|
||||
export type LoadablePlayerData = Omit<Partial<Player>, "id"> & { id: string; error?: unknown };
|
||||
|
||||
export function setupInitialStore(player: Partial<Player> = {}): Player {
|
||||
return Object.assign(
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ import { camelToKebab } from "./common";
|
|||
export const VueFeature = Symbol("VueFeature");
|
||||
|
||||
export type Renderable = JSX.Element | string;
|
||||
export type Wrapper = (el: () => Renderable) => Renderable;
|
||||
|
||||
export interface VueFeatureOptions {
|
||||
/** Whether this feature should be visible. */
|
||||
|
@ -37,7 +38,7 @@ export interface VueFeature {
|
|||
/** The components to render inside the vue feature */
|
||||
components: MaybeGetter<Renderable>[];
|
||||
/** The components to render wrapped around the vue feature */
|
||||
wrappers: ((el: () => Renderable) => Renderable)[];
|
||||
wrappers: Wrapper[];
|
||||
/** Used to identify Vue Features */
|
||||
[VueFeature]: true;
|
||||
}
|
||||
|
@ -53,7 +54,7 @@ export function vueFeatureMixin(
|
|||
classes: processGetter(options.classes),
|
||||
style: processGetter(options.style),
|
||||
components: component == null ? [] : [component],
|
||||
wrappers: [] as ((el: () => Renderable) => Renderable)[],
|
||||
wrappers: [] as Wrapper[],
|
||||
[VueFeature]: true
|
||||
} satisfies VueFeature;
|
||||
}
|
||||
|
@ -89,15 +90,11 @@ export function render(
|
|||
return wrapper?.(object) ?? object;
|
||||
}
|
||||
|
||||
export function renderRow(
|
||||
...objects: (VueFeature | MaybeGetter<Renderable>)[]
|
||||
): JSX.Element {
|
||||
export function renderRow(...objects: (VueFeature | MaybeGetter<Renderable>)[]): JSX.Element {
|
||||
return <Row>{objects.map(obj => render(obj))}</Row>;
|
||||
}
|
||||
|
||||
export function renderCol(
|
||||
...objects: (VueFeature | MaybeGetter<Renderable>)[]
|
||||
): JSX.Element {
|
||||
export function renderCol(...objects: (VueFeature | MaybeGetter<Renderable>)[]): JSX.Element {
|
||||
return <Col>{objects.map(obj => render(obj))}</Col>;
|
||||
}
|
||||
|
||||
|
@ -123,10 +120,7 @@ export function isJSXElement(element: unknown): element is JSX.Element {
|
|||
);
|
||||
}
|
||||
|
||||
export function setupHoldToClick(
|
||||
onClick?: Ref<((e?: MouseEvent | TouchEvent) => void) | undefined>,
|
||||
onHold?: Ref<VoidFunction | undefined>
|
||||
): {
|
||||
export function setupHoldToClick(callback: (e?: MouseEvent | TouchEvent) => void): {
|
||||
start: (e: MouseEvent | TouchEvent) => void;
|
||||
stop: VoidFunction;
|
||||
handleHolding: VoidFunction;
|
||||
|
@ -147,11 +141,7 @@ export function setupHoldToClick(
|
|||
}
|
||||
}
|
||||
function handleHolding() {
|
||||
if (onHold && onHold.value) {
|
||||
onHold.value();
|
||||
} else if (onClick && onClick.value) {
|
||||
onClick.value(event.value);
|
||||
}
|
||||
callback(event.value);
|
||||
}
|
||||
|
||||
onUnmounted(stop);
|
||||
|
|
|
@ -20,7 +20,7 @@ export interface Mark {
|
|||
/**
|
||||
* Creates a mark to the top left of the given element with the given options.
|
||||
* @param element The renderable feature to display the tooltip on.
|
||||
* @param options Mark options.
|
||||
* @param optionsFunc Mark options.
|
||||
*/
|
||||
export function addMark(
|
||||
element: VueFeature,
|
||||
|
|
|
@ -37,19 +37,19 @@
|
|||
import themes from "data/themes";
|
||||
import settings from "game/settings";
|
||||
import { Direction } from "util/common";
|
||||
import { render } from "util/vue";
|
||||
import type { Component } from "vue";
|
||||
import { MaybeGetter } from "util/computed";
|
||||
import { render, Renderable } from "util/vue";
|
||||
import type { Component, CSSProperties, MaybeRef, Ref } from "vue";
|
||||
import { computed, ref, unref } from "vue";
|
||||
import { Tooltip } from "./tooltip";
|
||||
|
||||
const props = defineProps<{
|
||||
pinned?: Tooltip["pinned"];
|
||||
display: Tooltip["display"];
|
||||
style?: Tooltip["style"];
|
||||
classes?: Tooltip["classes"];
|
||||
direction: Tooltip["direction"];
|
||||
xoffset?: Tooltip["xoffset"];
|
||||
yoffset?: Tooltip["yoffset"];
|
||||
pinned?: Ref<boolean>;
|
||||
display: MaybeGetter<Renderable>;
|
||||
style?: MaybeRef<CSSProperties>;
|
||||
classes?: MaybeRef<Record<string, boolean>>;
|
||||
direction: MaybeRef<Direction>;
|
||||
xoffset?: MaybeRef<string>;
|
||||
yoffset?: MaybeRef<string>;
|
||||
}>();
|
||||
|
||||
const isHovered = ref(false);
|
||||
|
|
|
@ -49,7 +49,7 @@ export interface Tooltip extends VueFeature {
|
|||
/**
|
||||
* Creates a tooltip on the given element with the given options.
|
||||
* @param element The renderable feature to display the tooltip on.
|
||||
* @param options Tooltip options.
|
||||
* @param optionsFunc Tooltip options.
|
||||
*/
|
||||
export function addTooltip(
|
||||
element: VueFeature,
|
||||
|
|
|
@ -4,10 +4,10 @@ import {
|
|||
setupUniqueIds,
|
||||
unwrapNodeRef
|
||||
} from "game/boards/board";
|
||||
import { Direction } from "util/common";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
import { Ref, ref } from "vue";
|
||||
import "../utils";
|
||||
import { Direction } from "util/common";
|
||||
|
||||
describe("Unwraps node refs", () => {
|
||||
test("Static value", () => expect(unwrapNodeRef(100, {})).toBe(100));
|
Loading…
Reference in a new issue