zrobienie jednego komponentu od wykresów. Naprawienie folderu public (favicon). Praca nad wykresami i statystykami.

This commit is contained in:
installer
2024-11-15 18:02:17 +01:00
parent 64db46b612
commit 479069747a
45 changed files with 1357 additions and 1295 deletions

View File

@@ -420,6 +420,8 @@
"useDataStore": true,
"chartsAndStatsStore": true,
"useChartsAndStatsStore": true,
"useCacheStore": true
"useCacheStore": true,
"cacheFullListResponses": true,
"Switch": true
}
}

BIN
bun.lockb

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,3 +0,0 @@
<script lang="ts" setup></script>
<template></template>

View File

@@ -0,0 +1,27 @@
<script lang="ts" setup>
import type { ChartData, Config } from '@/types/chartsTypes';
defineProps<{
config: Config;
labels: string[];
charts: Record<string, ChartData[]>;
}>();
</script>
<template>
<div v-for="(chart, _, index) in charts" :key="index" class="flex flex-col">
<!-- TODO: Zrobić własny tooltip -->
<Label class="my-4 text-center text-5xl font-bold text-primary"> {{ labels[index] }} </Label>
<LineChart
:categories="config.categories"
index="turn"
:colors="config.colors"
:data="chart"
class="h-[500px]"
:show-legend="true"
:show-tooltip="true"
/>
</div>
</template>

View File

@@ -1,3 +0,0 @@
<script lang="ts" setup></script>
<template></template>

View File

@@ -1,3 +0,0 @@
<script lang="ts" setup></script>
<template></template>

View File

@@ -1,3 +0,0 @@
<script lang="ts" setup></script>
<template></template>

View File

@@ -1,3 +0,0 @@
<script lang="ts" setup></script>
<template></template>

View File

@@ -1,115 +0,0 @@
<script setup lang="ts" generic="T extends Record<string, any>">
import type { BulletLegendItemInterface } from '@unovis/ts'
import type { BaseChartProps } from '.'
import { ChartCrosshair, ChartLegend, defaultColors } from '@/components/ui/chart'
import { cn } from '@/lib/utils'
import { Axis, GroupedBar, StackedBar } from '@unovis/ts'
import { VisAxis, VisGroupedBar, VisStackedBar, VisXYContainer } from '@unovis/vue'
import { useMounted } from '@vueuse/core'
import { type Component, computed, ref } from 'vue'
const props = withDefaults(defineProps<BaseChartProps<T> & {
/**
* Render custom tooltip component.
*/
customTooltip?: Component
/**
* Change the type of the chart
* @default "grouped"
*/
type?: 'stacked' | 'grouped'
/**
* Rounded bar corners
* @default 0
*/
roundedCorners?: number
}>(), {
type: 'grouped',
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
filterOpacity: 0.2,
roundedCorners: 0,
showXAxis: true,
showYAxis: true,
showTooltip: true,
showLegend: true,
showGridLine: true,
})
const emits = defineEmits<{
legendItemClick: [d: BulletLegendItemInterface, i: number]
}>()
type KeyOfT = Extract<keyof T, string>
type Data = typeof props.data[number]
const index = computed(() => props.index as KeyOfT)
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
name: category,
color: colors.value[i],
inactive: false,
})))
const isMounted = useMounted()
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
emits('legendItemClick', d, i)
}
const VisBarComponent = computed(() => props.type === 'grouped' ? VisGroupedBar : VisStackedBar)
const selectorsBar = computed(() => props.type === 'grouped' ? GroupedBar.selectors.bar : StackedBar.selectors.bar)
</script>
<template>
<div :class="cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')">
<ChartLegend v-if="showLegend" v-model:items="legendItems" @legend-item-click="handleLegendItemClick" />
<VisXYContainer
:data="data"
:style="{ height: isMounted ? '100%' : 'auto' }"
:margin="margin"
>
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :custom-tooltip="customTooltip" :index="index" />
<VisBarComponent
:x="(d: Data, i: number) => i"
:y="categories.map(category => (d: Data) => d[category]) "
:color="colors"
:rounded-corners="roundedCorners"
:bar-padding="0.05"
:attributes="{
[selectorsBar]: {
opacity: (d: Data, i:number) => {
const pos = i % categories.length
return legendItems[pos]?.inactive ? filterOpacity : 1
},
},
}"
/>
<VisAxis
v-if="showXAxis"
type="x"
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
:grid-line="false"
:tick-line="false"
tick-text-color="hsl(var(--vis-text-color))"
/>
<VisAxis
v-if="showYAxis"
type="y"
:tick-line="false"
:tick-format="yFormatter"
:domain-line="false"
:grid-line="showGridLine"
:attributes="{
[Axis.selectors.grid]: {
class: 'text-muted',
},
}"
tick-text-color="hsl(var(--vis-text-color))"
/>
<slot />
</VisXYContainer>
</div>
</template>

View File

@@ -1,66 +0,0 @@
export { default as BarChart } from './BarChart.vue'
import type { Spacing } from '@unovis/ts'
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
export interface BaseChartProps<T extends Record<string, any>> {
/**
* The source data, in which each entry is a dictionary.
*/
data: T[]
/**
* Select the categories from your data. Used to populate the legend and toolip.
*/
categories: KeyOf<T>[]
/**
* Sets the key to map the data to the axis.
*/
index: KeyOf<T>
/**
* Change the default colors.
*/
colors?: string[]
/**
* Margin of each the container
*/
margin?: Spacing
/**
* Change the opacity of the non-selected field
* @default 0.2
*/
filterOpacity?: number
/**
* Function to format X label
*/
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Function to format Y label
*/
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Controls the visibility of the X axis.
* @default true
*/
showXAxis?: boolean
/**
* Controls the visibility of the Y axis.
* @default true
*/
showYAxis?: boolean
/**
* Controls the visibility of tooltip.
* @default true
*/
showTooltip?: boolean
/**
* Controls the visibility of legend.
* @default true
*/
showLegend?: boolean
/**
* Controls the visibility of gridline.
* @default true
*/
showGridLine?: boolean
}

View File

@@ -1,105 +1,125 @@
<script setup lang="ts" generic="T extends Record<string, any>">
import type { BaseChartProps } from '.'
import { ChartCrosshair, ChartLegend, defaultColors } from '@/components/ui/chart'
import { cn } from '@/lib/utils'
import { type BulletLegendItemInterface, CurveType } from '@unovis/ts'
import { Axis, Line } from '@unovis/ts'
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue'
import { useMounted } from '@vueuse/core'
import { type Component, computed, ref } from 'vue'
import { ChartCrosshair, ChartLegend, defaultColors } from '@/components/ui/chart';
import { cn } from '@/lib/utils';
import { Axis, type BulletLegendItemInterface, CurveType, Line } from '@unovis/ts';
import { VisAxis, VisLine, VisXYContainer } from '@unovis/vue';
import { useMounted } from '@vueuse/core';
import { type Component, computed, ref } from 'vue';
import type { BaseChartProps } from '.';
const props = withDefaults(defineProps<BaseChartProps<T> & {
/**
* Render custom tooltip component.
*/
customTooltip?: Component
/**
* Type of curve
*/
curveType?: CurveType
}>(), {
curveType: CurveType.MonotoneX,
filterOpacity: 0.2,
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
showXAxis: true,
showYAxis: true,
showTooltip: true,
showLegend: true,
showGridLine: true,
})
const props = withDefaults(
defineProps<
BaseChartProps<T> & {
/**
* Render custom tooltip component.
*/
customTooltip?: Component;
/**
* Type of curve
*/
curveType?: CurveType;
}
>(),
{
curveType: CurveType.MonotoneX,
filterOpacity: 0.2,
margin: () => ({ top: 0, bottom: 0, left: 0, right: 0 }),
showXAxis: true,
showYAxis: true,
showTooltip: true,
showLegend: true,
showGridLine: true
}
);
const emits = defineEmits<{
legendItemClick: [d: BulletLegendItemInterface, i: number]
}>()
legendItemClick: [d: BulletLegendItemInterface, i: number];
}>();
type KeyOfT = Extract<keyof T, string>
type Data = typeof props.data[number]
type KeyOfT = Extract<keyof T, string>;
type Data = (typeof props.data)[number];
const index = computed(() => props.index as KeyOfT)
const colors = computed(() => props.colors?.length ? props.colors : defaultColors(props.categories.length))
const index = computed(() => props.index as KeyOfT);
const colors = computed(() =>
props.colors?.length ? props.colors : defaultColors(props.categories.length)
);
const legendItems = ref<BulletLegendItemInterface[]>(props.categories.map((category, i) => ({
name: category,
color: colors.value[i],
inactive: false,
})))
const legendItems = ref<BulletLegendItemInterface[]>(
props.categories.map((category, i) => ({
name: category,
color: colors.value[i],
inactive: false
}))
);
const isMounted = useMounted()
const isMounted = useMounted();
function handleLegendItemClick(d: BulletLegendItemInterface, i: number) {
emits('legendItemClick', d, i)
emits('legendItemClick', d, i);
}
</script>
<template>
<div :class="cn('w-full h-[400px] flex flex-col items-end', $attrs.class ?? '')">
<ChartLegend v-if="showLegend" v-model:items="legendItems" @legend-item-click="handleLegendItemClick" />
<div :class="cn('flex h-[400px] w-full flex-col items-end', $attrs.class ?? '')">
<ChartLegend
v-if="showLegend"
v-model:items="legendItems"
@legend-item-click="handleLegendItemClick"
/>
<VisXYContainer
:margin="{ left: 20, right: 20 }"
:data="data"
:style="{ height: isMounted ? '100%' : 'auto' }"
>
<ChartCrosshair v-if="showTooltip" :colors="colors" :items="legendItems" :index="index" :custom-tooltip="customTooltip" />
<VisXYContainer
:margin="{ left: 20, right: 20 }"
:data="data"
:style="{ height: isMounted ? '100%' : 'auto' }"
>
<ChartCrosshair
v-if="showTooltip"
:colors="colors"
:items="legendItems"
:index="index"
:custom-tooltip="customTooltip"
/>
<template v-for="(category, i) in categories" :key="category">
<VisLine
:x="(d: Data, i: number) => i"
:y="(d: Data) => d[category]"
:curve-type="curveType"
:color="colors[i]"
:attributes="{
[Line.selectors.line]: {
opacity: legendItems.find(item => item.name === category)?.inactive ? filterOpacity : 1,
},
}"
/>
</template>
<template v-for="(category, i) in categories" :key="category">
<VisLine
:x="(d: Data, i: number) => i"
:y="(d: Data) => d[category]"
:curve-type="curveType"
:color="colors[i]"
:attributes="{
[Line.selectors.line]: {
opacity: legendItems.find(item => item.name === category)?.inactive
? filterOpacity
: 1
}
}"
/>
</template>
<VisAxis
v-if="showXAxis"
type="x"
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
:grid-line="false"
:tick-line="false"
tick-text-color="hsl(var(--vis-text-color))"
/>
<VisAxis
v-if="showYAxis"
type="y"
:tick-line="false"
:tick-format="yFormatter"
:domain-line="false"
:grid-line="showGridLine"
:attributes="{
[Axis.selectors.grid]: {
class: 'text-muted',
},
}"
tick-text-color="hsl(var(--vis-text-color))"
/>
<VisAxis
v-if="showXAxis"
type="x"
:tick-format="xFormatter ?? ((v: number) => data[v]?.[index])"
:grid-line="false"
:tick-line="false"
tick-text-color="hsl(var(--vis-text-color))"
/>
<VisAxis
v-if="showYAxis"
type="y"
:tick-line="false"
:tick-format="yFormatter"
:domain-line="false"
:grid-line="showGridLine"
:attributes="{
[Axis.selectors.grid]: {
class: 'text-muted'
}
}"
tick-text-color="hsl(var(--vis-text-color))"
/>
<slot />
</VisXYContainer>
</div>
<slot />
</VisXYContainer>
</div>
</template>

View File

@@ -1,66 +1,66 @@
export { default as LineChart } from './LineChart.vue'
export { default as LineChart } from './LineChart.vue';
import type { Spacing } from '@unovis/ts'
import type { Spacing } from '@unovis/ts';
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
export interface BaseChartProps<T extends Record<string, any>> {
/**
* The source data, in which each entry is a dictionary.
*/
data: T[]
/**
* Select the categories from your data. Used to populate the legend and toolip.
*/
categories: KeyOf<T>[]
/**
* Sets the key to map the data to the axis.
*/
index: KeyOf<T>
/**
* Change the default colors.
*/
colors?: string[]
/**
* Margin of each the container
*/
margin?: Spacing
/**
* Change the opacity of the non-selected field
* @default 0.2
*/
filterOpacity?: number
/**
* Function to format X label
*/
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Function to format Y label
*/
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Controls the visibility of the X axis.
* @default true
*/
showXAxis?: boolean
/**
* Controls the visibility of the Y axis.
* @default true
*/
showYAxis?: boolean
/**
* Controls the visibility of tooltip.
* @default true
*/
showTooltip?: boolean
/**
* Controls the visibility of legend.
* @default true
*/
showLegend?: boolean
/**
* Controls the visibility of gridline.
* @default true
*/
showGridLine?: boolean
/**
* The source data, in which each entry is a dictionary.
*/
data: T[];
/**
* Select the categories from your data. Used to populate the legend and toolip.
*/
categories: KeyOf<T>[];
/**
* Sets the key to map the data to the axis.
*/
index: KeyOf<T>;
/**
* Change the default colors.
*/
colors?: string[];
/**
* Margin of each the container
*/
margin?: Spacing;
/**
* Change the opacity of the non-selected field
* @default 0.2
*/
filterOpacity?: number;
/**
* Function to format X label
*/
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;
/**
* Function to format Y label
*/
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;
/**
* Controls the visibility of the X axis.
* @default true
*/
showXAxis?: boolean;
/**
* Controls the visibility of the Y axis.
* @default true
*/
showYAxis?: boolean;
/**
* Controls the visibility of tooltip.
* @default true
*/
showTooltip?: boolean;
/**
* Controls the visibility of legend.
* @default true
*/
showLegend?: boolean;
/**
* Controls the visibility of gridline.
* @default true
*/
showGridLine?: boolean;
}

View File

@@ -1,44 +1,48 @@
<script setup lang="ts">
import type { BulletLegendItemInterface } from '@unovis/ts'
import { omit } from '@unovis/ts'
import { VisCrosshair, VisTooltip } from '@unovis/vue'
import { type Component, createApp } from 'vue'
import { ChartTooltip } from '.'
import type { BulletLegendItemInterface } from '@unovis/ts';
import { omit } from '@unovis/ts';
import { VisCrosshair, VisTooltip } from '@unovis/vue';
import { type Component, createApp } from 'vue';
import { ChartTooltip } from '.';
const props = withDefaults(defineProps<{
colors: string[]
index: string
items: BulletLegendItemInterface[]
customTooltip?: Component
}>(), {
colors: () => [],
})
const props = withDefaults(
defineProps<{
colors: string[];
index: string;
items: BulletLegendItemInterface[];
customTooltip?: Component;
}>(),
{
colors: () => []
}
);
// Use weakmap to store reference to each datapoint for Tooltip
const wm = new WeakMap()
const wm = new WeakMap();
function template(d: any) {
if (wm.has(d)) {
return wm.get(d)
}
else {
const componentDiv = document.createElement('div')
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
const legendReference = props.items.find(i => i.name === key)
return { ...legendReference, value }
})
const TooltipComponent = props.customTooltip ?? ChartTooltip
createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(componentDiv)
wm.set(d, componentDiv.innerHTML)
return componentDiv.innerHTML
}
if (wm.has(d)) {
return wm.get(d);
} else {
const componentDiv = document.createElement('div');
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
const legendReference = props.items.find(i => i.name === key);
return { ...legendReference, value };
});
const TooltipComponent = props.customTooltip ?? ChartTooltip;
createApp(TooltipComponent, { title: d[props.index].toString(), data: omittedData }).mount(
componentDiv
);
wm.set(d, componentDiv.innerHTML);
return componentDiv.innerHTML;
}
}
function color(d: unknown, i: number) {
return props.colors[i] ?? 'transparent';
return props.colors[i] ?? 'transparent';
}
</script>
<template>
<VisTooltip :horizontal-shift="20" :vertical-shift="20" />
<VisCrosshair :template="template" :color="color" />
<VisTooltip :horizontal-shift="20" :vertical-shift="20" />
<VisCrosshair :template="template" :color="color" />
</template>

View File

@@ -1,50 +1,57 @@
<script setup lang="ts">
import type { BulletLegendItemInterface } from '@unovis/ts'
import { buttonVariants } from '@/components/ui/button'
import { BulletLegend } from '@unovis/ts'
import { VisBulletLegend } from '@unovis/vue'
import { nextTick, onMounted, ref } from 'vue'
import { buttonVariants } from '@/components/ui/button';
import type { BulletLegendItemInterface } from '@unovis/ts';
import { BulletLegend } from '@unovis/ts';
import { VisBulletLegend } from '@unovis/vue';
import { nextTick, onMounted, ref } from 'vue';
const props = withDefaults(defineProps<{ items: BulletLegendItemInterface[] }>(), {
items: () => [],
})
items: () => []
});
const emits = defineEmits<{
'legendItemClick': [d: BulletLegendItemInterface, i: number]
'update:items': [payload: BulletLegendItemInterface[]]
}>()
legendItemClick: [d: BulletLegendItemInterface, i: number];
'update:items': [payload: BulletLegendItemInterface[]];
}>();
const elRef = ref<HTMLElement>()
const elRef = ref<HTMLElement>();
onMounted(() => {
const selector = `.${BulletLegend.selectors.item}`
nextTick(() => {
const elements = elRef.value?.querySelectorAll(selector)
const classes = buttonVariants({ variant: 'ghost', size: 'xs' }).split(' ')
elements?.forEach(el => el.classList.add(...classes, '!inline-flex', '!mr-2'))
})
})
const selector = `.${BulletLegend.selectors.item}`;
nextTick(() => {
const elements = elRef.value?.querySelectorAll(selector);
const classes = buttonVariants({ variant: 'ghost', size: 'xs' }).split(' ');
elements?.forEach(el => el.classList.add(...classes, '!inline-flex', '!mr-2'));
});
});
function onLegendItemClick(d: BulletLegendItemInterface, i: number) {
emits('legendItemClick', d, i)
const isBulletActive = !props.items[i].inactive
const isFilterApplied = props.items.some(i => i.inactive)
if (isFilterApplied && isBulletActive) {
// reset filter
emits('update:items', props.items.map(item => ({ ...item, inactive: false })))
}
else {
// apply selection, set other item as inactive
emits('update:items', props.items.map(item => item.name === d.name ? ({ ...d, inactive: false }) : { ...item, inactive: true }))
}
emits('legendItemClick', d, i);
const isBulletActive = !props.items[i].inactive;
const isFilterApplied = props.items.some(i => i.inactive);
if (isFilterApplied && isBulletActive) {
// reset filter
emits(
'update:items',
props.items.map(item => ({ ...item, inactive: false }))
);
} else {
// apply selection, set other item as inactive
emits(
'update:items',
props.items.map(item =>
item.name === d.name ? { ...d, inactive: false } : { ...item, inactive: true }
)
);
}
}
</script>
<template>
<div ref="elRef" class="w-max">
<VisBulletLegend
:items="items"
:on-legend-item-click="onLegendItemClick"
/>
</div>
<div ref="elRef" class="w-max">
<ScrollArea class="mb-2 ms-40 w-screen whitespace-nowrap rounded-md border">
<VisBulletLegend :items="items" :on-legend-item-click="onLegendItemClick" class="ms-10" />
<ScrollBar orientation="horizontal" />
</ScrollArea>
</div>
</template>

View File

@@ -1,63 +1,66 @@
<script setup lang="ts">
import type { BulletLegendItemInterface } from '@unovis/ts'
import { omit } from '@unovis/ts'
import { VisTooltip } from '@unovis/vue'
import { type Component, createApp } from 'vue'
import { ChartTooltip } from '.'
import type { BulletLegendItemInterface } from '@unovis/ts';
import { omit } from '@unovis/ts';
import { VisTooltip } from '@unovis/vue';
import { type Component, createApp } from 'vue';
import { ChartTooltip } from '.';
const props = withDefaults(defineProps<{
selector: string
index: string
items?: BulletLegendItemInterface[]
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string
customTooltip?: Component
}>(), {
valueFormatter: (tick: number) => `${tick}`,
})
const props = withDefaults(
defineProps<{
selector: string;
index: string;
items?: BulletLegendItemInterface[];
valueFormatter?: (tick: number, i?: number, ticks?: number[]) => string;
customTooltip?: Component;
}>(),
{
valueFormatter: (tick: number) => `${tick}`
}
);
// Use weakmap to store reference to each datapoint for Tooltip
const wm = new WeakMap()
const wm = new WeakMap();
function template(d: any, i: number, elements: (HTMLElement | SVGElement)[]) {
if (props.index in d) {
if (wm.has(d)) {
return wm.get(d)
}
else {
const componentDiv = document.createElement('div')
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
const legendReference = props.items?.find(i => i.name === key)
return { ...legendReference, value: props.valueFormatter(value) }
})
const TooltipComponent = props.customTooltip ?? ChartTooltip
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
wm.set(d, componentDiv.innerHTML)
return componentDiv.innerHTML
}
}
if (props.index in d) {
if (wm.has(d)) {
return wm.get(d);
} else {
const componentDiv = document.createElement('div');
const omittedData = Object.entries(omit(d, [props.index])).map(([key, value]) => {
const legendReference = props.items?.find(i => i.name === key);
return { ...legendReference, value: props.valueFormatter(value) };
});
const TooltipComponent = props.customTooltip ?? ChartTooltip;
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv);
wm.set(d, componentDiv.innerHTML);
return componentDiv.innerHTML;
}
} else {
const data = d.data;
else {
const data = d.data
if (wm.has(data)) {
return wm.get(data)
}
else {
const style = getComputedStyle(elements[i])
const omittedData = [{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }]
const componentDiv = document.createElement('div')
const TooltipComponent = props.customTooltip ?? ChartTooltip
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv)
wm.set(d, componentDiv.innerHTML)
return componentDiv.innerHTML
}
}
if (wm.has(data)) {
return wm.get(data);
} else {
const style = getComputedStyle(elements[i]);
const omittedData = [
{ name: data.name, value: props.valueFormatter(data[props.index]), color: style.fill }
];
const componentDiv = document.createElement('div');
const TooltipComponent = props.customTooltip ?? ChartTooltip;
createApp(TooltipComponent, { title: d[props.index], data: omittedData }).mount(componentDiv);
wm.set(d, componentDiv.innerHTML);
return componentDiv.innerHTML;
}
}
}
</script>
<template>
<VisTooltip
:horizontal-shift="20" :vertical-shift="20" :triggers="{
[selector]: template,
}"
/>
<VisTooltip
:horizontal-shift="20"
:vertical-shift="20"
:triggers="{
[selector]: template
}"
/>
</template>

