mirror of
https://forgejo.merr.is/annika/isl-vue3.git
synced 2025-12-10 12:04:19 -05:00
Type Issues Fixed and First Pass New Item Form
This commit is contained in:
parent
a1aa171bb1
commit
aafd3c19de
15 changed files with 422 additions and 164 deletions
|
|
@ -22,6 +22,10 @@ COPY . .
|
|||
|
||||
# [optional] tests & build
|
||||
ENV NODE_ENV=production
|
||||
# I can't run the type checking because of some sort of issue with
|
||||
# bun and vue-tsc.
|
||||
# see https://github.com/oven-sh/bun/issues/4754
|
||||
# RUN bunx --bun vue-tsc --build --force
|
||||
RUN bunx --bun vite build
|
||||
|
||||
# Copy the distribution folder into the final image.
|
||||
|
|
|
|||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -18,7 +18,6 @@
|
|||
"axios": "^1.6.5",
|
||||
"axios-retry": "^4.0.0",
|
||||
"pinia": "^2.1.7",
|
||||
"sass": "^1.69.7",
|
||||
"vue": "^3.3.11",
|
||||
"vue-router": "^4.2.5",
|
||||
"vuetify": "^3.4.10"
|
||||
|
|
@ -43,6 +42,8 @@
|
|||
"typescript": "~5.3.0",
|
||||
"vite": "^5.0.10",
|
||||
"vitest": "^1.0.4",
|
||||
"vue-tsc": "^1.8.25"
|
||||
"vue-tsc": "^1.8.25",
|
||||
"sass": "^1.69.7",
|
||||
"vite-plugin-vuetify": "^2.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
160
src/components/NewItemForm.vue
Normal file
160
src/components/NewItemForm.vue
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
type EventItemListing = {
|
||||
name: string
|
||||
id: number
|
||||
}
|
||||
|
||||
const firstName = ref('')
|
||||
const itemType = ref(0)
|
||||
const itemName = ref('')
|
||||
const iconURL = ref('')
|
||||
const minPower = ref(0)
|
||||
const maxPower = ref(0)
|
||||
const rarity = ref(0)
|
||||
const origin = ref('')
|
||||
const tooltip = ref('')
|
||||
const isEventItem = ref(false)
|
||||
|
||||
const eventItems = [
|
||||
{
|
||||
name: 'Blessing Power',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
name: 'Intimacy Power',
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
name: 'Fellow Power',
|
||||
id: 3
|
||||
}
|
||||
]
|
||||
const rarities = [
|
||||
{
|
||||
name: 'Green',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
name: 'Blue',
|
||||
id: 2
|
||||
},
|
||||
{
|
||||
name: 'Purple',
|
||||
id: 3
|
||||
},
|
||||
{
|
||||
name: 'Yellow',
|
||||
id: 4
|
||||
},
|
||||
{
|
||||
name: 'Red',
|
||||
id: 5
|
||||
}
|
||||
]
|
||||
const yesNo = [
|
||||
{
|
||||
name: 'Yes',
|
||||
id: 1
|
||||
},
|
||||
{
|
||||
name: 'No',
|
||||
id: 0
|
||||
}
|
||||
]
|
||||
|
||||
// Yes, I do want any, I don't know WHAT they have typed, but this rule is only checking that they typed SOMETHING.
|
||||
const requiredField = (v: any) => (v ? true : 'This field is required.')
|
||||
const textRules = [requiredField]
|
||||
const minPowerRules = [
|
||||
requiredField,
|
||||
(v: number) =>
|
||||
v <= maxPower.value ? true : 'Minimum power must be less than or equal to maximum power.'
|
||||
]
|
||||
const maxPowerRules = [
|
||||
requiredField,
|
||||
(v: number) =>
|
||||
v >= minPower.value ? true : 'Maximum power must be greater than or equal to minimum power.'
|
||||
]
|
||||
const listToProps = (item: EventItemListing) => ({ title: item.name })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row justify="center">
|
||||
<v-col lg="8" sm="12">
|
||||
<v-card fluid>
|
||||
<v-card-title>Add New Item</v-card-title>
|
||||
<v-card-item>
|
||||
<v-form @submit.prevent>
|
||||
<v-sheet>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-select
|
||||
:items="eventItems"
|
||||
:item-props="listToProps"
|
||||
label="Item Type"
|
||||
></v-select>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-text-field
|
||||
v-model="itemName"
|
||||
:rules="textRules"
|
||||
label="Item Name"
|
||||
></v-text-field>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-text-field
|
||||
v-model="iconURL"
|
||||
:rules="textRules"
|
||||
label="Image URL"
|
||||
disabled
|
||||
></v-text-field>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col class="pl-0">
|
||||
<v-text-field
|
||||
v-model="minPower"
|
||||
:rules="minPowerRules"
|
||||
label="Minimum Power"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
<v-col class="pr-0">
|
||||
<v-text-field
|
||||
v-model="maxPower"
|
||||
:rules="maxPowerRules"
|
||||
label="Maximum Power"
|
||||
></v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-select :items="rarities" :item-props="listToProps" label="Rarity"></v-select>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-text-field v-model="origin" :rules="textRules" label="Origin"></v-text-field>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-text-field
|
||||
v-model="tooltip"
|
||||
:rules="textRules"
|
||||
label="Tooltip"
|
||||
></v-text-field>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-select
|
||||
:items="yesNo"
|
||||
:item-props="listToProps"
|
||||
label="Is From An Event?"
|
||||
></v-select>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-sheet>
|
||||
<v-btn type="submit" block>Submit</v-btn>
|
||||
</v-form>
|
||||
</v-card-item>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
|
@ -1,72 +1,82 @@
|
|||
<script setup lang="ts">
|
||||
import { usePowerItems } from '@/stores/powerItems'
|
||||
import type { PowerItem } from '@/types/PowerItem';
|
||||
import type { DataTableHeader } from '@/types/DataTableHeader'
|
||||
import type { PowerItem } from '@/types/PowerItem'
|
||||
import type { Ref } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useDisplay } from 'vuetify'
|
||||
import type { VDataTable } from 'vuetify/components'
|
||||
|
||||
type SortItem = { key: string, order?: boolean | 'asc' | 'desc' }
|
||||
type ReadonlyHeaders = VDataTable['headers']
|
||||
type SortItem = { key: string; order?: boolean | 'asc' | 'desc' }
|
||||
const { lgAndUp } = useDisplay()
|
||||
|
||||
export interface Props {
|
||||
items: Map<string, PowerItem>
|
||||
minimumTotal: number
|
||||
maximumTotal: number
|
||||
averageTotal: number
|
||||
items: Map<string, PowerItem>
|
||||
minimumTotal: number
|
||||
maximumTotal: number
|
||||
averageTotal: number
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => new Map<string, PowerItem>
|
||||
items: () => new Map<string, PowerItem>()
|
||||
})
|
||||
|
||||
const headers = ref([
|
||||
{
|
||||
title: 'Event',
|
||||
align: ' d-none d-lg-table-cell start',
|
||||
sortable: true,
|
||||
value: '1.origin'
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
align: 'start',
|
||||
sortable: true,
|
||||
value: '1.itemName'
|
||||
},
|
||||
{
|
||||
title: 'Min.',
|
||||
align: 'end d-none d-lg-table-cell',
|
||||
sortable: true,
|
||||
key: '1.minItemPower'
|
||||
},
|
||||
{
|
||||
title: 'Max.',
|
||||
align: 'end d-none d-lg-table-cell',
|
||||
sortable: true,
|
||||
key: '1.maxItemPower'
|
||||
},
|
||||
{
|
||||
title: 'Owned',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: `1.owned`
|
||||
},
|
||||
{
|
||||
title: 'Min. Total',
|
||||
align: 'end d-none d-lg-table-cell',
|
||||
sortable: false,
|
||||
key: `1.minTotalPower`
|
||||
},
|
||||
{
|
||||
title: 'Max. Total',
|
||||
align: 'end d-none d-lg-table-cell',
|
||||
sortable: false,
|
||||
key: `1.maxTotalPower`
|
||||
},
|
||||
{
|
||||
title: 'Mean Total',
|
||||
align: 'end',
|
||||
sortable: false,
|
||||
key: `1.aveTotalPower`
|
||||
const computedHeaders = computed((): ReadonlyHeaders => {
|
||||
let initialHeaders: DataTableHeader[] = [
|
||||
{
|
||||
title: 'Name',
|
||||
align: 'start',
|
||||
sortable: true,
|
||||
value: '1.itemName'
|
||||
},
|
||||
{
|
||||
title: 'Owned',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: `1.owned`
|
||||
},
|
||||
{
|
||||
title: 'Mean Total',
|
||||
align: 'end',
|
||||
sortable: false,
|
||||
key: `1.aveTotalPower`
|
||||
}
|
||||
]
|
||||
if (lgAndUp.value) {
|
||||
initialHeaders!.unshift({
|
||||
title: 'Event',
|
||||
align: 'start',
|
||||
sortable: true,
|
||||
value: '1.origin'
|
||||
})
|
||||
initialHeaders.splice(2, 0, {
|
||||
title: 'Min.',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: '1.minItemPower'
|
||||
})
|
||||
initialHeaders.splice(3, 0, {
|
||||
title: 'Max.',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: '1.maxItemPower'
|
||||
})
|
||||
initialHeaders.splice(5, 0, {
|
||||
title: 'Min. Total',
|
||||
align: 'end',
|
||||
sortable: false,
|
||||
key: `1.minTotalPower`
|
||||
})
|
||||
initialHeaders.splice(6, 0, {
|
||||
title: 'Max. Total',
|
||||
align: 'end',
|
||||
sortable: false,
|
||||
key: `1.maxTotalPower`
|
||||
})
|
||||
}
|
||||
])
|
||||
return initialHeaders as ReadonlyHeaders
|
||||
})
|
||||
const sortBy: Ref<SortItem[]> = ref([
|
||||
{
|
||||
key: '1.minItemPower',
|
||||
|
|
@ -101,7 +111,7 @@ const filteredItems = computed(() =>
|
|||
? value
|
||||
: undefined
|
||||
)
|
||||
.filter((value) => value !== undefined)
|
||||
.filter((value): value is [string, PowerItem] => !!value)
|
||||
)
|
||||
const getColor = computed(() => (rarity: number): string => {
|
||||
if (rarity === 5) {
|
||||
|
|
@ -151,9 +161,9 @@ toggle()
|
|||
density="compact"
|
||||
v-model:sort-by="sortBy"
|
||||
:items="filteredItems"
|
||||
:headers="headers"
|
||||
:headers="computedHeaders"
|
||||
>
|
||||
<template v-slot:item.1.origin="{ item }">
|
||||
<template v-slot:[`item.1.origin`]="{ item }">
|
||||
<v-card
|
||||
class="my-2"
|
||||
elevation="2"
|
||||
|
|
@ -163,10 +173,10 @@ toggle()
|
|||
color="transparent"
|
||||
>
|
||||
<v-img :src="getEventImageUrl(item[1].origin)"></v-img>
|
||||
<v-tooltip activator="parent">{{ item?.[1].origin }}</v-tooltip>
|
||||
</v-card>
|
||||
<v-tooltip activator="parent">{{ item[1].origin }}</v-tooltip> </v-card
|
||||
>
|
||||
</template>
|
||||
<template v-slot:item.1.itemName="{ item }">
|
||||
<template v-slot:[`item.1.itemName`]="{ item }">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
v-if="item[1].tooltip != undefined"
|
||||
|
|
@ -183,7 +193,7 @@ toggle()
|
|||
{{ item[1].itemName }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<template v-slot:item.1.owned="{ item }">
|
||||
<template v-slot:[`item.1.owned`]="{ item }">
|
||||
<v-text-field
|
||||
density="compact"
|
||||
hide-details="auto"
|
||||
|
|
@ -191,13 +201,13 @@ toggle()
|
|||
@update:model-value="usePowerItems().updateOwned(item[0], item[1].owned)"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<template v-slot:item.1.minTotalPower="{ item }">
|
||||
<template v-slot:[`item.1.minTotalPower`]="{ item }">
|
||||
{{ item[1].minItemPower * item[1].owned }}
|
||||
</template>
|
||||
<template v-slot:item.1.maxTotalPower="{ item }">
|
||||
<template v-slot:[`item.1.maxTotalPower`]="{ item }">
|
||||
{{ item[1].maxItemPower * item[1].owned }}
|
||||
</template>
|
||||
<template v-slot:item.1.aveTotalPower="{ item }">
|
||||
<template v-slot:[`item.1.aveTotalPower`]="{ item }">
|
||||
{{ ((item[1].minItemPower + item[1].maxItemPower) / 2) * item[1].owned }}
|
||||
</template>
|
||||
<template v-slot:tfoot>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { usePowerItems } from '@/stores/powerItems'
|
||||
import type { PowerItem } from '@/types/PowerItem'
|
||||
import type { Ref } from 'vue';
|
||||
import { computed, ref } from 'vue'
|
||||
import { useDisplay } from 'vuetify';
|
||||
import type { VDataTable } from 'vuetify/components';
|
||||
|
||||
type ReadonlyHeaders = VDataTable['headers']
|
||||
type SortItem = { key: string; order?: boolean | 'asc' | 'desc' }
|
||||
const { lgAndUp } = useDisplay()
|
||||
|
||||
export interface Props {
|
||||
items: Map<string, PowerItem>
|
||||
|
|
@ -12,39 +19,46 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
items: () => new Map<string, PowerItem>()
|
||||
})
|
||||
|
||||
const headers = ref([
|
||||
{
|
||||
title: '',
|
||||
align: 'start',
|
||||
sortable: false,
|
||||
value: '1.iconURL'
|
||||
},
|
||||
{
|
||||
title: 'Name',
|
||||
align: ' d-none d-lg-table-cell start',
|
||||
sortable: true,
|
||||
value: '1.itemName'
|
||||
},
|
||||
{
|
||||
title: 'Power',
|
||||
align: ' d-none d-lg-table-cell',
|
||||
sortable: true,
|
||||
key: '1.minItemPower'
|
||||
},
|
||||
{
|
||||
title: 'Owned',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: `1.owned`
|
||||
},
|
||||
{
|
||||
title: 'Total',
|
||||
align: 'end',
|
||||
sortable: false,
|
||||
key: `1.totalPower`
|
||||
const headers = computed((): ReadonlyHeaders => {
|
||||
const initialHeaders = [
|
||||
{
|
||||
title: '',
|
||||
align: 'start',
|
||||
sortable: false,
|
||||
value: '1.iconURL'
|
||||
},
|
||||
{
|
||||
title: 'Owned',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: `1.owned`
|
||||
},
|
||||
{
|
||||
title: 'Total',
|
||||
align: 'end',
|
||||
sortable: false,
|
||||
key: `1.totalPower`
|
||||
}
|
||||
]
|
||||
if (lgAndUp.value) {
|
||||
initialHeaders!.splice(1, 0,
|
||||
{
|
||||
title: 'Name',
|
||||
align: 'start',
|
||||
sortable: true,
|
||||
value: '1.itemName'
|
||||
})
|
||||
initialHeaders!.splice(2, 0,
|
||||
{
|
||||
title: 'Power',
|
||||
align: 'end',
|
||||
sortable: true,
|
||||
key: '1.minItemPower'
|
||||
})
|
||||
}
|
||||
])
|
||||
const sortBy = ref([
|
||||
return initialHeaders as ReadonlyHeaders
|
||||
})
|
||||
const sortBy: Ref<SortItem[]> = ref([
|
||||
{
|
||||
key: '1.minItemPower',
|
||||
order: 'asc'
|
||||
|
|
@ -77,7 +91,7 @@ const getColor = computed(() => (rarity: number): string => {
|
|||
:items="[...items.entries()]"
|
||||
:headers="headers"
|
||||
>
|
||||
<template v-slot:item.1.iconURL="{ item }">
|
||||
<template v-slot:[`item.1.iconURL`]="{ item }">
|
||||
<v-card class="my-2" elevation="2" rounded width="41">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
|
|
@ -94,7 +108,7 @@ const getColor = computed(() => (rarity: number): string => {
|
|||
<v-img :src="`/images/${item[1].iconURL}`" height="41" width="41" cover></v-img>
|
||||
</v-card>
|
||||
</template>
|
||||
<template v-slot:item.1.itemName="{ item }">
|
||||
<template v-slot:[`item.1.itemName`]="{ item }">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
v-if="item[1].tooltip != undefined"
|
||||
|
|
@ -111,7 +125,7 @@ const getColor = computed(() => (rarity: number): string => {
|
|||
{{ item[1].itemName }}
|
||||
</v-chip>
|
||||
</template>
|
||||
<template v-slot:item.1.owned="{ item }">
|
||||
<template v-slot:[`item.1.owned`]="{ item }">
|
||||
<v-text-field
|
||||
density="compact"
|
||||
hide-details="auto"
|
||||
|
|
@ -119,7 +133,7 @@ const getColor = computed(() => (rarity: number): string => {
|
|||
@update:model-value="usePowerItems().updateOwned(item[0], item[1].owned)"
|
||||
></v-text-field>
|
||||
</template>
|
||||
<template v-slot:item.1.totalPower="{ item }">
|
||||
<template v-slot:[`item.1.totalPower`]="{ item }">
|
||||
{{ item[1].minItemPower * item[1].owned }}
|
||||
</template>
|
||||
<template v-slot:tfoot>
|
||||
|
|
|
|||
|
|
@ -10,15 +10,11 @@ import router from './router'
|
|||
import 'vuetify/styles'
|
||||
import '@mdi/font/css/materialdesignicons.css'
|
||||
import { createVuetify } from 'vuetify'
|
||||
import * as components from 'vuetify/components'
|
||||
import * as directives from 'vuetify/directives'
|
||||
import axios from 'axios'
|
||||
import zitadelAuth from '@/services/zitadelAuth'
|
||||
import { apiBaseURL } from './types/ConfigSymbols'
|
||||
|
||||
const vuetify = createVuetify({
|
||||
components,
|
||||
directives,
|
||||
icons: {
|
||||
defaultSet: 'mdi'
|
||||
},
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ const router = createRouter({
|
|||
{
|
||||
path: '/test',
|
||||
name: 'test',
|
||||
component: () => import('@/views/Test.vue')
|
||||
component: () => import('@/views/TestView.vue')
|
||||
},
|
||||
|
||||
{
|
||||
|
|
|
|||
110
src/types/DataTableHeader.ts
Normal file
110
src/types/DataTableHeader.ts
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import type { ComputedRef } from "vue"
|
||||
import type { Ref } from "vue"
|
||||
|
||||
export type DataTableHeader = {
|
||||
key?: 'data-table-group' | 'data-table-select' | 'data-table-expand' | (string & {})
|
||||
value?: SelectItemKey
|
||||
title?: string
|
||||
fixed?: boolean
|
||||
align?: 'start' | 'end' | 'center'
|
||||
width?: number | string
|
||||
minWidth?: string
|
||||
maxWidth?: string
|
||||
headerProps?: Record<string, any>
|
||||
cellProps?: HeaderCellProps
|
||||
sortable?: boolean
|
||||
sort?: DataTableCompareFunction
|
||||
filter?: FilterFunction
|
||||
children?: DataTableHeader[]
|
||||
}
|
||||
|
||||
type SelectItemKey<T = Record<string, any>> = boolean | null | undefined | string | readonly (string | number)[] | ((item: T, fallback?: any) => any);
|
||||
type HeaderCellProps = Record<string, any> | ((data: Pick<ItemKeySlot<any>, 'index' | 'item' | 'internalItem' | 'value'>) => Record<string, any>);
|
||||
type DataTableCompareFunction<T = any> = (a: T, b: T) => number;
|
||||
type FilterFunction = (value: string, query: string, item?: InternalItem) => FilterMatch;
|
||||
type ItemKeySlot<T> = ItemSlotBase<T> & {
|
||||
value: any;
|
||||
column: InternalDataTableHeader;
|
||||
};
|
||||
type FilterMatch = boolean | number | [number, number] | [number, number][];
|
||||
type ItemSlotBase<T> = {
|
||||
index: number;
|
||||
item: T;
|
||||
internalItem: DataTableItem<T>;
|
||||
isExpanded: ReturnType<typeof provideExpanded>['isExpanded'];
|
||||
toggleExpand: ReturnType<typeof provideExpanded>['toggleExpand'];
|
||||
isSelected: ReturnType<typeof provideSelection>['isSelected'];
|
||||
toggleSelect: ReturnType<typeof provideSelection>['toggleSelect'];
|
||||
};
|
||||
type InternalDataTableHeader = Omit<DataTableHeader, 'key' | 'value' | 'children'> & {
|
||||
key: string | null;
|
||||
value: SelectItemKey | null;
|
||||
sortable: boolean;
|
||||
fixedOffset?: number;
|
||||
lastFixed?: boolean;
|
||||
colspan?: number;
|
||||
rowspan?: number;
|
||||
children?: InternalDataTableHeader[];
|
||||
};
|
||||
type ExpandProps = {
|
||||
expandOnClick: boolean;
|
||||
expanded: readonly string[];
|
||||
'onUpdate:expanded': ((value: any[]) => void) | undefined;
|
||||
};
|
||||
type SelectionProps = Pick<DataTableItemProps, 'itemValue'> & {
|
||||
modelValue: readonly any[];
|
||||
selectStrategy: 'single' | 'page' | 'all';
|
||||
valueComparator: typeof deepEqual;
|
||||
'onUpdate:modelValue': EventProp<[any[]]> | undefined;
|
||||
};
|
||||
type EventProp<T extends any[] = any[], F = (...args: T) => void> = F;
|
||||
|
||||
declare function provideExpanded(props: ExpandProps): {
|
||||
expand: (item: DataTableItem, value: boolean) => void;
|
||||
expanded: Ref<Set<string>> & {
|
||||
readonly externalValue: readonly string[];
|
||||
};
|
||||
expandOnClick: Ref<boolean>;
|
||||
isExpanded: (item: DataTableItem) => boolean;
|
||||
toggleExpand: (item: DataTableItem) => void;
|
||||
};
|
||||
declare function provideSelection(props: SelectionProps, { allItems, currentPage }: {
|
||||
allItems: Ref<SelectableItem[]>;
|
||||
currentPage: Ref<SelectableItem[]>;
|
||||
}): {
|
||||
toggleSelect: (item: SelectableItem) => void;
|
||||
select: (items: SelectableItem[], value: boolean) => void;
|
||||
selectAll: (value: boolean) => void;
|
||||
isSelected: (items: SelectableItem | SelectableItem[]) => boolean;
|
||||
isSomeSelected: (items: SelectableItem | SelectableItem[]) => boolean;
|
||||
someSelected: ComputedRef<boolean>;
|
||||
allSelected: ComputedRef<boolean>;
|
||||
showSelectAll: boolean;
|
||||
};
|
||||
declare function deepEqual(a: any, b: any): boolean;
|
||||
|
||||
interface InternalItem<T = any> {
|
||||
value: any;
|
||||
raw: T;
|
||||
}
|
||||
interface DataTableItemProps {
|
||||
items: any[];
|
||||
itemValue: SelectItemKey;
|
||||
itemSelectable: SelectItemKey;
|
||||
returnObject: boolean;
|
||||
}
|
||||
interface DataTableItem<T = any> extends InternalItem<T>, GroupableItem<T>, SelectableItem {
|
||||
key: any;
|
||||
index: number;
|
||||
columns: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
interface SelectableItem {
|
||||
value: any;
|
||||
selectable: boolean;
|
||||
}
|
||||
interface GroupableItem<T = any> {
|
||||
type: 'item';
|
||||
raw: T;
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ const {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card class="flex-fill">
|
||||
<v-card-title>Blessing Power</v-card-title>
|
||||
<v-card-text>
|
||||
<v-sheet class="d-flex flex-wrap flex-fill">
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card class="flex-fill">
|
||||
<v-card-title>Fellow Power</v-card-title>
|
||||
<v-card-text>
|
||||
<v-sheet class="d-flex flex-wrap flex-fill">
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card class="flex-fill">
|
||||
<v-card-title>Intimacy Power</v-card-title>
|
||||
<v-card-text>
|
||||
<v-sheet class="d-flex flex-wrap flex-fill">
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import SpecialItemsCard from '@/components/SpecialItemsCard.vue'
|
||||
import StandardItemsCard from '@/components/StandardItemsCard.vue'
|
||||
import SummaryCard from '@/components/SummaryCard.vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { usePowerItems } from '@/stores/powerItems'
|
||||
|
||||
const {
|
||||
standardBlessingItems,
|
||||
standardBlessingItemTotal,
|
||||
specialBlessingItems,
|
||||
specialBlessingItemsMinTotal,
|
||||
specialBlessingItemsMaxTotal,
|
||||
specialBlessingItemsAveTotal
|
||||
} = storeToRefs(usePowerItems())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card-title>Intimacy Power</v-card-title>
|
||||
<v-card-text>
|
||||
<v-sheet class="d-flex flex-wrap flex-fill">
|
||||
<StandardItemsCard
|
||||
class="ma-2 align-self-start"
|
||||
:items="standardBlessingItems"
|
||||
:total="standardBlessingItemTotal"
|
||||
/>
|
||||
<SpecialItemsCard
|
||||
class="ma-2 align-self-start"
|
||||
:items="specialBlessingItems"
|
||||
:minimum-total="specialBlessingItemsMinTotal"
|
||||
:maximum-total="specialBlessingItemsMaxTotal"
|
||||
:average-total="specialBlessingItemsAveTotal"
|
||||
/>
|
||||
<SummaryCard
|
||||
class="ma-2 align-self-start"
|
||||
:standard-total="standardBlessingItemTotal"
|
||||
:minimum-total="specialBlessingItemsMinTotal"
|
||||
:maximum-total="specialBlessingItemsMaxTotal"
|
||||
:average-total="specialBlessingItemsAveTotal"
|
||||
/>
|
||||
</v-sheet>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '@/styles/settings.scss';
|
||||
:deep(tbody) tr:nth-of-type(even) {
|
||||
background-color: rgba(var(--v-theme-primary-darken-1), 0.25);
|
||||
}
|
||||
</style>
|
||||
13
src/views/TestView.vue
Normal file
13
src/views/TestView.vue
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import NewItemForm from '@/components/NewItemForm.vue';
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-sheet class="flex-fill">
|
||||
<NewItemForm />
|
||||
</v-sheet>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
||||
|
|
@ -2,11 +2,13 @@ import { fileURLToPath, URL } from 'node:url'
|
|||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vuetify from 'vite-plugin-vuetify'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vuetify(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue