update
This commit is contained in:
parent
c91e9d1040
commit
28b3b9dc24
18
index.html
18
index.html
@ -1,13 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<script>
|
||||
document.documentElement.classList.toggle(
|
||||
'dark',
|
||||
localStorage.theme === 'dark' ||
|
||||
(!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches),
|
||||
)
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div class="bg-surface-0 dark:bg-surface-900 min-h-screen p-4 flex flex-col" id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -13,11 +13,16 @@
|
||||
"format": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"fp-ts": "^2.16.9",
|
||||
"pinia": "^2.3.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"primevue": "^4.2.5",
|
||||
"ts-pattern": "^5.6.0",
|
||||
"uuid": "^11.0.3",
|
||||
"vue": "^3.5.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tsconfig/node22": "^22.0.0",
|
||||
"@types/node": "^22.10.2",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
|
||||
62
src/App.vue
62
src/App.vue
@ -1,12 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import DatePicker from 'primevue/datepicker'
|
||||
import { ref } from 'vue'
|
||||
import { Button, } from 'primevue'
|
||||
import TreeNav from './components/TreeNav.vue'
|
||||
import FilterDetail from './components/FilterDetail.vue'
|
||||
import Info from './components/Info.vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import type { TreeNode } from 'primevue/treenode'
|
||||
import * as O from 'fp-ts/Option'
|
||||
import * as A from 'fp-ts/lib/Array';
|
||||
import { pipe } from 'fp-ts/function'
|
||||
import * as uuid from 'uuid';
|
||||
import type { Filter, FilterConfig } from './models'
|
||||
|
||||
const date = ref()
|
||||
const darkMode = ref(document.documentElement.classList.contains('dark'))
|
||||
|
||||
const icon = computed(() => `pi pi-${darkMode.value ? "moon" : "sun"}`)
|
||||
|
||||
watch(darkMode, (dark) => {
|
||||
document.documentElement.classList.toggle(
|
||||
'dark',
|
||||
dark
|
||||
)
|
||||
localStorage.theme = dark ? 'dark' : 'light'
|
||||
})
|
||||
function onNodeSelect(node: TreeNode) {
|
||||
}
|
||||
|
||||
function onNodeUnselect(node: TreeNode) {
|
||||
}
|
||||
|
||||
let defaultFilters: Filter[] = [
|
||||
{ type: 'leaf', id: uuid.v4(), name: "", show: true, enabled: true, rule: {} },
|
||||
{
|
||||
type: 'group', id: uuid.v4(), name: "", enabled: true, rule: {}, filters: [
|
||||
{ type: 'leaf', id: uuid.v4(), name: "", show: true, enabled: true, rule: {} }
|
||||
]
|
||||
}
|
||||
]
|
||||
const filters = ref(pipe(
|
||||
localStorage.getItem("filters"),
|
||||
O.fromNullable,
|
||||
O.map((value): FilterConfig => JSON.parse(value)),
|
||||
O.map(value => value.filters),
|
||||
O.getOrElse(() => defaultFilters),
|
||||
))
|
||||
const selectedFilter = ref<Filter>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex items-center justify-center min-h-screen">
|
||||
<DatePicker v-model="date" />
|
||||
<div class="flex flex-row gap-2 items-center flex-grow-0">
|
||||
<article class="prose dark:prose-invert">
|
||||
<h1>POE2 Loot Filter Config</h1>
|
||||
</article><Button :icon @click="darkMode = !darkMode" severity="secondary" variant="outlined" rounded />
|
||||
</div>
|
||||
<div class="flex flex-1 flex-row">
|
||||
<div class="flex-1">
|
||||
<TreeNav :filters @nodeSelect="selectedFilter = $event.data" @nodeUnselect="selectedFilter = undefined" />
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<FilterDetail v-if="selectedFilter" :filter="selectedFilter" />
|
||||
<Info v-else />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
3
src/base.css
Normal file
3
src/base.css
Normal file
@ -0,0 +1,3 @@
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
19
src/components/FilterDetail.vue
Normal file
19
src/components/FilterDetail.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import type { Filter } from '@/models';
|
||||
import { ref, watchEffect } from 'vue'
|
||||
import { ToggleButton, SelectButton, Card } from 'primevue'
|
||||
const props = defineProps<{
|
||||
filter: Filter
|
||||
}>()
|
||||
|
||||
watchEffect(() => {
|
||||
console.log(props.filter);
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="prose dark:prose-invert">
|
||||
<h2>Filter detail:</h2>
|
||||
</article>
|
||||
<ToggleButton v-if="filter.type === 'leaf'" v-model="filter.show" onLabel="Show" offLabel="Hide" />
|
||||
</template>
|
||||
10
src/components/Info.vue
Normal file
10
src/components/Info.vue
Normal file
@ -0,0 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<article class="prose dark:prose-invert">
|
||||
<h2>How to use:</h2>
|
||||
</article>
|
||||
</template>
|
||||
24
src/components/TreeNav.vue
Normal file
24
src/components/TreeNav.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import type { Filter, FilterConfig } from '../models';
|
||||
import { filterToTreeNode } from '../services/filter';
|
||||
import * as A from 'fp-ts/lib/Array';
|
||||
import { pipe } from 'fp-ts/function'
|
||||
import { Tree } from 'primevue'
|
||||
|
||||
const props = defineProps<{
|
||||
filters: Filter[]
|
||||
}>()
|
||||
|
||||
const nodes = computed(() => pipe(
|
||||
props.filters,
|
||||
A.map(filterToTreeNode),
|
||||
))
|
||||
const selectedKey = ref()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Tree :value="nodes" v-model:selectionKeys="selectedKey" selectionMode="single">
|
||||
|
||||
</Tree>
|
||||
</template>
|
||||
@ -1,6 +1,8 @@
|
||||
import PrimeVue from 'primevue/config'
|
||||
import './style.css'
|
||||
import './assets/tailwind.css'
|
||||
import 'primeicons/primeicons.css'
|
||||
import './base.css'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
@ -10,9 +12,7 @@ const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(PrimeVue, {
|
||||
theme: {
|
||||
preset: 'none',
|
||||
},
|
||||
theme: 'none'
|
||||
})
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
62
src/models/index.ts
Normal file
62
src/models/index.ts
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
interface _Filter {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
rule: FilterRule;
|
||||
}
|
||||
|
||||
export interface FilterConfig {
|
||||
filters: Filter[]
|
||||
}
|
||||
|
||||
export type FilterLeaf = _Filter & {
|
||||
type: 'leaf';
|
||||
show: boolean;
|
||||
}
|
||||
|
||||
export type FilterGroup = _Filter & {
|
||||
type: 'group';
|
||||
filters: Filter[]
|
||||
}
|
||||
|
||||
export type Filter = FilterLeaf | FilterGroup;
|
||||
|
||||
export type ItemClass = any; // Replace with actual type definition
|
||||
export type ItemBaseType = any; // Replace with actual type definition
|
||||
export type Op = any; // Replace with actual type definition
|
||||
export type Level = RangedNumber<1, 100>; // Replace with actual type definition
|
||||
export type ItemRarity = 'Normal' | 'Magic' | 'Rare' | 'Unique'; // Replace with actual type definition
|
||||
export type Color = any; // Replace with actual type definition
|
||||
export type GameColor = any; // Replace with actual type definition
|
||||
export type MinimapIconShape = any; // Replace with actual type definition
|
||||
|
||||
export interface RangedNumber<T extends number, U extends number> {
|
||||
value: number;
|
||||
min: T;
|
||||
max: U;
|
||||
}
|
||||
|
||||
export interface FilterRule {
|
||||
class?: ItemClass[];
|
||||
base_type?: ItemBaseType[];
|
||||
area_level?: [Op, Level];
|
||||
drop_level?: [Op, Level];
|
||||
item_level?: [Op, Level];
|
||||
rarity?: [Op, ItemRarity];
|
||||
sockets?: [Op, number];
|
||||
quality?: [Op, number];
|
||||
stack_size?: [Op, number];
|
||||
|
||||
// waystones
|
||||
waystone_tier?: [Op, RangedNumber<1, 16>];
|
||||
|
||||
// effects
|
||||
set_font_size?: RangedNumber<1, 45>;
|
||||
set_text_color?: Color;
|
||||
set_border_color?: Color;
|
||||
set_background_color?: Color;
|
||||
play_alert_sound?: [RangedNumber<1, 16>, RangedNumber<0, 300>];
|
||||
play_effect?: GameColor;
|
||||
minimap_icon?: [RangedNumber<0, 2>, GameColor, MinimapIconShape];
|
||||
}
|
||||
26
src/services/filter.ts
Normal file
26
src/services/filter.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import type { Filter } from '@/models'
|
||||
import type { TreeNode } from 'primevue/treenode'
|
||||
import { match } from 'ts-pattern'
|
||||
|
||||
export function filterToTreeNode(filter: Filter): TreeNode {
|
||||
let children = match(filter)
|
||||
.with({ type: 'leaf' }, (filter) => undefined)
|
||||
.with({ type: 'group' }, (filter) => filter.filters.map(filterToTreeNode))
|
||||
.exhaustive()
|
||||
|
||||
let icon = match(filter)
|
||||
.with({ type: 'leaf' }, () => "file")
|
||||
.with({ type: 'group' }, () => "folder")
|
||||
.exhaustive()
|
||||
return {
|
||||
key: filter.id,
|
||||
data: filter,
|
||||
label: filter.id,
|
||||
children,
|
||||
icon: `pi pi-${icon}`
|
||||
}
|
||||
}
|
||||
|
||||
export function treeNodeToFilter(node: TreeNode): Filter {
|
||||
return node.data;
|
||||
}
|
||||
@ -53,22 +53,22 @@
|
||||
* should be;
|
||||
* :root[class="app-dark"] {
|
||||
*/
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--p-primary-color: var(--p-primary-400);
|
||||
--p-primary-contrast-color: var(--p-surface-900);
|
||||
--p-primary-hover-color: var(--p-primary-300);
|
||||
--p-primary-active-color: var(--p-primary-200);
|
||||
--p-content-border-color: var(--p-surface-700);
|
||||
--p-content-hover-background: var(--p-surface-800);
|
||||
--p-content-hover-color: var(--p-surface-0);
|
||||
--p-highlight-background: color-mix(in srgb, var(--p-primary-400), transparent 84%);
|
||||
--p-highlight-color: rgba(255, 255, 255, 0.87);
|
||||
--p-highlight-focus-background: color-mix(in srgb, var(--p-primary-400), transparent 76%);
|
||||
--p-highlight-focus-color: rgba(255, 255, 255, 0.87);
|
||||
--p-text-color: var(--p-surface-0);
|
||||
--p-text-hover-color: var(--p-surface-0);
|
||||
--p-text-muted-color: var(--p-surface-400);
|
||||
--p-text-hover-muted-color: var(--p-surface-300);
|
||||
}
|
||||
/* @media (prefers-color-scheme: dark) { */
|
||||
:root[class='dark'] {
|
||||
--p-primary-color: var(--p-primary-400);
|
||||
--p-primary-contrast-color: var(--p-surface-900);
|
||||
--p-primary-hover-color: var(--p-primary-300);
|
||||
--p-primary-active-color: var(--p-primary-200);
|
||||
--p-content-border-color: var(--p-surface-700);
|
||||
--p-content-hover-background: var(--p-surface-800);
|
||||
--p-content-hover-color: var(--p-surface-0);
|
||||
--p-highlight-background: color-mix(in srgb, var(--p-primary-400), transparent 84%);
|
||||
--p-highlight-color: rgba(255, 255, 255, 0.87);
|
||||
--p-highlight-focus-background: color-mix(in srgb, var(--p-primary-400), transparent 76%);
|
||||
--p-highlight-focus-color: rgba(255, 255, 255, 0.87);
|
||||
--p-text-color: var(--p-surface-0);
|
||||
--p-text-hover-color: var(--p-surface-0);
|
||||
--p-text-muted-color: var(--p-surface-400);
|
||||
--p-text-hover-muted-color: var(--p-surface-300);
|
||||
}
|
||||
/* } */
|
||||
|
||||
@ -1,7 +1,17 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
import primeui from 'tailwindcss-primeui'
|
||||
import typography from '@tailwindcss/typography'
|
||||
import defaultTheme from 'tailwindcss/defaultTheme'
|
||||
|
||||
export default {
|
||||
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||
plugins: [primeui],
|
||||
darkMode: 'selector',
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['InterVariable', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [primeui, typography],
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user