Merge remote-tracking branch 'template/main'
This commit is contained in:
commit
f0ba5a69f5
15 changed files with 128 additions and 50 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.2.0] - 2022-03-27
|
||||
### Added
|
||||
- Particles feature
|
||||
- Collapsible layout component
|
||||
- Utility function for splitting off the first from the list of features that meets a given filter
|
||||
### Changed
|
||||
- **BREAKING** Reworked most of the code from Links into a generic Context component that manages the positions of features in the DOM
|
||||
- Updated vue-cli and TS dependencies
|
||||
- Challenges cannot be started when maxed, and `canStart` now defaults to `true`
|
||||
- onClick listeners on various features now get passed a MouseEvent or TouchEvent when possible
|
||||
- Minor style changes to Milestones, most notably removing min-height
|
||||
### Fixed
|
||||
- Buyables didn't support CoercableComponents for displays
|
||||
- TreeNodes would have a double glow effect on hover
|
||||
### Removed
|
||||
- Unused mousemove listener attached to App.vue
|
||||
|
||||
## [0.1.4] - 2022-03-13
|
||||
### Added
|
||||
- You can now access this.on() from within a createLayer function (and other BaseLayer properties)
|
||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "profectus",
|
||||
"version": "0.1.4",
|
||||
"version": "0.2.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "profectus",
|
||||
"version": "0.1.4",
|
||||
"version": "0.2.0",
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "profectus",
|
||||
"version": "0.1.4",
|
||||
"version": "0.2.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "vue-cli-service serve",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div id="modal-root" :style="theme" />
|
||||
<div class="app" @mousemove="updateMouse" :style="theme" :class="{ useHeader }">
|
||||
<div class="app" :style="theme" :class="{ useHeader }">
|
||||
<Nav v-if="useHeader" />
|
||||
<Game />
|
||||
<TPS v-if="unref(showTPS)" />
|
||||
|
@ -24,10 +24,6 @@ import themes from "./data/themes";
|
|||
import settings, { gameComponents } from "./game/settings";
|
||||
import "./main.css";
|
||||
|
||||
function updateMouse(/* event */) {
|
||||
// TODO use event to update mouse position for particles
|
||||
}
|
||||
|
||||
const useHeader = projInfo.useHeader;
|
||||
const theme = computed(() => themes[settings.theme].variables);
|
||||
const showTPS = toRef(settings, "showTPS");
|
||||
|
|
|
@ -24,11 +24,11 @@ const observerOptions = {
|
|||
provide(RegisterNodeInjectionKey, (id, element) => {
|
||||
const observer = new MutationObserver(() => updateNode(id));
|
||||
observer.observe(element, observerOptions);
|
||||
nodes.value[id] = { element, observer };
|
||||
nodes.value[id] = { element, observer, rect: element.getBoundingClientRect() };
|
||||
nextTick(() => updateNode(id));
|
||||
});
|
||||
provide(UnregisterNodeInjectionKey, id => {
|
||||
nodes.value[id]?.observer?.disconnect();
|
||||
nodes.value[id]?.observer.disconnect();
|
||||
nodes.value[id] = undefined;
|
||||
});
|
||||
provide(NodesInjectionKey, nodes);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="tabs-container">
|
||||
<div class="tabs-container" :class="{ useHeader }">
|
||||
<div v-for="(tab, index) in tabs" :key="index" class="tab" :ref="`tab-${index}`">
|
||||
<Nav v-if="index === 0 && !useHeader" />
|
||||
<div class="inner-tab">
|
||||
|
@ -29,9 +29,8 @@ const layerKeys = computed(() => Object.keys(layers));
|
|||
const useHeader = projInfo.useHeader;
|
||||
|
||||
function gatherLayerProps(layer: GenericLayer) {
|
||||
const { display, minimized, minWidth, name, color, style, classes, links, minimizable, nodes } =
|
||||
layer;
|
||||
return { display, minimized, minWidth, name, color, style, classes, links, minimizable, nodes };
|
||||
const { display, minimized, minWidth, name, color, style, classes, minimizable, nodes } = layer;
|
||||
return { display, minimized, minWidth, name, color, style, classes, minimizable, nodes };
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -44,6 +43,11 @@ function gatherLayerProps(layer: GenericLayer) {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.tabs-container:not(.useHeader) {
|
||||
width: calc(100vw - 50px);
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
|
|
|
@ -147,12 +147,12 @@ function openDiscord() {
|
|||
}
|
||||
|
||||
.overlay-nav {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.overlay-nav > * {
|
||||
|
|
51
src/components/layout/Collapsible.vue
Normal file
51
src/components/layout/Collapsible.vue
Normal file
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<Col style="width: 100%">
|
||||
<button @click="collapsed.value = !collapsed.value" class="feature collapsible-toggle">
|
||||
<component :is="displayComponent" />
|
||||
</button>
|
||||
<component v-if="!collapsed.value" :is="contentComponent" />
|
||||
</Col>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { CoercableComponent } from "features/feature";
|
||||
import { coerceComponent } from "util/vue";
|
||||
import { computed, Ref } from "vue";
|
||||
import Col from "./Column.vue";
|
||||
|
||||
const props = defineProps<{
|
||||
collapsed: Ref<boolean>;
|
||||
display: CoercableComponent;
|
||||
content: CoercableComponent;
|
||||
}>();
|
||||
|
||||
const displayComponent = computed(() => coerceComponent(props.display));
|
||||
const contentComponent = computed(() => coerceComponent(props.content));
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.collapsible-toggle {
|
||||
width: calc(100% - 10px);
|
||||
background: var(--raised-background);
|
||||
padding: var(--feature-margin);
|
||||
color: var(--foreground);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:deep(.col) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mergeAdjacent .collapsible-toggle {
|
||||
border: 0;
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
|
||||
:deep(.mergeAdjacent .feature:not(.dontMerge):first-child) {
|
||||
border-top-left-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
}
|
||||
</style>
|
|
@ -26,13 +26,12 @@ const props = toRefs(_props);
|
|||
const startPosition = computed(() => {
|
||||
const rect = props.startNode.value.rect;
|
||||
const boundingRect = props.boundingRect.value;
|
||||
const position =
|
||||
rect && boundingRect
|
||||
? {
|
||||
x: rect.x + rect.width / 2 - boundingRect.x,
|
||||
y: rect.y + rect.height / 2 - boundingRect.y
|
||||
}
|
||||
: { x: 0, y: 0 };
|
||||
const position = boundingRect
|
||||
? {
|
||||
x: rect.x + rect.width / 2 - boundingRect.x,
|
||||
y: rect.y + rect.height / 2 - boundingRect.y
|
||||
}
|
||||
: { x: 0, y: 0 };
|
||||
if (props.link.value.offsetStart) {
|
||||
position.x += props.link.value.offsetStart.x;
|
||||
position.y += props.link.value.offsetStart.y;
|
||||
|
@ -43,13 +42,12 @@ const startPosition = computed(() => {
|
|||
const endPosition = computed(() => {
|
||||
const rect = props.endNode.value.rect;
|
||||
const boundingRect = props.boundingRect.value;
|
||||
const position =
|
||||
rect && boundingRect
|
||||
? {
|
||||
x: rect.x + rect.width / 2 - boundingRect.x,
|
||||
y: rect.y + rect.height / 2 - boundingRect.y
|
||||
}
|
||||
: { x: 0, y: 0 };
|
||||
const position = boundingRect
|
||||
? {
|
||||
x: rect.x + rect.width / 2 - boundingRect.x,
|
||||
y: rect.y + rect.height / 2 - boundingRect.y
|
||||
}
|
||||
: { x: 0, y: 0 };
|
||||
if (props.link.value.offsetEnd) {
|
||||
position.x += props.link.value.offsetEnd.x;
|
||||
position.y += props.link.value.offsetEnd.y;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { Link } from "features/links/links";
|
||||
import { NodesInjectionKey } from "game/layers";
|
||||
import { FeatureNode, NodesInjectionKey } from "game/layers";
|
||||
import { computed, inject, nextTick, onMounted, ref, toRef } from "vue";
|
||||
import LinkVue from "./Link.vue";
|
||||
|
||||
|
@ -43,9 +43,8 @@ function updateNodes() {
|
|||
isDirty = false;
|
||||
nextTick(() => {
|
||||
boundingRect.value = resizeListener.value?.getBoundingClientRect();
|
||||
Object.values(nodes.value).forEach(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
node => (node!.rect = node?.element.getBoundingClientRect())
|
||||
(Object.values(nodes.value) as FeatureNode[]).forEach(
|
||||
node => (node.rect = node.element.getBoundingClientRect())
|
||||
);
|
||||
isDirty = true;
|
||||
});
|
||||
|
|
|
@ -102,13 +102,10 @@ export default defineComponent({
|
|||
min-width: 120px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
min-height: 75px;
|
||||
background-color: var(--locked);
|
||||
border-width: 4px;
|
||||
border-radius: 5px;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.milestone.done {
|
||||
|
@ -116,12 +113,12 @@ export default defineComponent({
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.milestone >>> .equal-spaced {
|
||||
.milestone :deep(.equal-spaced) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.milestone >>> .equal-spaced > * {
|
||||
.milestone :deep(.equal-spaced > *) {
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -35,7 +35,7 @@ import { Emitters } from "tsparticles-plugin-emitters/Emitters";
|
|||
import { EmitterContainer } from "tsparticles-plugin-emitters/EmitterContainer";
|
||||
import { defineComponent, inject, nextTick, onMounted, PropType, ref } from "vue";
|
||||
import { ParticlesComponent } from "particles.vue3";
|
||||
import { NodesInjectionKey } from "game/layers";
|
||||
import { FeatureNode, NodesInjectionKey } from "game/layers";
|
||||
|
||||
// TODO get typing support on the Particles component
|
||||
export default defineComponent({
|
||||
|
@ -93,9 +93,8 @@ export default defineComponent({
|
|||
nextTick(() => {
|
||||
if (resizeListener.value != null && props.onContainerResized) {
|
||||
// TODO don't overlap with Links.vue
|
||||
Object.values(nodes.value).forEach(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
node => (node!.rect = node?.element.getBoundingClientRect())
|
||||
(Object.values(nodes.value) as FeatureNode[]).forEach(
|
||||
node => (node.rect = node.element.getBoundingClientRect())
|
||||
);
|
||||
props.onContainerResized(resizeListener.value.getBoundingClientRect());
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
...unref(classes)
|
||||
}"
|
||||
>
|
||||
<button
|
||||
<div
|
||||
@click="click"
|
||||
@mousedown="start"
|
||||
@mouseleave="stop"
|
||||
|
@ -31,7 +31,7 @@
|
|||
]"
|
||||
>
|
||||
<component :is="unref(comp)" />
|
||||
</button>
|
||||
</div>
|
||||
<MarkNode :mark="unref(mark)" />
|
||||
<Node :id="id" />
|
||||
</Tooltip>
|
||||
|
@ -156,7 +156,7 @@ export default defineComponent({
|
|||
margin: 0 10px 0 10px;
|
||||
}
|
||||
|
||||
.treeNode button {
|
||||
.treeNode > *:first-child {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 2px solid rgba(0, 0, 0, 0.125);
|
||||
|
@ -166,6 +166,7 @@ export default defineComponent({
|
|||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: -4px -4px 4px rgba(0, 0, 0, 0.25) inset, 0px 0px 20px var(--background);
|
||||
text-transform: capitalize;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.treeNode.small {
|
||||
|
@ -173,7 +174,7 @@ export default defineComponent({
|
|||
width: 60px;
|
||||
}
|
||||
|
||||
.treeNode.small button {
|
||||
.treeNode.small > *:first-child {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ import { persistent, PersistentRef } from "./persistence";
|
|||
import player from "./player";
|
||||
|
||||
export interface FeatureNode {
|
||||
rect?: DOMRect;
|
||||
observer?: MutationObserver;
|
||||
rect: DOMRect;
|
||||
observer: MutationObserver;
|
||||
element: HTMLElement;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import {
|
|||
Component as ComponentKey,
|
||||
GatherProps,
|
||||
GenericComponent,
|
||||
JSXFunction
|
||||
JSXFunction,
|
||||
Visibility
|
||||
} from "features/feature";
|
||||
import {
|
||||
Component,
|
||||
|
@ -121,6 +122,21 @@ export function setupHoldToClick(
|
|||
return { start, stop, handleHolding };
|
||||
}
|
||||
|
||||
export function getFirstFeature<T extends { visibility: ProcessedComputable<Visibility> }>(
|
||||
features: T[],
|
||||
filter: (feature: T) => boolean
|
||||
): { firstFeature: Ref<T | undefined>; hiddenFeatures: Ref<T[]> } {
|
||||
const filteredFeatures = computed(() =>
|
||||
features.filter(
|
||||
feature => unref(feature.visibility) === Visibility.Visible && filter(feature)
|
||||
)
|
||||
);
|
||||
return {
|
||||
firstFeature: computed(() => filteredFeatures.value[0]),
|
||||
hiddenFeatures: computed(() => filteredFeatures.value.slice(1))
|
||||
};
|
||||
}
|
||||
|
||||
export function computeComponent(
|
||||
component: Ref<ProcessedComputable<CoercableComponent>>,
|
||||
defaultWrapper = "div"
|
||||
|
|
Loading…
Reference in a new issue