Skip to content

Commit

Permalink
Simplify Requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
ltouroumov committed Sep 3, 2023
1 parent 470252e commit cc07c16
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 143 deletions.
22 changes: 8 additions & 14 deletions components/viewer/ViewProjectObj.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,24 +50,18 @@ const objClass = (row: ProjectRow, obj: ProjectObj) => {
return { [className]: true };
};
const toggle = () => {
if (isEnabled.value) {
isSelected.value = !isSelected.value;
}
};
const store = useProjectStore();
const { selected } = useProjectRefs();
const condition = buildConditions(obj);
const isEnabled = ref<boolean>(condition(selected.value));
const isSelected = ref<boolean>(R.includes(obj.id, selected.value));
watch(selected, (newSelection) => {
isEnabled.value = condition(newSelection);
});
watch(isSelected, (newIsSelected) => {
store.setSelected(obj.id, newIsSelected);
});
const isEnabled = computed<boolean>(() => condition(selected.value));
const isSelected = computed<boolean>(() => R.includes(obj.id, selected.value));
const toggle = () => {
if (isEnabled.value) {
store.setSelected(obj.id, !isSelected.value);
}
};
</script>

<style lang="scss">
Expand Down
44 changes: 24 additions & 20 deletions components/viewer/ViewProjectRow.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
<template>
<div class="project-row" :class="{ hidden: !isVisible }">
<div class="row-meta">
<div class="row-title">{{ row.title }}</div>
<img
v-if="row.image"
class="row-image"
:src="row.image"
:alt="row.title"
/>
<div v-if="row.titleText" class="row-text">{{ row.titleText }}</div>
</div>
<div class="container-fluid p-0">
<div class="row g-2">
<ViewProjectObj
v-for="obj in row.objects"
:key="obj.id"
:obj="obj"
:row="row"
<div class="project-row-wrapper">
<div v-if="isVisible" class="project-row">
<div class="row-meta">
<div class="row-title">{{ row.title }}</div>
<img
v-if="row.image"
class="row-image"
:src="row.image"
:alt="row.title"
/>
<div v-if="row.titleText" class="row-text">{{ row.titleText }}</div>
</div>
<div class="container-fluid p-0">
<div class="row g-2">
<ViewProjectObj
v-for="obj in row.objects"
:key="obj.id"
:obj="obj"
:row="row"
/>
</div>
</div>
</div>
</div>
Expand All @@ -26,16 +28,18 @@
<script setup lang="ts">
import { computed } from 'vue';
import { buildConditions } from '~/composables/conditions';
import { ProjectRow } from '~/composables/project';
import { useProjectRefs } from '~/composables/store/project';
const { row } = defineProps<{
row: ProjectRow;
}>();
const { rowStatus } = useProjectRefs();
const { selected } = useProjectRefs();
const isVisible = computed(() => rowStatus.value[row.id] ?? true);
const condition = buildConditions(row);
const isVisible = computed(() => condition(selected.value));
</script>

<style lang="scss">
Expand Down
7 changes: 1 addition & 6 deletions components/viewer/ViewRequirement.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';

import { buildConditions } from '~/composables/conditions';
import { ConditionTerm } from '~/composables/project';
import { useProjectRefs, useProjectStore } from '~/composables/store/project';
Expand All @@ -20,10 +18,7 @@ const { getObject } = useProjectStore();
const { selected } = useProjectRefs();

const condition = buildConditions(req);
const isEnabled = ref<boolean>(condition(selected.value));
watch(selected, (newSelection) => {
isEnabled.value = condition(newSelection);
});
const isEnabled = computed<boolean>(() => condition(selected.value));
</script>

<style lang="scss">
Expand Down
14 changes: 3 additions & 11 deletions components/viewer/ViewScore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</template>

<script setup lang="ts">
import { ref, watch } from 'vue';
import { computed } from 'vue';
import { buildConditions } from '~/composables/conditions';
import { Score } from '~/composables/project';
Expand All @@ -23,16 +23,8 @@ const { score } = defineProps<{ score: Score }>();
const { selected } = useProjectRefs();
const isEnabled = ref<boolean>(true);
if (score.requireds.length > 0) {
const condition = buildConditions(score);
isEnabled.value = condition(selected.value);
watch(selected, (newSelection) => {
isEnabled.value = condition(newSelection);
});
}
const condition = buildConditions(score);
const isEnabled = computed<boolean>(() => condition(selected.value));
</script>

<style lang="scss">
Expand Down
3 changes: 2 additions & 1 deletion composables/conditions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const buildConditions = (item: HasRequirements): Term => {

return exec;
};

export const buildRootCondition = (terms: ConditionTerm[]): ConditionExec => {
const { code, deps } =
terms.length === 0 ? ALWAYS : AND(R.map(buildCondition, terms));
Expand Down Expand Up @@ -103,7 +104,7 @@ const OR = (terms: Condition[]): Condition => {
return combine(
R.pipe(
R.map((c) => `(${c})`),
R.join(' && '),
R.join(' || '),
),
terms,
);
Expand Down
92 changes: 1 addition & 91 deletions composables/store/project.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import { defineStore, storeToRefs } from 'pinia';
import * as R from 'ramda';
import { ComputedRef, Ref, computed } from 'vue';
import { ComputedRef, computed } from 'vue';

import { ConditionExec, buildRootCondition } from '~/composables/conditions';
import {
HasId,
HasRequirements,
PointType,
Project,
ProjectFile,
ProjectObj,
ProjectRow,
} from '~/composables/project';

type Deps = Record<string, string[]>;

export const useProjectStore = defineStore('project', () => {
const project = ref<ProjectFile | null>(null);
const selected = ref<string[]>([]);
Expand All @@ -30,9 +25,6 @@ export const useProjectStore = defineStore('project', () => {
const projectRows: ComputedRef<ProjectRow[]> = computed(
() => project.value?.data.rows ?? [],
);
const projectObjs: ComputedRef<ProjectObj[]> = computed(() =>
R.chain(R.prop('objects'), projectRows.value),
);

const getRow = computed(() => {
const rows: Record<string, ProjectRow> = R.fromPairs(
Expand Down Expand Up @@ -83,79 +75,6 @@ export const useProjectStore = defineStore('project', () => {
project.value = null;
};

function _buildConditions(seq: (HasId & HasRequirements)[]) {
return R.pipe(
R.filter(({ requireds }: HasRequirements) => !R.isEmpty(requireds)),
R.map((item: HasRequirements & HasId): [string, ConditionExec] => [
item.id,
buildRootCondition(item.requireds),
]),
R.fromPairs,
)(seq);
}

function _buildDeps(seq: Record<string, ConditionExec>): Deps {
return R.pipe(
R.toPairs,
R.chain(([id, { deps }]: [string, ConditionExec]) =>
R.map((dep: string): [string, string] => [dep, id], deps),
),
R.reduceBy(
(acc: string[], [_, dep]) => R.append(dep, acc),
[],
([dep, _]) => dep,
),
)(seq);
}

const rowConditions = computed(() => {
console.log('rebuild rowConditions');
return _buildConditions(projectRows.value);
});
const rowDeps: ComputedRef<Deps> = computed(() => {
console.log('rebuild rowDeps');
return _buildDeps(rowConditions.value);
});
const rowStatus: Ref<Record<string, boolean>> = ref({});

// const objConditions = computed(() => _buildConditions(projectObjs.value));
// const objDeps = computed(() => _buildDeps(objConditions.value));

watch(projectRows, (newRows) => {
console.log('rebuild rowStatus defaults');

const _selected: string[] = selected.value;

rowStatus.value = R.pipe(
R.map((row: ProjectRow): [string, boolean] => {
if (row.id in rowConditions.value) {
const { exec } = rowConditions.value[row.id];
return [row.id, exec(_selected)];
} else {
return [row.id, true];
}
}),
R.fromPairs,
)(newRows);
});

watch(selected, (newValue, oldValue) => {
const _deps = rowDeps.value;
const _cond = rowConditions.value;
const updated = R.symmetricDifference(newValue, oldValue);

const _status: Record<string, boolean> = {};
R.pipe(
R.chain((id: string) => _deps[id] ?? []),
R.forEach((dep: string) => {
const { exec } = _cond[dep];
_status[dep] = exec(newValue);
}),
)(updated);

rowStatus.value = { ...rowStatus.value, ..._status };
});

const setSelected = (id: string, isSelected: boolean) => {
if (isSelected) {
selected.value = R.append(id, selected.value);
Expand All @@ -164,14 +83,9 @@ export const useProjectStore = defineStore('project', () => {
}
};

const setRowStatus = (id: string, status: boolean) => {
rowStatus.value = { ...rowStatus.value, [id]: status };
};

return {
project,
projectRows,
projectObjs,
backpack,
selected,
pointTypes,
Expand All @@ -182,10 +96,6 @@ export const useProjectStore = defineStore('project', () => {
getObject,
getObjectRow,
setSelected,
rowConditions,
rowDeps,
rowStatus,
setRowStatus,
};
});

Expand Down
3 changes: 3 additions & 0 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ export default defineNuxtConfig({
app: {
baseURL: '/cyoa-editor/',
buildAssetsDir: 'assets',
head: {
title: 'Interactive CYOA',
},
},
imports: { autoImport: true },
css: [
Expand Down

0 comments on commit cc07c16

Please sign in to comment.