You've already forked AstralRinth
forked from didirus/AstralRinth
Add TailwindCSS (#1252)
* Setup TailwindCSS * Fully setup configuration * Refactor some tailwind variables
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import dayjs from 'dayjs'
|
||||
import { formatNumber, formatMoney } from '@modrinth/utils'
|
||||
import VueApexCharts from 'vue3-apexcharts'
|
||||
import dayjs from "dayjs";
|
||||
import { formatNumber, formatMoney } from "@modrinth/utils";
|
||||
import VueApexCharts from "vue3-apexcharts";
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
@@ -18,7 +18,7 @@ const props = defineProps({
|
||||
},
|
||||
formatLabels: {
|
||||
type: Function,
|
||||
default: (label) => dayjs(label).format('MMM D'),
|
||||
default: (label) => dayjs(label).format("MMM D"),
|
||||
},
|
||||
colors: {
|
||||
type: Array,
|
||||
@@ -26,11 +26,11 @@ const props = defineProps({
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: "",
|
||||
},
|
||||
suffix: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: "",
|
||||
},
|
||||
hideToolbar: {
|
||||
type: Boolean,
|
||||
@@ -46,7 +46,7 @@ const props = defineProps({
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'bar',
|
||||
default: "bar",
|
||||
},
|
||||
hideTotal: {
|
||||
type: Boolean,
|
||||
@@ -58,11 +58,11 @@ const props = defineProps({
|
||||
},
|
||||
legendPosition: {
|
||||
type: String,
|
||||
default: 'right',
|
||||
default: "right",
|
||||
},
|
||||
xAxisType: {
|
||||
type: String,
|
||||
default: 'datetime',
|
||||
default: "datetime",
|
||||
},
|
||||
percentStacked: {
|
||||
type: Boolean,
|
||||
@@ -76,14 +76,14 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
function formatTooltipValue(value, props) {
|
||||
return props.isMoney ? formatMoney(value, false) : formatNumber(value, false)
|
||||
return props.isMoney ? formatMoney(value, false) : formatNumber(value, false);
|
||||
}
|
||||
|
||||
function generateListEntry(value, index, _, w, props) {
|
||||
const color = w.globals.colors?.[index]
|
||||
const color = w.globals.colors?.[index];
|
||||
|
||||
return `<div class="list-entry">
|
||||
<span class="circle" style="background-color: ${color}"></span>
|
||||
@@ -93,35 +93,35 @@ function generateListEntry(value, index, _, w, props) {
|
||||
<div class="value">
|
||||
${props.prefix}${formatTooltipValue(value, props)}${props.suffix}
|
||||
</div>
|
||||
</div>`
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function generateTooltip({ series, seriesIndex, dataPointIndex, w }, props) {
|
||||
const label = w.globals.lastXAxis.categories?.[dataPointIndex]
|
||||
const label = w.globals.lastXAxis.categories?.[dataPointIndex];
|
||||
|
||||
const formattedLabel = props.formatLabels(label)
|
||||
const formattedLabel = props.formatLabels(label);
|
||||
|
||||
let tooltip = `<div class="bar-tooltip">
|
||||
<div class="seperated-entry title">
|
||||
<div class="label">${formattedLabel}</div>`
|
||||
<div class="label">${formattedLabel}</div>`;
|
||||
|
||||
// Logic for total and percent stacked
|
||||
if (!props.hideTotal) {
|
||||
if (props.percentStacked) {
|
||||
const total = series.reduce((a, b) => a + (b?.[dataPointIndex] || 0), 0)
|
||||
const percentValue = (100 * series[seriesIndex][dataPointIndex]) / total
|
||||
const total = series.reduce((a, b) => a + (b?.[dataPointIndex] || 0), 0);
|
||||
const percentValue = (100 * series[seriesIndex][dataPointIndex]) / total;
|
||||
tooltip += `<div class="value">${props.prefix}${formatNumber(percentValue)}%${
|
||||
props.suffix
|
||||
}</div>`
|
||||
}</div>`;
|
||||
} else {
|
||||
const totalValue = series.reduce((a, b) => a + (b?.[dataPointIndex] || 0), 0)
|
||||
const totalValue = series.reduce((a, b) => a + (b?.[dataPointIndex] || 0), 0);
|
||||
tooltip += `<div class="value">${props.prefix}${formatTooltipValue(totalValue, props)}${
|
||||
props.suffix
|
||||
}</div>`
|
||||
}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
tooltip += '</div><hr class="card-divider" />'
|
||||
tooltip += '</div><hr class="card-divider" />';
|
||||
|
||||
// Logic for generating list entries
|
||||
if (props.percentStacked) {
|
||||
@@ -130,10 +130,10 @@ function generateTooltip({ series, seriesIndex, dataPointIndex, w }, props) {
|
||||
seriesIndex,
|
||||
seriesIndex,
|
||||
w,
|
||||
props
|
||||
)
|
||||
props,
|
||||
);
|
||||
} else {
|
||||
const returnTopN = 5
|
||||
const returnTopN = 5;
|
||||
|
||||
const listEntries = series
|
||||
.map((value, index) => [
|
||||
@@ -144,13 +144,13 @@ function generateTooltip({ series, seriesIndex, dataPointIndex, w }, props) {
|
||||
.sort((a, b) => b[0] - a[0])
|
||||
.slice(0, returnTopN) // Return only the top X entries
|
||||
.map((value) => value[1])
|
||||
.join('')
|
||||
.join("");
|
||||
|
||||
tooltip += listEntries
|
||||
tooltip += listEntries;
|
||||
}
|
||||
|
||||
tooltip += '</div>'
|
||||
return tooltip
|
||||
tooltip += "</div>";
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
const chartOptions = computed(() => {
|
||||
@@ -158,19 +158,19 @@ const chartOptions = computed(() => {
|
||||
chart: {
|
||||
id: props.name,
|
||||
fontFamily:
|
||||
'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif',
|
||||
foreColor: 'var(--color-base)',
|
||||
"Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif",
|
||||
foreColor: "var(--color-base)",
|
||||
selection: {
|
||||
enabled: true,
|
||||
fill: {
|
||||
color: 'var(--color-brand)',
|
||||
color: "var(--color-brand)",
|
||||
},
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
stacked: props.stacked,
|
||||
stackType: props.percentStacked ? '100%' : 'normal',
|
||||
stackType: props.percentStacked ? "100%" : "normal",
|
||||
zoom: {
|
||||
autoScaleYaxis: true,
|
||||
},
|
||||
@@ -183,7 +183,7 @@ const chartOptions = computed(() => {
|
||||
categories: props.labels,
|
||||
labels: {
|
||||
style: {
|
||||
borderRadius: 'var(--radius-sm)',
|
||||
borderRadius: "var(--radius-sm)",
|
||||
},
|
||||
},
|
||||
axisTicks: {
|
||||
@@ -207,8 +207,8 @@ const chartOptions = computed(() => {
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
borderColor: 'var(--color-button-bg)',
|
||||
tickColor: 'var(--color-button-bg)',
|
||||
borderColor: "var(--color-button-bg)",
|
||||
tickColor: "var(--color-button-bg)",
|
||||
},
|
||||
legend: {
|
||||
show: !props.hideLegend,
|
||||
@@ -216,16 +216,16 @@ const chartOptions = computed(() => {
|
||||
showForZeroSeries: false,
|
||||
showForSingleSeries: false,
|
||||
showForNullSeries: false,
|
||||
fontSize: 'var(--font-size-nm)',
|
||||
fontSize: "var(--font-size-nm)",
|
||||
fontFamily:
|
||||
'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif',
|
||||
"Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif",
|
||||
onItemClick: {
|
||||
toggleDataSeries: true,
|
||||
},
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
strokeColor: 'var(--color-contrast)',
|
||||
strokeColor: "var(--color-contrast)",
|
||||
strokeWidth: 3,
|
||||
strokeOpacity: 1,
|
||||
fillOpacity: 1,
|
||||
@@ -236,29 +236,29 @@ const chartOptions = computed(() => {
|
||||
plotOptions: {
|
||||
bar: {
|
||||
horizontal: props.horizontalBar,
|
||||
columnWidth: '80%',
|
||||
endingShape: 'rounded',
|
||||
columnWidth: "80%",
|
||||
endingShape: "rounded",
|
||||
borderRadius: 5,
|
||||
borderRadiusApplication: 'end',
|
||||
borderRadiusWhenStacked: 'last',
|
||||
borderRadiusApplication: "end",
|
||||
borderRadiusWhenStacked: "last",
|
||||
},
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth',
|
||||
curve: "smooth",
|
||||
width: 2,
|
||||
},
|
||||
tooltip: {
|
||||
custom: (d) => generateTooltip(d, props),
|
||||
},
|
||||
fill:
|
||||
props.type === 'area'
|
||||
props.type === "area"
|
||||
? {
|
||||
colors: props.colors,
|
||||
type: 'gradient',
|
||||
type: "gradient",
|
||||
opacity: 1,
|
||||
gradient: {
|
||||
shade: 'light',
|
||||
type: 'vertical',
|
||||
shade: "light",
|
||||
type: "vertical",
|
||||
shadeIntensity: 0,
|
||||
gradientToColors: props.colors,
|
||||
inverseColors: true,
|
||||
@@ -269,40 +269,40 @@ const chartOptions = computed(() => {
|
||||
},
|
||||
}
|
||||
: {},
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
const chart = ref(null)
|
||||
const chart = ref(null);
|
||||
|
||||
const legendValues = ref(
|
||||
[...props.data].map((project, index) => {
|
||||
return { name: project.name, visible: true, color: props.colors[index] }
|
||||
})
|
||||
)
|
||||
return { name: project.name, visible: true, color: props.colors[index] };
|
||||
}),
|
||||
);
|
||||
|
||||
const flipLegend = (legend, newVal) => {
|
||||
legend.visible = newVal
|
||||
chart.value.toggleSeries(legend.name)
|
||||
}
|
||||
legend.visible = newVal;
|
||||
chart.value.toggleSeries(legend.name);
|
||||
};
|
||||
|
||||
const resetChart = () => {
|
||||
if (!chart.value) return
|
||||
chart.value.updateSeries([...props.data])
|
||||
if (!chart.value) return;
|
||||
chart.value.updateSeries([...props.data]);
|
||||
chart.value.updateOptions({
|
||||
xaxis: {
|
||||
categories: props.labels,
|
||||
},
|
||||
})
|
||||
chart.value.resetSeries()
|
||||
});
|
||||
chart.value.resetSeries();
|
||||
legendValues.value.forEach((legend) => {
|
||||
legend.visible = true
|
||||
})
|
||||
}
|
||||
legend.visible = true;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
resetChart,
|
||||
flipLegend,
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -86,7 +86,9 @@
|
||||
v-model="selectedRange"
|
||||
:options="selectableRanges"
|
||||
name="Time range"
|
||||
:display-name="(o: typeof selectableRanges[number] | undefined) => o?.label || 'Custom'"
|
||||
:display-name="
|
||||
(o: (typeof selectableRanges)[number] | undefined) => o?.label || 'Custom'
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -218,7 +220,7 @@
|
||||
:style="{
|
||||
width: formatPercent(
|
||||
count,
|
||||
analytics.formattedData.value.downloadsByCountry.sum
|
||||
analytics.formattedData.value.downloadsByCountry.sum,
|
||||
),
|
||||
backgroundColor: 'var(--color-brand)',
|
||||
}"
|
||||
@@ -266,7 +268,7 @@
|
||||
v-tooltip="
|
||||
`${
|
||||
Math.round(
|
||||
(count / analytics.formattedData.value.viewsByCountry.sum) * 10000
|
||||
(count / analytics.formattedData.value.viewsByCountry.sum) * 10000,
|
||||
) / 100
|
||||
}%`
|
||||
"
|
||||
@@ -289,56 +291,56 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Button, Card, DropdownSelect } from '@modrinth/ui'
|
||||
import { formatMoney, formatNumber, formatCategoryHeader } from '@modrinth/utils'
|
||||
import { UpdatedIcon, DownloadIcon } from '@modrinth/assets'
|
||||
import dayjs from 'dayjs'
|
||||
import { computed } from 'vue'
|
||||
import { Button, Card, DropdownSelect } from "@modrinth/ui";
|
||||
import { formatMoney, formatNumber, formatCategoryHeader } from "@modrinth/utils";
|
||||
import { UpdatedIcon, DownloadIcon } from "@modrinth/assets";
|
||||
import dayjs from "dayjs";
|
||||
import { computed } from "vue";
|
||||
|
||||
import { analyticsSetToCSVString, intToRgba } from '~/utils/analytics.js'
|
||||
import { analyticsSetToCSVString, intToRgba } from "~/utils/analytics.js";
|
||||
|
||||
import { UiChartsCompactChart as CompactChart, UiChartsChart as Chart } from '#components'
|
||||
import { UiChartsCompactChart as CompactChart, UiChartsChart as Chart } from "#components";
|
||||
|
||||
import PaletteIcon from '~/assets/icons/palette.svg?component'
|
||||
import PaletteIcon from "~/assets/icons/palette.svg?component";
|
||||
|
||||
const router = useNativeRouter()
|
||||
const theme = useTheme()
|
||||
const router = useNativeRouter();
|
||||
const theme = useTheme();
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
projects?: any[]
|
||||
projects?: any[];
|
||||
/**
|
||||
* @deprecated Use `ranges` instead
|
||||
*/
|
||||
resoloutions?: Record<string, number>
|
||||
ranges?: Record<number, [string, number] | string>
|
||||
personal?: boolean
|
||||
resoloutions?: Record<string, number>;
|
||||
ranges?: Record<number, [string, number] | string>;
|
||||
personal?: boolean;
|
||||
}>(),
|
||||
{
|
||||
projects: undefined,
|
||||
resoloutions: () => defaultResoloutions,
|
||||
ranges: () => defaultRanges,
|
||||
personal: false,
|
||||
}
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
const projects = ref(props.projects || [])
|
||||
const projects = ref(props.projects || []);
|
||||
|
||||
const selectableRanges = Object.entries(props.ranges).map(([duration, extra]) => ({
|
||||
label: typeof extra === 'string' ? extra : extra[0],
|
||||
label: typeof extra === "string" ? extra : extra[0],
|
||||
value: Number(duration),
|
||||
res: typeof extra === 'string' ? Number(duration) : extra[1],
|
||||
}))
|
||||
res: typeof extra === "string" ? Number(duration) : extra[1],
|
||||
}));
|
||||
|
||||
// const selectedChart = ref('downloads')
|
||||
const selectedChart = computed({
|
||||
get: () => {
|
||||
const id = (router.currentRoute.value.query?.chart as string | undefined) || 'downloads'
|
||||
const id = (router.currentRoute.value.query?.chart as string | undefined) || "downloads";
|
||||
// if the id is anything but the 3 charts we have or undefined, throw an error
|
||||
if (!['downloads', 'views', 'revenue'].includes(id)) {
|
||||
throw new Error(`Unknown chart ${id}`)
|
||||
if (!["downloads", "views", "revenue"].includes(id)) {
|
||||
throw new Error(`Unknown chart ${id}`);
|
||||
}
|
||||
return id
|
||||
return id;
|
||||
},
|
||||
set: (chart) => {
|
||||
router.push({
|
||||
@@ -346,153 +348,153 @@ const selectedChart = computed({
|
||||
...router.currentRoute.value.query,
|
||||
chart,
|
||||
},
|
||||
})
|
||||
});
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
// Chart refs
|
||||
const downloadsChart = ref()
|
||||
const viewsChart = ref()
|
||||
const revenueChart = ref()
|
||||
const tinyDownloadChart = ref()
|
||||
const tinyViewChart = ref()
|
||||
const tinyRevenueChart = ref()
|
||||
const downloadsChart = ref();
|
||||
const viewsChart = ref();
|
||||
const revenueChart = ref();
|
||||
const tinyDownloadChart = ref();
|
||||
const tinyViewChart = ref();
|
||||
const tinyRevenueChart = ref();
|
||||
|
||||
const selectedDisplayProjects = ref(props.projects || [])
|
||||
const selectedDisplayProjects = ref(props.projects || []);
|
||||
|
||||
const removeProjectFromDisplay = (id: string) => {
|
||||
selectedDisplayProjects.value = selectedDisplayProjects.value.filter((p) => p.id !== id)
|
||||
}
|
||||
selectedDisplayProjects.value = selectedDisplayProjects.value.filter((p) => p.id !== id);
|
||||
};
|
||||
|
||||
const addProjectToDisplay = (id: string) => {
|
||||
selectedDisplayProjects.value = [
|
||||
...selectedDisplayProjects.value,
|
||||
props.projects?.find((p) => p.id === id),
|
||||
].filter(Boolean)
|
||||
}
|
||||
].filter(Boolean);
|
||||
};
|
||||
|
||||
const projectIsOnDisplay = (id: string) => {
|
||||
return selectedDisplayProjects.value?.some((p) => p.id === id) ?? false
|
||||
}
|
||||
return selectedDisplayProjects.value?.some((p) => p.id === id) ?? false;
|
||||
};
|
||||
|
||||
const resetCharts = () => {
|
||||
downloadsChart.value?.resetChart()
|
||||
viewsChart.value?.resetChart()
|
||||
revenueChart.value?.resetChart()
|
||||
downloadsChart.value?.resetChart();
|
||||
viewsChart.value?.resetChart();
|
||||
revenueChart.value?.resetChart();
|
||||
|
||||
tinyDownloadChart.value?.resetChart()
|
||||
tinyViewChart.value?.resetChart()
|
||||
tinyRevenueChart.value?.resetChart()
|
||||
}
|
||||
tinyDownloadChart.value?.resetChart();
|
||||
tinyViewChart.value?.resetChart();
|
||||
tinyRevenueChart.value?.resetChart();
|
||||
};
|
||||
|
||||
const isUsingProjectColors = computed({
|
||||
get: () => {
|
||||
return (
|
||||
router.currentRoute.value.query?.colors === 'true' ||
|
||||
router.currentRoute.value.query?.colors === "true" ||
|
||||
router.currentRoute.value.query?.colors === undefined
|
||||
)
|
||||
);
|
||||
},
|
||||
set: (newValue) => {
|
||||
router.push({
|
||||
query: {
|
||||
...router.currentRoute.value.query,
|
||||
colors: newValue ? 'true' : 'false',
|
||||
colors: newValue ? "true" : "false",
|
||||
},
|
||||
})
|
||||
});
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const analytics = useFetchAllAnalytics(
|
||||
resetCharts,
|
||||
projects,
|
||||
selectedDisplayProjects,
|
||||
props.personal
|
||||
)
|
||||
props.personal,
|
||||
);
|
||||
|
||||
const { startDate, endDate, timeRange, timeResolution } = analytics
|
||||
const { startDate, endDate, timeRange, timeResolution } = analytics;
|
||||
|
||||
const selectedRange = computed({
|
||||
get: () => {
|
||||
return (
|
||||
selectableRanges.find((option) => option.value === timeRange.value) || {
|
||||
label: 'Custom',
|
||||
label: "Custom",
|
||||
value: timeRange.value,
|
||||
}
|
||||
)
|
||||
);
|
||||
},
|
||||
set: (newRange: { label: string; value: number; res?: number }) => {
|
||||
timeRange.value = newRange.value
|
||||
startDate.value = Date.now() - timeRange.value * 60 * 1000
|
||||
endDate.value = Date.now()
|
||||
timeRange.value = newRange.value;
|
||||
startDate.value = Date.now() - timeRange.value * 60 * 1000;
|
||||
endDate.value = Date.now();
|
||||
|
||||
if (newRange?.res) {
|
||||
timeResolution.value = newRange.res
|
||||
timeResolution.value = newRange.res;
|
||||
}
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const selectedDataSet = computed(() => {
|
||||
switch (selectedChart.value) {
|
||||
case 'downloads':
|
||||
return analytics.totalData.value.downloads
|
||||
case 'views':
|
||||
return analytics.totalData.value.views
|
||||
case 'revenue':
|
||||
return analytics.totalData.value.revenue
|
||||
case "downloads":
|
||||
return analytics.totalData.value.downloads;
|
||||
case "views":
|
||||
return analytics.totalData.value.views;
|
||||
case "revenue":
|
||||
return analytics.totalData.value.revenue;
|
||||
default:
|
||||
throw new Error(`Unknown chart ${selectedChart.value}`)
|
||||
throw new Error(`Unknown chart ${selectedChart.value}`);
|
||||
}
|
||||
})
|
||||
});
|
||||
const selectedDataSetProjects = computed(() => {
|
||||
return selectedDataSet.value.projectIds
|
||||
.map((id) => props.projects?.find((p) => p?.id === id))
|
||||
.filter(Boolean)
|
||||
})
|
||||
.filter(Boolean);
|
||||
});
|
||||
|
||||
const downloadSelectedSetAsCSV = () => {
|
||||
const selectedChartName = selectedChart.value
|
||||
const selectedChartName = selectedChart.value;
|
||||
|
||||
const csv = analyticsSetToCSVString(selectedDataSet.value)
|
||||
const csv = analyticsSetToCSVString(selectedDataSet.value);
|
||||
|
||||
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
|
||||
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
||||
|
||||
const link = document.createElement('a')
|
||||
const url = URL.createObjectURL(blob)
|
||||
link.setAttribute('href', url)
|
||||
link.setAttribute('download', `${selectedChartName}-data.csv`)
|
||||
link.style.visibility = 'hidden'
|
||||
document.body.appendChild(link)
|
||||
const link = document.createElement("a");
|
||||
const url = URL.createObjectURL(blob);
|
||||
link.setAttribute("href", url);
|
||||
link.setAttribute("download", `${selectedChartName}-data.csv`);
|
||||
link.style.visibility = "hidden";
|
||||
document.body.appendChild(link);
|
||||
|
||||
link.click()
|
||||
}
|
||||
link.click();
|
||||
};
|
||||
|
||||
const onDownloadSetAsCSV = useClientTry(async () => await downloadSelectedSetAsCSV())
|
||||
const onDownloadSetAsCSV = useClientTry(async () => await downloadSelectedSetAsCSV());
|
||||
const onToggleColors = () => {
|
||||
isUsingProjectColors.value = !isUsingProjectColors.value
|
||||
}
|
||||
isUsingProjectColors.value = !isUsingProjectColors.value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
const defaultResoloutions: Record<string, number> = {
|
||||
'5 minutes': 5,
|
||||
'30 minutes': 30,
|
||||
'An hour': 60,
|
||||
'12 hours': 720,
|
||||
'A day': 1440,
|
||||
'A week': 10080,
|
||||
}
|
||||
"5 minutes": 5,
|
||||
"30 minutes": 30,
|
||||
"An hour": 60,
|
||||
"12 hours": 720,
|
||||
"A day": 1440,
|
||||
"A week": 10080,
|
||||
};
|
||||
|
||||
const defaultRanges: Record<number, [string, number] | string> = {
|
||||
30: ['Last 30 minutes', 1],
|
||||
60: ['Last hour', 5],
|
||||
720: ['Last 12 hours', 15],
|
||||
1440: ['Last day', 60],
|
||||
10080: ['Last week', 720],
|
||||
43200: ['Last month', 1440],
|
||||
129600: ['Last quarter', 10080],
|
||||
525600: ['Last year', 20160],
|
||||
1051200: ['Last two years', 40320],
|
||||
}
|
||||
30: ["Last 30 minutes", 1],
|
||||
60: ["Last hour", 5],
|
||||
720: ["Last 12 hours", 15],
|
||||
1440: ["Last day", 60],
|
||||
10080: ["Last week", 720],
|
||||
43200: ["Last month", 1440],
|
||||
129600: ["Last quarter", 10080],
|
||||
525600: ["Last year", 20160],
|
||||
1051200: ["Last two years", 40320],
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -590,7 +592,9 @@ const defaultRanges: Record<number, [string, number] | string> = {
|
||||
.chart-button-base__selected {
|
||||
color: var(--color-contrast);
|
||||
background-color: var(--color-brand-highlight);
|
||||
box-shadow: inset 0 0 0 transparent, 0 0 0 2px var(--color-brand);
|
||||
box-shadow:
|
||||
inset 0 0 0 transparent,
|
||||
0 0 0 2px var(--color-brand);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-brand-highlight);
|
||||
@@ -662,7 +666,7 @@ const defaultRanges: Record<number, [string, number] | string> = {
|
||||
|
||||
.country-value {
|
||||
display: grid;
|
||||
grid-template-areas: 'flag text bar';
|
||||
grid-template-areas: "flag text bar";
|
||||
grid-template-columns: auto 1fr 10rem;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { Card } from '@modrinth/ui'
|
||||
import VueApexCharts from 'vue3-apexcharts'
|
||||
import { Card } from "@modrinth/ui";
|
||||
import VueApexCharts from "vue3-apexcharts";
|
||||
|
||||
// let VueApexCharts
|
||||
// if (process.client) {
|
||||
@@ -10,11 +10,11 @@ import VueApexCharts from 'vue3-apexcharts'
|
||||
const props = defineProps({
|
||||
value: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: "",
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: "",
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
@@ -26,11 +26,11 @@ const props = defineProps({
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: "",
|
||||
},
|
||||
suffix: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: "",
|
||||
},
|
||||
isMoney: {
|
||||
type: Boolean,
|
||||
@@ -38,17 +38,17 @@ const props = defineProps({
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: 'var(--color-brand)',
|
||||
default: "var(--color-brand)",
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
// no grid lines, no toolbar, no legend, no data labels
|
||||
const chartOptions = {
|
||||
chart: {
|
||||
id: props.title,
|
||||
fontFamily:
|
||||
'Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif',
|
||||
foreColor: 'var(--color-base)',
|
||||
"Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif",
|
||||
foreColor: "var(--color-base)",
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
@@ -61,16 +61,16 @@ const chartOptions = {
|
||||
parentHeightOffset: 0,
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth',
|
||||
curve: "smooth",
|
||||
width: 2,
|
||||
},
|
||||
fill: {
|
||||
colors: [props.color],
|
||||
type: 'gradient',
|
||||
type: "gradient",
|
||||
opacity: 1,
|
||||
gradient: {
|
||||
shade: 'light',
|
||||
type: 'vertical',
|
||||
shade: "light",
|
||||
type: "vertical",
|
||||
shadeIntensity: 0,
|
||||
gradientToColors: [props.color],
|
||||
inverseColors: true,
|
||||
@@ -91,7 +91,7 @@ const chartOptions = {
|
||||
enabled: false,
|
||||
},
|
||||
xaxis: {
|
||||
type: 'datetime',
|
||||
type: "datetime",
|
||||
categories: props.labels,
|
||||
labels: {
|
||||
show: false,
|
||||
@@ -120,23 +120,23 @@ const chartOptions = {
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const chart = ref(null)
|
||||
const chart = ref(null);
|
||||
|
||||
const resetChart = () => {
|
||||
chart.value?.updateSeries([...props.data])
|
||||
chart.value?.updateSeries([...props.data]);
|
||||
chart.value?.updateOptions({
|
||||
xaxis: {
|
||||
categories: props.labels,
|
||||
},
|
||||
})
|
||||
chart.value?.resetSeries()
|
||||
}
|
||||
});
|
||||
chart.value?.resetSeries();
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
resetChart,
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in New Issue
Block a user