View File

@@ -1,40 +1,40 @@
<script setup lang="ts">
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
defineProps<{
title?: string
data: {
name: string
color: string
value: any
}[]
}>()
title?: string;
data: {
name: string;
color: string;
value: any;
}[];
}>();
</script>
<template>
<Card class="text-sm">
<CardHeader v-if="title" class="p-3 border-b">
<CardTitle>
{{ title }}
</CardTitle>
</CardHeader>
<CardContent class="p-3 min-w-[180px] flex flex-col gap-1">
<div v-for="(item, key) in data" :key="key" class="flex justify-between">
<div class="flex items-center">
<span class="w-2.5 h-2.5 mr-2">
<svg width="100%" height="100%" viewBox="0 0 30 30">
<path
d=" M 15 15 m -14, 0 a 14,14 0 1,1 28,0 a 14,14 0 1,1 -28,0"
:stroke="item.color"
:fill="item.color"
stroke-width="1"
/>
</svg>
</span>
<span>{{ item.name }}</span>
</div>
<span class="font-semibold ml-4">{{ item.value }}</span>
</div>
</CardContent>
</Card>
<Card class="text-sm">
<CardHeader v-if="title" class="border-b p-3">
<CardTitle>
{{ title }}
</CardTitle>
</CardHeader>
<CardContent class="flex min-w-[180px] flex-col gap-1 p-3">
<div v-for="(item, key) in data" :key="key" class="flex justify-between">
<div class="flex items-center">
<span class="mr-2 h-2.5 w-2.5">
<svg width="100%" height="100%" viewBox="0 0 30 30">
<path
d=" M 15 15 m -14, 0 a 14,14 0 1,1 28,0 a 14,14 0 1,1 -28,0"
:stroke="item.color"
:fill="item.color"
stroke-width="1"
/>
</svg>
</span>
<span>{{ item.name }}</span>
</div>
<span class="ml-4 font-semibold">{{ item.value }}</span>
</div>
</CardContent>
</Card>
</template>

View File

@@ -1,18 +1,22 @@
export { default as ChartCrosshair } from './ChartCrosshair.vue'
export { default as ChartLegend } from './ChartLegend.vue'
export { default as ChartSingleTooltip } from './ChartSingleTooltip.vue'
export { default as ChartTooltip } from './ChartTooltip.vue'
export { default as ChartCrosshair } from './ChartCrosshair.vue';
export { default as ChartLegend } from './ChartLegend.vue';
export { default as ChartSingleTooltip } from './ChartSingleTooltip.vue';
export { default as ChartTooltip } from './ChartTooltip.vue';
export function defaultColors(count: number = 3) {
const quotient = Math.floor(count / 2)
const remainder = count % 2
const quotient = Math.floor(count / 2);
const remainder = count % 2;
const primaryCount = quotient + remainder
const secondaryCount = quotient
return [
...Array.from(new Array(primaryCount).keys()).map(i => `hsl(var(--vis-primary-color) / ${1 - (1 / primaryCount) * i})`),
...Array.from(new Array(secondaryCount).keys()).map(i => `hsl(var(--vis-secondary-color) / ${1 - (1 / secondaryCount) * i})`),
];
const primaryCount = quotient + remainder;
const secondaryCount = quotient;
return [
...Array.from(new Array(primaryCount).keys()).map(
i => `hsl(var(--vis-primary-color) / ${1 - (1 / primaryCount) * i})`
),
...Array.from(new Array(secondaryCount).keys()).map(
i => `hsl(var(--vis-secondary-color) / ${1 - (1 / secondaryCount) * i})`
)
];
}
export * from './interface'
export * from './interface';

View File

@@ -1,64 +1,64 @@
import type { Spacing } from '@unovis/ts'
import type { Spacing } from '@unovis/ts';
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>
type KeyOf<T extends Record<string, any>> = Extract<keyof T, string>;
export interface BaseChartProps<T extends Record<string, any>> {
/**
* The source data, in which each entry is a dictionary.
*/
data: T[]
/**
* Select the categories from your data. Used to populate the legend and toolip.
*/
categories: KeyOf<T>[]
/**
* Sets the key to map the data to the axis.
*/
index: KeyOf<T>
/**
* Change the default colors.
*/
colors?: string[]
/**
* Margin of each the container
*/
margin?: Spacing
/**
* Change the opacity of the non-selected field
* @default 0.2
*/
filterOpacity?: number
/**
* Function to format X label
*/
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Function to format Y label
*/
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string
/**
* Controls the visibility of the X axis.
* @default true
*/
showXAxis?: boolean
/**
* Controls the visibility of the Y axis.
* @default true
*/
showYAxis?: boolean
/**
* Controls the visibility of tooltip.
* @default true
*/
showTooltip?: boolean
/**
* Controls the visibility of legend.
* @default true
*/
showLegend?: boolean
/**
* Controls the visibility of gridline.
* @default true
*/
showGridLine?: boolean
/**
* The source data, in which each entry is a dictionary.
*/
data: T[];
/**
* Select the categories from your data. Used to populate the legend and toolip.
*/
categories: KeyOf<T>[];
/**
* Sets the key to map the data to the axis.
*/
index: KeyOf<T>;
/**
* Change the default colors.
*/
colors?: string[];
/**
* Margin of each the container
*/
margin?: Spacing;
/**
* Change the opacity of the non-selected field
* @default 0.2
*/
filterOpacity?: number;
/**
* Function to format X label
*/
xFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;
/**
* Function to format Y label
*/
yFormatter?: (tick: number | Date, i: number, ticks: number[] | Date[]) => string;
/**
* Controls the visibility of the X axis.
* @default true
*/
showXAxis?: boolean;
/**
* Controls the visibility of the Y axis.
* @default true
*/
showYAxis?: boolean;
/**
* Controls the visibility of tooltip.
* @default true
*/
showTooltip?: boolean;
/**
* Controls the visibility of legend.
* @default true
*/
showLegend?: boolean;
/**
* Controls the visibility of gridline.
* @default true
*/
showGridLine?: boolean;
}

View File

@@ -1,14 +1,19 @@
<script setup lang="ts">
import { DialogRoot, type DialogRootEmits, type DialogRootProps, useForwardPropsEmits } from 'radix-vue'
import {
DialogRoot,
type DialogRootEmits,
type DialogRootProps,
useForwardPropsEmits
} from 'radix-vue';
const props = defineProps<DialogRootProps>()
const emits = defineEmits<DialogRootEmits>()
const props = defineProps<DialogRootProps>();
const emits = defineEmits<DialogRootEmits>();
const forwarded = useForwardPropsEmits(props, emits)
const forwarded = useForwardPropsEmits(props, emits);
</script>
<template>
<DialogRoot v-bind="forwarded">
<slot />
</DialogRoot>
<DialogRoot v-bind="forwarded">
<slot />
</DialogRoot>
</template>

View File

@@ -1,11 +1,11 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from 'radix-vue'
import { DialogClose, type DialogCloseProps } from 'radix-vue';
const props = defineProps<DialogCloseProps>()
const props = defineProps<DialogCloseProps>();
</script>
<template>
<DialogClose v-bind="props">
<slot />
</DialogClose>
<DialogClose v-bind="props">
<slot />
</DialogClose>
</template>

View File

@@ -1,50 +1,51 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { X } from 'lucide-vue-next'
import { cn } from '@/lib/utils';
import { X } from 'lucide-vue-next';
import {
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits
} from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DialogContentEmits>()
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<DialogContentEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits)
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
/>
<DialogContent
v-bind="forwarded"
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
props.class,
)"
>
<slot />
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
/>
<DialogContent
v-bind="forwarded"
:class="
cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
props.class
)
"
>
<slot />
<DialogClose
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="w-4 h-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
<DialogClose
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="h-4 w-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
</template>

View File

@@ -1,24 +1,24 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils';
import { DialogDescription, type DialogDescriptionProps, useForwardProps } from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwardedProps = useForwardProps(delegatedProps)
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DialogDescription
v-bind="forwardedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
>
<slot />
</DialogDescription>
<DialogDescription
v-bind="forwardedProps"
:class="cn('text-sm text-muted-foreground', props.class)"
>
<slot />
</DialogDescription>
</template>

View File

@@ -1,19 +1,12 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { cn } from '@/lib/utils';
import type { HTMLAttributes } from 'vue';
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
const props = defineProps<{ class?: HTMLAttributes['class'] }>();
</script>
<template>
<div
:class="
cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2',
props.class,
)
"
>
<slot />
</div>
<div :class="cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:gap-x-2', props.class)">
<slot />
</div>
</template>

View File

@@ -1,16 +1,14 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { cn } from '@/lib/utils';
import type { HTMLAttributes } from 'vue';
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
class?: HTMLAttributes['class'];
}>();
</script>
<template>
<div
:class="cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)"
>
<slot />
</div>
<div :class="cn('flex flex-col gap-y-1.5 text-center sm:text-left', props.class)">
<slot />
</div>
</template>

View File

@@ -1,59 +1,64 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { X } from 'lucide-vue-next'
import { cn } from '@/lib/utils';
import { X } from 'lucide-vue-next';
import {
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits
} from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<DialogContentEmits>()
const props = defineProps<DialogContentProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<DialogContentEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits)
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
>
<DialogContent
:class="
cn(
'relative z-50 grid w-full max-w-lg my-8 gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',
props.class,
)
"
v-bind="forwarded"
@pointer-down-outside="(event) => {
const originalEvent = event.detail.originalEvent;
const target = originalEvent.target as HTMLElement;
if (originalEvent.offsetX > target.clientWidth || originalEvent.offsetY > target.clientHeight) {
event.preventDefault();
}
}"
>
<slot />
<DialogPortal>
<DialogOverlay
class="fixed inset-0 z-50 grid place-items-center overflow-y-auto bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0"
>
<DialogContent
:class="
cn(
'relative z-50 my-8 grid w-full max-w-lg gap-4 border border-border bg-background p-6 shadow-lg duration-200 sm:rounded-lg md:w-full',
props.class
)
"
v-bind="forwarded"
@pointer-down-outside="
event => {
const originalEvent = event.detail.originalEvent;
const target = originalEvent.target as HTMLElement;
if (
originalEvent.offsetX > target.clientWidth ||
originalEvent.offsetY > target.clientHeight
) {
event.preventDefault();
}
}
"
>
<slot />
<DialogClose
class="absolute top-3 right-3 p-0.5 transition-colors rounded-md hover:bg-secondary"
>
<X class="w-4 h-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogOverlay>
</DialogPortal>
<DialogClose
class="absolute right-3 top-3 rounded-md p-0.5 transition-colors hover:bg-secondary"
>
<X class="h-4 w-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogOverlay>
</DialogPortal>
</template>

View File

@@ -1,29 +1,24 @@
<script setup lang="ts">
import { cn } from '@/lib/utils'
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils';
import { DialogTitle, type DialogTitleProps, useForwardProps } from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwardedProps = useForwardProps(delegatedProps)
const forwardedProps = useForwardProps(delegatedProps);
</script>
<template>
<DialogTitle
v-bind="forwardedProps"
:class="
cn(
'text-lg font-semibold leading-none tracking-tight',
props.class,
)
"
>
<slot />
</DialogTitle>
<DialogTitle
v-bind="forwardedProps"
:class="cn('text-lg font-semibold leading-none tracking-tight', props.class)"
>
<slot />
</DialogTitle>
</template>

View File

@@ -1,11 +1,11 @@
<script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from 'radix-vue'
import { DialogTrigger, type DialogTriggerProps } from 'radix-vue';
const props = defineProps<DialogTriggerProps>()
const props = defineProps<DialogTriggerProps>();
</script>
<template>
<DialogTrigger v-bind="props">
<slot />
</DialogTrigger>
<DialogTrigger v-bind="props">
<slot />
</DialogTrigger>
</template>

View File

@@ -1,9 +1,9 @@
export { default as Dialog } from './Dialog.vue'
export { default as DialogClose } from './DialogClose.vue'
export { default as DialogContent } from './DialogContent.vue'
export { default as DialogDescription } from './DialogDescription.vue'
export { default as DialogFooter } from './DialogFooter.vue'
export { default as DialogHeader } from './DialogHeader.vue'
export { default as DialogScrollContent } from './DialogScrollContent.vue'
export { default as DialogTitle } from './DialogTitle.vue'
export { default as DialogTrigger } from './DialogTrigger.vue'
export { default as Dialog } from './Dialog.vue';
export { default as DialogClose } from './DialogClose.vue';
export { default as DialogContent } from './DialogContent.vue';
export { default as DialogDescription } from './DialogDescription.vue';
export { default as DialogFooter } from './DialogFooter.vue';
export { default as DialogHeader } from './DialogHeader.vue';
export { default as DialogScrollContent } from './DialogScrollContent.vue';
export { default as DialogTitle } from './DialogTitle.vue';
export { default as DialogTrigger } from './DialogTrigger.vue';

View File

@@ -1,23 +1,23 @@
<script setup lang="ts">
import type { NumberFieldRootEmits, NumberFieldRootProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { NumberFieldRoot, useForwardPropsEmits } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils';
import type { NumberFieldRootEmits, NumberFieldRootProps } from 'radix-vue';
import { NumberFieldRoot, useForwardPropsEmits } from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<NumberFieldRootProps & { class?: HTMLAttributes['class'] }>()
const emits = defineEmits<NumberFieldRootEmits>()
const props = defineProps<NumberFieldRootProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<NumberFieldRootEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits)
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<NumberFieldRoot v-bind="forwarded" :class="cn('grid gap-1.5', props.class)">
<slot />
</NumberFieldRoot>
<NumberFieldRoot v-bind="forwarded" :class="cn('grid gap-1.5', props.class)">
<slot />
</NumberFieldRoot>
</template>

View File

@@ -1,14 +1,21 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { cn } from '@/lib/utils';
import type { HTMLAttributes } from 'vue';
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
class?: HTMLAttributes['class'];
}>();
</script>
<template>
<div :class="cn('relative [&>[data-slot=input]]:has-[[data-slot=increment]]:pr-5 [&>[data-slot=input]]:has-[[data-slot=decrement]]:pl-5', props.class)">
<slot />
</div>
<div
:class="
cn(
'relative [&>[data-slot=input]]:has-[[data-slot=decrement]]:pl-5 [&>[data-slot=input]]:has-[[data-slot=increment]]:pr-5',
props.class
)
"
>
<slot />
</div>
</template>

View File

@@ -1,25 +1,34 @@
<script setup lang="ts">
import type { NumberFieldDecrementProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { Minus } from 'lucide-vue-next'
import { NumberFieldDecrement, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils';
import { Minus } from 'lucide-vue-next';
import type { NumberFieldDecrementProps } from 'radix-vue';
import { NumberFieldDecrement, useForwardProps } from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<NumberFieldDecrementProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<NumberFieldDecrementProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwarded = useForwardProps(delegatedProps)
const forwarded = useForwardProps(delegatedProps);
</script>
<template>
<NumberFieldDecrement data-slot="decrement" v-bind="forwarded" :class="cn('absolute top-1/2 -translate-y-1/2 left-0 p-3 disabled:cursor-not-allowed disabled:opacity-20', props.class)">
<slot>
<Minus class="h-4 w-4" />
</slot>
</NumberFieldDecrement>
<NumberFieldDecrement
data-slot="decrement"
v-bind="forwarded"
:class="
cn(
'absolute left-0 top-1/2 -translate-y-1/2 p-3 disabled:cursor-not-allowed disabled:opacity-20',
props.class
)
"
>
<slot>
<Minus class="h-4 w-4" />
</slot>
</NumberFieldDecrement>
</template>

View File

@@ -1,25 +1,34 @@
<script setup lang="ts">
import type { NumberFieldIncrementProps } from 'radix-vue'
import { cn } from '@/lib/utils'
import { Plus } from 'lucide-vue-next'
import { NumberFieldIncrement, useForwardProps } from 'radix-vue'
import { computed, type HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils';
import { Plus } from 'lucide-vue-next';
import type { NumberFieldIncrementProps } from 'radix-vue';
import { NumberFieldIncrement, useForwardProps } from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<NumberFieldIncrementProps & { class?: HTMLAttributes['class'] }>()
const props = defineProps<NumberFieldIncrementProps & { class?: HTMLAttributes['class'] }>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props
const { class: _, ...delegated } = props;
return delegated
})
return delegated;
});
const forwarded = useForwardProps(delegatedProps)
const forwarded = useForwardProps(delegatedProps);
</script>
<template>
<NumberFieldIncrement data-slot="increment" v-bind="forwarded" :class="cn('absolute top-1/2 -translate-y-1/2 right-0 disabled:cursor-not-allowed disabled:opacity-20 p-3', props.class)">
<slot>
<Plus class="h-4 w-4" />
</slot>
</NumberFieldIncrement>
<NumberFieldIncrement
data-slot="increment"
v-bind="forwarded"
:class="
cn(
'absolute right-0 top-1/2 -translate-y-1/2 p-3 disabled:cursor-not-allowed disabled:opacity-20',
props.class
)
"
>
<slot>
<Plus class="h-4 w-4" />
</slot>
</NumberFieldIncrement>
</template>

View File

@@ -1,16 +1,21 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
import { NumberFieldInput } from 'radix-vue'
import { cn } from '@/lib/utils';
import { NumberFieldInput } from 'radix-vue';
import type { HTMLAttributes } from 'vue';
const props = defineProps<{
class?: HTMLAttributes['class']
}>()
class?: HTMLAttributes['class'];
}>();
</script>
<template>
<NumberFieldInput
data-slot="input"
:class="cn('flex h-10 w-full rounded-md border border-input bg-background py-2 text-sm text-center ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50', props.class)"
/>
<NumberFieldInput
data-slot="input"
:class="
cn(
'flex h-10 w-full rounded-md border border-input bg-background py-2 text-center text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
props.class
)
"
/>
</template>

View File

@@ -1,5 +1,5 @@
export { default as NumberField } from './NumberField.vue'
export { default as NumberFieldContent } from './NumberFieldContent.vue'
export { default as NumberFieldDecrement } from './NumberFieldDecrement.vue'
export { default as NumberFieldIncrement } from './NumberFieldIncrement.vue'
export { default as NumberFieldInput } from './NumberFieldInput.vue'
export { default as NumberField } from './NumberField.vue';
export { default as NumberFieldContent } from './NumberFieldContent.vue';
export { default as NumberFieldDecrement } from './NumberFieldDecrement.vue';
export { default as NumberFieldIncrement } from './NumberFieldIncrement.vue';
export { default as NumberFieldInput } from './NumberFieldInput.vue';

View File

@@ -0,0 +1,45 @@
<script setup lang="ts">
import { cn } from '@/lib/utils';
import {
SwitchRoot,
type SwitchRootEmits,
type SwitchRootProps,
SwitchThumb,
useForwardPropsEmits
} from 'radix-vue';
import { computed, type HTMLAttributes } from 'vue';
const props = defineProps<SwitchRootProps & { class?: HTMLAttributes['class'] }>();
const emits = defineEmits<SwitchRootEmits>();
const delegatedProps = computed(() => {
const { class: _, ...delegated } = props;
return delegated;
});
const forwarded = useForwardPropsEmits(delegatedProps, emits);
</script>
<template>
<SwitchRoot
v-bind="forwarded"
:class="
cn(
'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
props.class
)
"
>
<SwitchThumb
:class="
cn(
'pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5'
)
"
>
<slot name="thumb" />
</SwitchThumb>
</SwitchRoot>
</template>

View File

@@ -0,0 +1 @@
export { default as Switch } from './Switch.vue';

View File

@@ -5,10 +5,10 @@ export { default as Toast } from './Toast.vue';
export { default as ToastAction } from './ToastAction.vue';
export { default as ToastClose } from './ToastClose.vue';
export { default as ToastDescription } from './ToastDescription.vue';
export { default as Toaster } from './Toaster.vue';
export { default as ToastProvider } from './ToastProvider.vue';
export { default as ToastTitle } from './ToastTitle.vue';
export { default as ToastViewport } from './ToastViewport.vue';
export { default as Toaster } from './Toaster.vue';
export { toast, useToast } from './use-toast';
import { cva, type VariantProps } from 'class-variance-authority';

View File

@@ -3,68 +3,9 @@ useHead({
title: "Garand's WG | Wykresy i statystyki"
});
interface DataForCharts {
states: {
config: Config;
burgs: ChartData[];
provinces: ChartData[];
cells: ChartData[];
culturesCells: ChartData[];
religionCells: ChartData[];
biomesCells: ChartData[];
ruralPopulation: ChartData[];
urbanPopulation: ChartData[];
forms: ChartData[];
};
provinces: {
config: Config;
burgs: ChartData[];
cells: ChartData[];
ruralPopulation: ChartData[];
urbanPopulation: ChartData[];
forms: ChartData[];
};
burgs: {
config: Config;
population: ChartData[];
religions: ChartData[];
cultures: ChartData[];
capitals: ChartData[];
ports: ChartData[];
cities: ChartData[];
walls: ChartData[];
plazas: ChartData[];
temples: ChartData[];
shantyTowns: ChartData[];
};
cultures: {
config: Config;
cells: ChartData[];
population: ChartData[];
types: ChartData[];
namesbases: ChartData[];
};
religions: {
config: Config;
cells: ChartData[];
population: ChartData[];
types: ChartData[];
forms: ChartData[];
};
}
import type { ChartData, Config, DataForCharts } from '@/types/chartsTypes';
interface ChartData {
turn: number;
[key: string]: number;
}
interface Config {
categories: string[];
colors?: string[];
}
const pb = usePocketBase();
const data = useChartsAndStatsStore();
const data = cacheFullListResponses();
const turnsData = await data.fetchTurnsData();
const statesData = await data.fetchStatesData();
@@ -76,50 +17,55 @@ const religionsData = await data.fetchReligionsData();
const dataForCharts: DataForCharts = {
states: {
config: { categories: [], colors: [] },
burgs: [],
provinces: [],
cells: [],
culturesCells: [],
religionCells: [],
biomesCells: [],
ruralPopulation: [],
urbanPopulation: [],
forms: []
charts: {
burgs: [],
provinces: [],
cells: [],
ruralPopulation: [],
urbanPopulation: []
}
},
provinces: {
config: { categories: [], colors: [] },
burgs: [],
cells: [],
ruralPopulation: [],
urbanPopulation: [],
forms: []
charts: {
burgs: [],
cells: [],
ruralPopulation: [],
urbanPopulation: []
}
},
burgs: {
config: { categories: [], colors: [] },
population: [],
religions: [],
cultures: [],
capitals: [],
ports: [],
cities: [],
walls: [],
plazas: [],
temples: [],
shantyTowns: []
charts: {
population: [],
religions: [],
cultures: [],
capitals: [],
ports: [],
cities: [],
walls: [],
plazas: [],
temples: [],
shantyTowns: []
}
},
cultures: {
config: { categories: [], colors: [] },
cells: [],
population: [],
types: [],
namesbases: []
charts: {
cells: [],
population: [],
types: [],
namesbases: []
}
},
religions: {
config: { categories: [], colors: [] },
cells: [],
population: [],
types: [],
forms: []
charts: {
cells: [],
population: [],
types: [],
forms: []
}
}
};
@@ -139,67 +85,61 @@ for (let i = 0; i < configsDataSets.length; i++) {
if (dataset.data[0].color) config.colors = dataset.data.map(item => item.color);
}
for (let i = 0; i < turnsData.length - 1; i++) {
for (let i = 0; i < turnsData.length - 0; i++) {
const turn = turnsData[i];
const statesBurgsDataItem: ChartData = { turn: turn.value };
const statesProvincesDataItem: ChartData = { turn: turn.value };
const statesCellsDataItem: ChartData = { turn: turn.value };
const culturesCellsDataItem: ChartData = { turn: turn.value };
const religionCellsDataItem: ChartData = { turn: turn.value };
const biomesCellsDataItem: ChartData = { turn: turn.value };
const ruralPopulationDataItem: ChartData = { turn: turn.value };
const urbanPopulationDataItem: ChartData = { turn: turn.value };
const formsDataItem: ChartData = { turn: turn.value };
// TODO: Dokończyć resztę DataItems'ów
const statesDataItems: ChartData[] = [
{ turn: turn.value },
{ turn: turn.value },
{ turn: turn.value },
{ turn: turn.value },
{ turn: turn.value }
];
for (let j = 0; j < statesData.length; j++) {
const state = statesData[j];
const provincesDataItems: ChartData[] = [
{ turn: turn.value },
{ turn: turn.value },
{ turn: turn.value },
{ turn: turn.value }
];
statesBurgsDataItem[state.name] = state.burgs;
statesProvincesDataItem[state.name] = provincesData.filter(
for (let i = 0; i < statesData.length; i++) {
const state = statesData[i];
statesDataItems[0][state.name] = state.burgs;
statesDataItems[1][state.name] = provincesData.filter(
province => province.turn === turn.id && province.state === state.id
).length;
statesCellsDataItem[state.name] = state.cells;
statesDataItems[2][state.name] = state.cells;
statesDataItems[3][state.name] = state.ruralPopulation;
statesDataItems[4][state.name] = state.urbanPopulation;
}
dataForCharts.states.burgs.push(statesBurgsDataItem);
dataForCharts.states.provinces.push(statesProvincesDataItem);
dataForCharts.states.cells.push(statesCellsDataItem);
dataForCharts.states.charts.burgs.push(statesDataItems[0]);
dataForCharts.states.charts.provinces.push(statesDataItems[1]);
dataForCharts.states.charts.cells.push(statesDataItems[2]);
dataForCharts.states.charts.ruralPopulation.push(statesDataItems[3]);
dataForCharts.states.charts.urbanPopulation.push(statesDataItems[4]);
for (let i = 0; i < provincesData.length; i++) {
const province = provincesData[i];
provincesDataItems[0][province.name] = province.burgs;
provincesDataItems[1][province.name] = province.cells;
provincesDataItems[2][province.name] = province.ruralPopulation;
provincesDataItems[3][province.name] = province.urbanPopulation;
}
dataForCharts.provinces.charts.burgs.push(provincesDataItems[0]);
dataForCharts.provinces.charts.cells.push(provincesDataItems[1]);
dataForCharts.provinces.charts.ruralPopulation.push(provincesDataItems[2]);
dataForCharts.provinces.charts.urbanPopulation.push(provincesDataItems[3]);
}
console.log(dataForCharts);
// console.log(provincesData);
// console.table(statesData);
// console.table(provincesData);
// console.table(burgsData);
// console.table(culturesData);
// console.table(religionsData);
// console.log(statesData);
// TODO: dodać wykresy z shadcn-vue https://www.shadcn-vue.com/docs/charts.html
// TODO: Statystyki państw na przestrzeni tur, kolor z pola color:
// - ilość miast - liniowy,
// - ilość prowincji - liniowy,
// - ilość kratek - liniowy,
// - ilość kratek danej kultury - słupkowy,
// - ilość kratek danej religii - słupkowy,
// - ilość kratek danego biomu - słupkowy,z
// - ilość populacji wiejskiej - liniowy,
// - ilość populacji miejskiej - liniowy,
// - ilość danych form rządu - liniowy
// TODO: Statystyki prowincji na przestrzeni tur, kolor z pola color:
// - ilość miast - liniowy,
// - ilość kratek - liniowy,
// - ilość populacji wiejskiej - liniowy,
// - ilość populacji miejskiej - liniowy,
// - ilość danych form rządu - liniowy
// TODO: Statystyki miast na przestrzeni tur, kolor z pola color:
// - ilość populacji - liniowy,
// - ilość religii - liniowy,
@@ -224,44 +164,134 @@ console.log(dataForCharts);
// - ilość danych typów religii - liniowy,
// - ilość danych form religii - liniowy,
const tabs: { [key: string]: string } = {
states: 'Państwa',
provinces: 'Prowincje',
burgs: 'Miasta',
cultures: 'Kultury',
religions: 'Religie'
};
const tabs: {
name: string;
label: string;
description: string;
props: {
config: Config;
labels: string[];
charts: Record<string, ChartData[]>;
};
}[] = [
{
name: 'states',
label: 'Państwa',
description: 'Statystyki państw',
props: {
config: dataForCharts.states.config,
labels: [
'Ilość miast',
'Ilość prowincji',
'Ilość kratek',
'Ilość populacji wiejskiej ',
'Ilość populacji miejskiej'
],
charts: dataForCharts.states.charts
}
},
{
name: 'provinces',
label: 'Prowincje',
description: 'Statystyki prowincji',
props: {
config: dataForCharts.provinces.config,
labels: [
'Ilość miast',
'Ilość kratek',
'Ilość populacji wiejskiej ',
'Ilość populacji miejskiej'
],
charts: dataForCharts.provinces.charts
}
},
{
name: 'burgs',
label: 'Miasta',
description: 'Statystyki miast',
props: {
config: dataForCharts.burgs.config,
charts: dataForCharts.burgs.charts
}
},
{
name: 'cultures',
label: 'Kultury',
description: 'Statystyki kultur',
props: {
config: dataForCharts.cultures.config,
charts: dataForCharts.cultures.charts
}
},
{
name: 'religions',
label: 'Religie',
description: 'Statystyki religii',
props: {
config: dataForCharts.religions.config,
charts: dataForCharts.religions.charts
}
}
];
console.log(tabs);
</script>
<template>
<div class="mt-12 flex h-screen items-center justify-center">
<Tabs
class="flex w-full flex-col items-center justify-center"
:default-value="tabs[Object.keys(tabs)[0]]"
>
<Tabs class="flex w-full flex-col items-center justify-center" :default-value="tabs[0].name">
<TabsList class="w-full items-center justify-center">
<TabsTrigger v-for="(tab, key) in tabs" :key="key" :value="tab"> {{ tab }}</TabsTrigger>
<TabsTrigger v-for="tab in tabs" :key="tab.name" :value="tab.name">
{{ tab.label }}
</TabsTrigger>
</TabsList>
<TabsContent
v-for="(tab, key) in tabs"
:key="key"
:value="tab"
v-for="tab in tabs"
:key="tab.name"
:value="tab.name"
class="h-screen w-full flex-col items-center justify-center"
>
<Card>
<CardHeader>
<CardTitle>
{{ tab }}
<!-- {{ props.title }} Numer <span class="text-primary">{{ turn.value }}</span> -->
{{ tab.label }}
</CardTitle>
<CardDescription> Jeżyk </CardDescription>
<CardDescription class="flex flex-col">
{{ tab.description }}
<Label class="mb-2 mt-5"> Jakiego tooltip'a użyć? </Label>
<div>
<RadioGroup default-value="option-one">
<div class="flex items-center space-x-2">
<RadioGroupItem id="option-one" value="option-one" />
<Label for="option-one">Klasycznego</Label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem id="option-two" value="option-two" />
<Label for="option-two">Uproszczonego</Label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem id="option-three" value="option-three" />
<Label for="option-three">Najlepsi i najgorsi</Label>
</div>
</RadioGroup>
</div>
</CardDescription>
</CardHeader>
<Separator />
<CardContent class="space-y-2 py-6"> </CardContent>
<CardContent class="space-y-2 py-6">
<!-- <component :is="tab.component" v-bind="tab.props" /> -->
<ChartComponent
:config="tab.props.config"
:charts="tab.props.charts"
:labels="tab.props.labels"
/>
</CardContent>
</Card>
</TabsContent>
</Tabs>

BIN
src/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -1,6 +1,6 @@
const ONE_HOUR = 60 * 60 * 1000; // 1 godzina w milisekundach
// TODO: Napisać unit testy dla useChartsAndStatsStore
export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () => {
// TODO: Napisać unit testy dla cacheFullListResponses
export const cacheFullListResponses = defineStore('cacheFullListResponses', () => {
const pb = usePocketBase();
const turnsData = ref(null);
@@ -20,7 +20,7 @@ export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () =
const fetchStatesData = async () => {
if (statesData.value && isCached('statesData')) return statesData.value;
const data = await pb.collection('states').getFullList({ expand: 'turn' });
const data = await pb.collection('states').getFullList();
statesData.value = data;
cacheData('statesData', data);
return data;
@@ -28,7 +28,7 @@ export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () =
const fetchProvincesData = async () => {
if (provincesData.value && isCached('provincesData')) return provincesData.value;
const data = await pb.collection('provinces').getFullList({ expand: 'turn' });
const data = await pb.collection('provinces').getFullList();
provincesData.value = data;
cacheData('provincesData', data);
return data;
@@ -36,7 +36,7 @@ export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () =
const fetchBurgsData = async () => {
if (burgsData.value && isCached('burgsData')) return burgsData.value;
const data = await pb.collection('burgs').getFullList({ expand: 'turn' });
const data = await pb.collection('burgs').getFullList();
burgsData.value = data;
cacheData('burgsData', data);
return data;
@@ -44,7 +44,7 @@ export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () =
const fetchCulturesData = async () => {
if (culturesData.value && isCached('culturesData')) return culturesData.value;
const data = await pb.collection('cultures').getFullList({ expand: 'turn' });
const data = await pb.collection('cultures').getFullList();
culturesData.value = data;
cacheData('culturesData', data);
return data;
@@ -52,7 +52,7 @@ export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () =
const fetchReligionsData = async () => {
if (religionsData.value && isCached('religionsData')) return religionsData.value;
const data = await pb.collection('religions').getFullList({ expand: 'turn' });
const data = await pb.collection('religions').getFullList();
religionsData.value = data;
cacheData('religionsData', data);
return data;
@@ -70,12 +70,12 @@ export const useChartsAndStatsStore = defineStore('useChartsAndStatsStore', () =
};
return {
turnsData,
statesData,
provincesData,
burgsData,
culturesData,
religionsData,
// turnsData,
// statesData,
// provincesData,
// burgsData,
// culturesData,
// religionsData,
fetchTurnsData,
fetchStatesData,
fetchProvincesData,

View File

@@ -6,7 +6,7 @@
// biome-ignore lint: disable
export {}
declare global {
const BarChart: typeof import('../components/ui/chart-bar/index')['BarChart']
const BarChart: (typeof import('../components/ui/chart-bar/index'))['BarChart']
const Button: typeof import('../components/ui/button/index')['Button']
const Card: typeof import('../components/ui/card/index')['Card']
const CardContent: typeof import('../components/ui/card/index')['CardContent']
@@ -70,12 +70,13 @@ declare global {
const PopoverTrigger: typeof import('../components/ui/popover/index')['PopoverTrigger']
const RadioGroup: typeof import('../components/ui/radio-group/index')['RadioGroup']
const RadioGroupItem: typeof import('../components/ui/radio-group/index')['RadioGroupItem']
const ResizableHandle: typeof import('../components/ui/resizable/index')['ResizableHandle']
const ResizablePanel: typeof import('../components/ui/resizable/index')['ResizablePanel']
const ResizablePanelGroup: typeof import('../components/ui/resizable/index')['ResizablePanelGroup']
const ResizableHandle: (typeof import('../components/ui/resizable/index'))['ResizableHandle']
const ResizablePanel: (typeof import('../components/ui/resizable/index'))['ResizablePanel']
const ResizablePanelGroup: (typeof import('../components/ui/resizable/index'))['ResizablePanelGroup']
const ScrollArea: typeof import('../components/ui/scroll-area/index')['ScrollArea']
const ScrollBar: typeof import('../components/ui/scroll-area/index')['ScrollBar']
const Separator: typeof import('../components/ui/separator/index')['Separator']
const Switch: typeof import('../components/ui/switch/index')['Switch']
const Tabs: typeof import('../components/ui/tabs/index')['Tabs']
const TabsContent: typeof import('../components/ui/tabs/index')['TabsContent']
const TabsList: typeof import('../components/ui/tabs/index')['TabsList']
@@ -97,8 +98,9 @@ declare global {
const beforeAll: typeof import('vitest')['beforeAll']
const beforeEach: typeof import('vitest')['beforeEach']
const buttonVariants: typeof import('../components/ui/button/index')['buttonVariants']
const cacheFullListResponses: typeof import('../stores/useCacheFullListResponsesStore')['cacheFullListResponses']
const chai: typeof import('vitest')['chai']
const chartsAndStatsStore: typeof import('../stores/chartsAndStatsStore')['chartsAndStatsStore']
const chartsAndStatsStore: (typeof import('../stores/useCacheFullListResponsesStore'))['chartsAndStatsStore']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
@@ -246,9 +248,9 @@ declare global {
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
const useCacheStore: typeof import('../stores/chartsAndStatsStore')['useCacheStore']
const useCacheStore: (typeof import('../stores/useCacheFullListResponsesStore'))['useCacheStore']
const useCached: typeof import('@vueuse/core')['useCached']
const useChartsAndStatsStore: typeof import('../stores/chartsAndStatsStore')['useChartsAndStatsStore']
const useChartsAndStatsStore: (typeof import('../stores/useCacheFullListResponsesStore'))['useChartsAndStatsStore']
const useClipboard: typeof import('@vueuse/core')['useClipboard']
const useClipboardItems: typeof import('@vueuse/core')['useClipboardItems']
const useCloned: typeof import('@vueuse/core')['useCloned']
@@ -261,7 +263,7 @@ declare global {
const useCurrentElement: typeof import('@vueuse/core')['useCurrentElement']
const useCycleList: typeof import('@vueuse/core')['useCycleList']
const useDark: typeof import('@vueuse/core')['useDark']
const useDataStore: typeof import('../stores/chartsAndStatsStore')['useDataStore']
const useDataStore: (typeof import('../stores/useCacheFullListResponsesStore'))['useDataStore']
const useDateFormat: typeof import('@vueuse/core')['useDateFormat']
const useDebounce: typeof import('@vueuse/core')['useDebounce']
const useDebounceFn: typeof import('@vueuse/core')['useDebounceFn']

66
src/types/chartsTypes.ts Normal file
View File

@@ -0,0 +1,66 @@
interface DataForCharts {
states: {
config: Config;
charts: {
burgs: ChartData[];
provinces: ChartData[];
cells: ChartData[];
ruralPopulation: ChartData[];
urbanPopulation: ChartData[];
};
};
provinces: {
config: Config;
charts: {
burgs: ChartData[];
cells: ChartData[];
ruralPopulation: ChartData[];
urbanPopulation: ChartData[];
};
};
burgs: {
config: Config;
charts: {
population: ChartData[];
religions: ChartData[];
cultures: ChartData[];
capitals: ChartData[];
ports: ChartData[];
cities: ChartData[];
walls: ChartData[];
plazas: ChartData[];
temples: ChartData[];
shantyTowns: ChartData[];
};
};
cultures: {
config: Config;
charts: {
cells: ChartData[];
population: ChartData[];
types: ChartData[];
namesbases: ChartData[];
};
};
religions: {
config: Config;
charts: {
cells: ChartData[];
population: ChartData[];
types: ChartData[];
forms: ChartData[];
};
};
}
interface ChartData {
turn: number;
[key: string]: number;
}
interface Config {
categories: string[];
colors?: string[];
}
export type { ChartData, Config, DataForCharts };

View File

@@ -16,6 +16,8 @@ declare module 'vue' {
CardFooter: typeof import('./../components/ui/card/CardFooter.vue')['default']
CardHeader: typeof import('./../components/ui/card/CardHeader.vue')['default']
CardTitle: typeof import('./../components/ui/card/CardTitle.vue')['default']
Chart: typeof import('../components/charts-and-stats/chartComponent.vue')['default']
ChartComponent: typeof import('./../components/charts-and-stats/chartComponent.vue')['default']
ChartCrosshair: typeof import('./../components/ui/chart/ChartCrosshair.vue')['default']
ChartLegend: typeof import('./../components/ui/chart/ChartLegend.vue')['default']
ChartSingleTooltip: typeof import('./../components/ui/chart/ChartSingleTooltip.vue')['default']
@@ -106,7 +108,8 @@ declare module 'vue' {
SidebarRail: typeof import('./../components/ui/sidebar/SidebarRail.vue')['default']
SidebarSeparator: typeof import('./../components/ui/sidebar/SidebarSeparator.vue')['default']
SidebarTrigger: typeof import('./../components/ui/sidebar/SidebarTrigger.vue')['default']
StatesCharts: typeof import('./../components/charts-and-stats/statesCharts.vue')['default']
StatesCharts: typeof import('../components/charts-and-stats/chartComponent.vue')['default']
Switch: typeof import('./../components/ui/switch/Switch.vue')['default']
Tabs: typeof import('./../components/ui/tabs/Tabs.vue')['default']
TabsContent: typeof import('./../components/ui/tabs/TabsContent.vue')['default']
TabsList: typeof import('./../components/ui/tabs/TabsList.vue')['default']

View File

@@ -1,376 +1,393 @@
/**
* This file was @generated using pocketbase-typegen
*/
* This file was @generated using pocketbase-typegen
*/
import type PocketBase from 'pocketbase'
import type { RecordService } from 'pocketbase'
import type PocketBase from 'pocketbase';
import type { RecordService } from 'pocketbase';
export enum Collections {
Burgs = "burgs",
Cultures = "cultures",
Maps = "maps",
Provinces = "provinces",
Religions = "religions",
ReportInputs = "reportInputs",
ReportOutputs = "reportOutputs",
Reports = "reports",
States = "states",
Turns = "turns",
Users = "users",
Burgs = 'burgs',
Cultures = 'cultures',
Maps = 'maps',
Provinces = 'provinces',
Religions = 'religions',
ReportInputs = 'reportInputs',
ReportOutputs = 'reportOutputs',
Reports = 'reports',
States = 'states',
Turns = 'turns',
Users = 'users'
}
// Alias types for improved usability
export type IsoDateString = string
export type RecordIdString = string
export type HTMLString = string
export type IsoDateString = string;
export type RecordIdString = string;
export type HTMLString = string;
// System fields
export type BaseSystemFields<T = never> = {
id: RecordIdString
created: IsoDateString
updated: IsoDateString
collectionId: string
collectionName: Collections
expand?: T
}
id: RecordIdString;
created: IsoDateString;
updated: IsoDateString;
collectionId: string;
collectionName: Collections;
expand?: T;
};
export type AuthSystemFields<T = never> = {
email: string
emailVisibility: boolean
username: string
verified: boolean
} & BaseSystemFields<T>
email: string;
emailVisibility: boolean;
username: string;
verified: boolean;
} & BaseSystemFields<T>;
// Record types for each collection
export type BurgsRecord<Temblem = unknown> = {
cityGeneratorLink: string
culture: RecordIdString
emblem: null | Temblem
isCapital?: boolean
isCitadel?: boolean
isPlaza?: boolean
isPort?: boolean
isShantyTown?: boolean
isTemple?: boolean
isWalls?: boolean
name: string
population?: number
province?: RecordIdString
religion: RecordIdString
state: RecordIdString
turn: RecordIdString
}
cityGeneratorLink: string;
culture: RecordIdString;
emblem: null | Temblem;
isCapital?: boolean;
isCitadel?: boolean;
isPlaza?: boolean;
isPort?: boolean;
isShantyTown?: boolean;
isTemple?: boolean;
isWalls?: boolean;
name: string;
population?: number;
province?: RecordIdString;
religion: RecordIdString;
state: RecordIdString;
turn: RecordIdString;
};
export enum CulturesTypeOptions {
"Generic" = "Generic",
"River" = "River",
"Lake" = "Lake",
"Naval" = "Naval",
"Nomadic" = "Nomadic",
"Hunting" = "Hunting",
"Highland" = "Highland",
'Generic' = 'Generic',
'River' = 'River',
'Lake' = 'Lake',
'Naval' = 'Naval',
'Nomadic' = 'Nomadic',
'Hunting' = 'Hunting',
'Highland' = 'Highland'
}
export enum CulturesNamesbaseOptions {
"German" = "German",
"English" = "English",
"French" = "French",
"Italian" = "Italian",
"Castillian" = "Castillian",
"Ruthenian" = "Ruthenian",
"Nordic" = "Nordic",
"Greek" = "Greek",
"Roman" = "Roman",
"Finnic" = "Finnic",
"Korean" = "Korean",
"Chinese" = "Chinese",
"Japanese" = "Japanese",
"Portuguese" = "Portuguese",
"Nahuatl" = "Nahuatl",
"Hungarian" = "Hungarian",
"Turkish" = "Turkish",
"Berber" = "Berber",
"Arabic" = "Arabic",
"Inuit" = "Inuit",
"Basque" = "Basque",
"Nigerian" = "Nigerian",
"Celtic" = "Celtic",
"Mesopotamian" = "Mesopotamian",
"Iranian" = "Iranian",
"Hawaiian" = "Hawaiian",
"Karnataka" = "Karnataka",
"Quechua" = "Quechua",
"Swahili" = "Swahili",
"Vietnamese" = "Vietnamese",
"Cantonese" = "Cantonese",
"Mongolian" = "Mongolian",
"Human Generic" = "Human Generic",
"Elven" = "Elven",
"Dark Elven" = "Dark Elven",
"Dwarven" = "Dwarven",
"Goblin" = "Goblin",
"Orc" = "Orc",
"Giant" = "Giant",
"Draconic" = "Draconic",
"Arachnid" = "Arachnid",
"Serpents" = "Serpents",
"Levantine" = "Levantine",
'German' = 'German',
'English' = 'English',
'French' = 'French',
'Italian' = 'Italian',
'Castillian' = 'Castillian',
'Ruthenian' = 'Ruthenian',
'Nordic' = 'Nordic',
'Greek' = 'Greek',
'Roman' = 'Roman',
'Finnic' = 'Finnic',
'Korean' = 'Korean',
'Chinese' = 'Chinese',
'Japanese' = 'Japanese',
'Portuguese' = 'Portuguese',
'Nahuatl' = 'Nahuatl',
'Hungarian' = 'Hungarian',
'Turkish' = 'Turkish',
'Berber' = 'Berber',
'Arabic' = 'Arabic',
'Inuit' = 'Inuit',
'Basque' = 'Basque',
'Nigerian' = 'Nigerian',
'Celtic' = 'Celtic',
'Mesopotamian' = 'Mesopotamian',
'Iranian' = 'Iranian',
'Hawaiian' = 'Hawaiian',
'Karnataka' = 'Karnataka',
'Quechua' = 'Quechua',
'Swahili' = 'Swahili',
'Vietnamese' = 'Vietnamese',
'Cantonese' = 'Cantonese',
'Mongolian' = 'Mongolian',
'Human Generic' = 'Human Generic',
'Elven' = 'Elven',
'Dark Elven' = 'Dark Elven',
'Dwarven' = 'Dwarven',
'Goblin' = 'Goblin',
'Orc' = 'Orc',
'Giant' = 'Giant',
'Draconic' = 'Draconic',
'Arachnid' = 'Arachnid',
'Serpents' = 'Serpents',
'Levantine' = 'Levantine'
}
export type CulturesRecord = {
cells?: number
color?: string
name: string
namesbase: CulturesNamesbaseOptions
population?: number
turn: RecordIdString
type?: CulturesTypeOptions
}
cells?: number;
color?: string;
name: string;
namesbase: CulturesNamesbaseOptions;
population?: number;
turn: RecordIdString;
type?: CulturesTypeOptions;
};
export type MapsRecord = {
file: string
name: string
turn?: RecordIdString
}
file: string;
name: string;
turn?: RecordIdString;
};
export enum ProvincesFormOptions {
"Area" = "Area",
"Autonomy" = "Autonomy",
"Barony" = "Barony",
"Canton" = "Canton",
"Captaincy" = "Captaincy",
"Chiefdom" = "Chiefdom",
"Clan" = "Clan",
"Colony" = "Colony",
"Council" = "Council",
"County" = "County",
"Deanery" = "Deanery",
"Department" = "Department",
"Dependency" = "Dependency",
"Diaconate" = "Diaconate",
"District" = "District",
"Earldom" = "Earldom",
"Governorate" = "Governorate",
"Island" = "Island",
"Islands" = "Islands",
"Land" = "Land",
"Landgrave" = "Landgrave",
"Mandate" = "Mandate",
"Margrave" = "Margrave",
"Municipality" = "Municipality",
"Occupation zone" = "Occupation zone",
"Parish" = "Parish",
"Prefecture" = "Prefecture",
"Province" = "Province",
"Region" = "Region",
"Republic" = "Republic",
"Reservation" = "Reservation",
"Seneschalty" = "Seneschalty",
"Shire" = "Shire",
"State" = "State",
"Territory" = "Territory",
"Tribe" = "Tribe",
'Area' = 'Area',
'Autonomy' = 'Autonomy',
'Barony' = 'Barony',
'Canton' = 'Canton',
'Captaincy' = 'Captaincy',
'Chiefdom' = 'Chiefdom',
'Clan' = 'Clan',
'Colony' = 'Colony',
'Council' = 'Council',
'County' = 'County',
'Deanery' = 'Deanery',
'Department' = 'Department',
'Dependency' = 'Dependency',
'Diaconate' = 'Diaconate',
'District' = 'District',
'Earldom' = 'Earldom',
'Governorate' = 'Governorate',
'Island' = 'Island',
'Islands' = 'Islands',
'Land' = 'Land',
'Landgrave' = 'Landgrave',
'Mandate' = 'Mandate',
'Margrave' = 'Margrave',
'Municipality' = 'Municipality',
'Occupation zone' = 'Occupation zone',
'Parish' = 'Parish',
'Prefecture' = 'Prefecture',
'Province' = 'Province',
'Region' = 'Region',
'Republic' = 'Republic',
'Reservation' = 'Reservation',
'Seneschalty' = 'Seneschalty',
'Shire' = 'Shire',
'State' = 'State',
'Territory' = 'Territory',
'Tribe' = 'Tribe'
}
export type ProvincesRecord = {
burgs?: number
capital?: string
cells?: number
color: string
form: ProvincesFormOptions
name: string
nameFull: string
ruralPopulation?: number
state: RecordIdString
turn: RecordIdString
urbanPopulation?: number
}
burgs?: number;
capital?: string;
cells?: number;
color: string;
form: ProvincesFormOptions;
name: string;
nameFull: string;
ruralPopulation?: number;
state: RecordIdString;
turn: RecordIdString;
urbanPopulation?: number;
};
export enum ReligionsTypeOptions {
"Organized" = "Organized",
"Heresy" = "Heresy",
"Cult" = "Cult",
"Folk" = "Folk",
'Organized' = 'Organized',
'Heresy' = 'Heresy',
'Cult' = 'Cult',
'Folk' = 'Folk'
}
export type ReligionsRecord = {
cells?: number
color?: string
form?: string
name: string
population?: number
supremeDeity?: string
turn: RecordIdString
type?: ReligionsTypeOptions
}
cells?: number;
color?: string;
form?: string;
name: string;
population?: number;
supremeDeity?: string;
turn: RecordIdString;
type?: ReligionsTypeOptions;
};
export type ReportInputsRecord = {
sdad?: string
}
sdad?: string;
};
export type ReportOutputsRecord = {
sadasds?: string
}
sadasds?: string;
};
export type ReportsRecord = {
reportInput: RecordIdString
reportOutput: RecordIdString
state: RecordIdString
turn: RecordIdString
}
reportInput: RecordIdString;
reportOutput: RecordIdString;
state: RecordIdString;
turn: RecordIdString;
};
export enum StatesFormOptions {
"Beylik" = "Beylik",
"Despotate" = "Despotate",
"Dominion" = "Dominion",
"Duchy" = "Duchy",
"Emirate" = "Emirate",
"Empire" = "Empire",
"Horde" = "Horde",
"Grand Duchy" = "Grand Duchy",
"Heptarchy" = "Heptarchy",
"Khaganate" = "Khaganate",
"Khanate" = "Khanate",
"Kingdom" = "Kingdom",
"Marches" = "Marches",
"Principality" = "Principality",
"Satrapy" = "Satrapy",
"Shogunate" = "Shogunate",
"Sultanate" = "Sultanate",
"Tsardom" = "Tsardom",
"Ulus" = "Ulus",
"Viceroyalty" = "Viceroyalty",
"Chancellery" = "Chancellery",
"City-state" = "City-state",
"Diarchy" = "Diarchy",
"Federation" = "Federation",
"Free City" = "Free City",
"Most Serene Republic" = "Most Serene Republic",
"Oligarchy" = "Oligarchy",
"Protectorate" = "Protectorate",
"Republic" = "Republic",
"Tetrarchy" = "Tetrarchy",
"Trade Company" = "Trade Company",
"Triumvirate" = "Triumvirate",
"Confederacy" = "Confederacy",
"Confederation" = "Confederation",
"Conglomerate" = "Conglomerate",
"Commonwealth" = "Commonwealth",
"League" = "League",
"Union" = "Union",
"United Hordes" = "United Hordes",
"United Kingdom" = "United Kingdom",
"United Provinces" = "United Provinces",
"United Republic" = "United Republic",
"United States" = "United States",
"United Tribes" = "United Tribes",
"Bishopric" = "Bishopric",
"Brotherhood" = "Brotherhood",
"Caliphate" = "Caliphate",
"Diocese" = "Diocese",
"Divine Duchy" = "Divine Duchy",
"Divine Grand Duchy" = "Divine Grand Duchy",
"Divine Principality" = "Divine Principality",
"Divine Kingdom" = "Divine Kingdom",
"Divine Empire" = "Divine Empire",
"Eparchy" = "Eparchy",
"Exarchate" = "Exarchate",
"Holy State" = "Holy State",
"Imamah" = "Imamah",
"Patriarchate" = "Patriarchate",
"Theocracy" = "Theocracy",
"Commune" = "Commune",
"Community" = "Community",
"Council" = "Council",
"Free Territory" = "Free Territory",
"Tribes" = "Tribes",
}
export type StatesRecord<TbiomesCells = unknown, TculturesCells = unknown, TreligionsCells = unknown> = {
biomesCells?: null | TbiomesCells
burgs?: number
capital?: string
cells?: number
color?: string
culture?: RecordIdString
culturesCells?: null | TculturesCells
form?: StatesFormOptions
name: string
nameFull?: string
religionsCells?: null | TreligionsCells
ruralPopulation?: number
turn: RecordIdString
urbanPopulation?: number
user?: RecordIdString
'Beylik' = 'Beylik',
'Despotate' = 'Despotate',
'Dominion' = 'Dominion',
'Duchy' = 'Duchy',
'Emirate' = 'Emirate',
'Empire' = 'Empire',
'Horde' = 'Horde',
'Grand Duchy' = 'Grand Duchy',
'Heptarchy' = 'Heptarchy',
'Khaganate' = 'Khaganate',
'Khanate' = 'Khanate',
'Kingdom' = 'Kingdom',
'Marches' = 'Marches',
'Principality' = 'Principality',
'Satrapy' = 'Satrapy',
'Shogunate' = 'Shogunate',
'Sultanate' = 'Sultanate',
'Tsardom' = 'Tsardom',
'Ulus' = 'Ulus',
'Viceroyalty' = 'Viceroyalty',
'Chancellery' = 'Chancellery',
'City-state' = 'City-state',
'Diarchy' = 'Diarchy',
'Federation' = 'Federation',
'Free City' = 'Free City',
'Most Serene Republic' = 'Most Serene Republic',
'Oligarchy' = 'Oligarchy',
'Protectorate' = 'Protectorate',
'Republic' = 'Republic',
'Tetrarchy' = 'Tetrarchy',
'Trade Company' = 'Trade Company',
'Triumvirate' = 'Triumvirate',
'Confederacy' = 'Confederacy',
'Confederation' = 'Confederation',
'Conglomerate' = 'Conglomerate',
'Commonwealth' = 'Commonwealth',
'League' = 'League',
'Union' = 'Union',
'United Hordes' = 'United Hordes',
'United Kingdom' = 'United Kingdom',
'United Provinces' = 'United Provinces',
'United Republic' = 'United Republic',
'United States' = 'United States',
'United Tribes' = 'United Tribes',
'Bishopric' = 'Bishopric',
'Brotherhood' = 'Brotherhood',
'Caliphate' = 'Caliphate',
'Diocese' = 'Diocese',
'Divine Duchy' = 'Divine Duchy',
'Divine Grand Duchy' = 'Divine Grand Duchy',
'Divine Principality' = 'Divine Principality',
'Divine Kingdom' = 'Divine Kingdom',
'Divine Empire' = 'Divine Empire',
'Eparchy' = 'Eparchy',
'Exarchate' = 'Exarchate',
'Holy State' = 'Holy State',
'Imamah' = 'Imamah',
'Patriarchate' = 'Patriarchate',
'Theocracy' = 'Theocracy',
'Commune' = 'Commune',
'Community' = 'Community',
'Council' = 'Council',
'Free Territory' = 'Free Territory',
'Tribes' = 'Tribes'
}
export type StatesRecord<
TbiomesCells = unknown,
TculturesCells = unknown,
TreligionsCells = unknown
> = {
biomesCells?: null | TbiomesCells;
burgs?: number;
capital?: string;
cells?: number;
color?: string;
culture?: RecordIdString;
culturesCells?: null | TculturesCells;
form?: StatesFormOptions;
name: string;
nameFull?: string;
religionsCells?: null | TreligionsCells;
ruralPopulation?: number;
turn: RecordIdString;
urbanPopulation?: number;
user?: RecordIdString;
};
export type TurnsRecord = {
value?: number
}
value?: number;
};
export enum UsersRoleOptions {
"user" = "user",
"moderator" = "moderator",
"admin" = "admin",
'user' = 'user',
'moderator' = 'moderator',
'admin' = 'admin'
}
export type UsersRecord = {
avatar?: string
role: UsersRoleOptions
}
avatar?: string;
role: UsersRoleOptions;
};
// Response types include system fields and match responses from the PocketBase API
export type BurgsResponse<Temblem = unknown, Texpand = unknown> = Required<BurgsRecord<Temblem>> & BaseSystemFields<Texpand>
export type CulturesResponse<Texpand = unknown> = Required<CulturesRecord> & BaseSystemFields<Texpand>
export type MapsResponse<Texpand = unknown> = Required<MapsRecord> & BaseSystemFields<Texpand>
export type ProvincesResponse<Texpand = unknown> = Required<ProvincesRecord> & BaseSystemFields<Texpand>
export type ReligionsResponse<Texpand = unknown> = Required<ReligionsRecord> & BaseSystemFields<Texpand>
export type ReportInputsResponse<Texpand = unknown> = Required<ReportInputsRecord> & BaseSystemFields<Texpand>
export type ReportOutputsResponse<Texpand = unknown> = Required<ReportOutputsRecord> & BaseSystemFields<Texpand>
export type ReportsResponse<Texpand = unknown> = Required<ReportsRecord> & BaseSystemFields<Texpand>
export type StatesResponse<TbiomesCells = unknown, TculturesCells = unknown, TreligionsCells = unknown, Texpand = unknown> = Required<StatesRecord<TbiomesCells, TculturesCells, TreligionsCells>> & BaseSystemFields<Texpand>
export type TurnsResponse<Texpand = unknown> = Required<TurnsRecord> & BaseSystemFields<Texpand>
export type UsersResponse<Texpand = unknown> = Required<UsersRecord> & AuthSystemFields<Texpand>
export type BurgsResponse<Temblem = unknown, Texpand = unknown> = Required<BurgsRecord<Temblem>> &
BaseSystemFields<Texpand>;
export type CulturesResponse<Texpand = unknown> = Required<CulturesRecord> &
BaseSystemFields<Texpand>;
export type MapsResponse<Texpand = unknown> = Required<MapsRecord> & BaseSystemFields<Texpand>;
export type ProvincesResponse<Texpand = unknown> = Required<ProvincesRecord> &
BaseSystemFields<Texpand>;
export type ReligionsResponse<Texpand = unknown> = Required<ReligionsRecord> &
BaseSystemFields<Texpand>;
export type ReportInputsResponse<Texpand = unknown> = Required<ReportInputsRecord> &
BaseSystemFields<Texpand>;
export type ReportOutputsResponse<Texpand = unknown> = Required<ReportOutputsRecord> &
BaseSystemFields<Texpand>;
export type ReportsResponse<Texpand = unknown> = Required<ReportsRecord> &
BaseSystemFields<Texpand>;
export type StatesResponse<
TbiomesCells = unknown,
TculturesCells = unknown,
TreligionsCells = unknown,
Texpand = unknown
> = Required<StatesRecord<TbiomesCells, TculturesCells, TreligionsCells>> &
BaseSystemFields<Texpand>;
export type TurnsResponse<Texpand = unknown> = Required<TurnsRecord> & BaseSystemFields<Texpand>;
export type UsersResponse<Texpand = unknown> = Required<UsersRecord> & AuthSystemFields<Texpand>;
// Types containing all Records and Responses, useful for creating typing helper functions
export type CollectionRecords = {
burgs: BurgsRecord
cultures: CulturesRecord
maps: MapsRecord
provinces: ProvincesRecord
religions: ReligionsRecord
reportInputs: ReportInputsRecord
reportOutputs: ReportOutputsRecord
reports: ReportsRecord
states: StatesRecord
turns: TurnsRecord
users: UsersRecord
}
burgs: BurgsRecord;
cultures: CulturesRecord;
maps: MapsRecord;
provinces: ProvincesRecord;
religions: ReligionsRecord;
reportInputs: ReportInputsRecord;
reportOutputs: ReportOutputsRecord;
reports: ReportsRecord;
states: StatesRecord;
turns: TurnsRecord;
users: UsersRecord;
};
export type CollectionResponses = {
burgs: BurgsResponse
cultures: CulturesResponse
maps: MapsResponse
provinces: ProvincesResponse
religions: ReligionsResponse
reportInputs: ReportInputsResponse
reportOutputs: ReportOutputsResponse
reports: ReportsResponse
states: StatesResponse
turns: TurnsResponse
users: UsersResponse
}
burgs: BurgsResponse;
cultures: CulturesResponse;
maps: MapsResponse;
provinces: ProvincesResponse;
religions: ReligionsResponse;
reportInputs: ReportInputsResponse;
reportOutputs: ReportOutputsResponse;
reports: ReportsResponse;
states: StatesResponse;
turns: TurnsResponse;
users: UsersResponse;
};
// Type for usage with type asserted PocketBase instance
// https://github.com/pocketbase/js-sdk#specify-typescript-definitions
export type TypedPocketBase = PocketBase & {
collection(idOrName: 'burgs'): RecordService<BurgsResponse>
collection(idOrName: 'cultures'): RecordService<CulturesResponse>
collection(idOrName: 'maps'): RecordService<MapsResponse>
collection(idOrName: 'provinces'): RecordService<ProvincesResponse>
collection(idOrName: 'religions'): RecordService<ReligionsResponse>
collection(idOrName: 'reportInputs'): RecordService<ReportInputsResponse>
collection(idOrName: 'reportOutputs'): RecordService<ReportOutputsResponse>
collection(idOrName: 'reports'): RecordService<ReportsResponse>
collection(idOrName: 'states'): RecordService<StatesResponse>
collection(idOrName: 'turns'): RecordService<TurnsResponse>
collection(idOrName: 'users'): RecordService<UsersResponse>
}
collection(idOrName: 'burgs'): RecordService<BurgsResponse>;
collection(idOrName: 'cultures'): RecordService<CulturesResponse>;
collection(idOrName: 'maps'): RecordService<MapsResponse>;
collection(idOrName: 'provinces'): RecordService<ProvincesResponse>;
collection(idOrName: 'religions'): RecordService<ReligionsResponse>;
collection(idOrName: 'reportInputs'): RecordService<ReportInputsResponse>;
collection(idOrName: 'reportOutputs'): RecordService<ReportOutputsResponse>;
collection(idOrName: 'reports'): RecordService<ReportsResponse>;
collection(idOrName: 'states'): RecordService<StatesResponse>;
collection(idOrName: 'turns'): RecordService<TurnsResponse>;
collection(idOrName: 'users'): RecordService<UsersResponse>;
};