mirror of
https://github.com/go-gitea/gitea.git
synced 2026-11-09 17:37:20 -06:00
Derive theme colors from a few base colors with `color-mix(in srgb, …)` and make the colorful palette coherent, so custom themes that import a Gitea theme can override a base color and get matching shades. - Every `-light`, `-dark-1` and `-dark-2` shade follows one rule for all hues, fixing dark orange shades copied from the light theme, black shades that barely moved and neon tints - Base colors move at most 4 OKLab units toward a common lightness, the median in dark and red in light, yellow stays unchanged - Text, secondary, console, message, surface and alpha colors derive from their own base, alpha variants now match their names - Added and removed diff colors share one lightness per level in all themes, including colorblind ones - Chart.js and the external render iframe resolve `color-mix()` values to hex through `getComputedStyle` - Remove unused `secondary-dark-12`, `-13`, `shadow-opaque` and `workflow-edge-hover` Fixes: https://github.com/go-gitea/gitea/issues/30160 <img width="880" alt="Components with the largest color changes, dark and light, before and after" src="https://github.com/user-attachments/assets/a9d27636-e3bb-46fa-a3ac-3fec33fd9806" /> <img width="880" alt="All theme colors per family, before and after, unchanged ones dimmed" src="https://github.com/user-attachments/assets/9977dde3-0749-4926-b110-18c0dc31d632" /> --------- Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
72 lines
2.5 KiB
Vue
72 lines
2.5 KiB
Vue
<script lang="ts" setup>
|
|
import {onMounted, onUnmounted, toRaw, useTemplateRef, watch, type ShallowRef} from 'vue';
|
|
import {_adapters, BarController, Chart, LinearScale, LineController, TimeScale, type ChartData, type ChartOptions, type TimeUnit} from 'chart.js';
|
|
import {chartJsColor} from '../utils/color.ts';
|
|
import dayjs from 'dayjs';
|
|
import advancedFormat from 'dayjs/plugin/advancedFormat.js';
|
|
import quarterOfYear from 'dayjs/plugin/quarterOfYear.js';
|
|
import type {ConfigType, ManipulateType} from 'dayjs';
|
|
|
|
dayjs.extend(advancedFormat); // the quarter format needs the `Q` token
|
|
dayjs.extend(quarterOfYear);
|
|
|
|
Chart.defaults.color = chartJsColor('text');
|
|
Chart.defaults.borderColor = chartJsColor('border');
|
|
Chart.register(BarController, LineController, LinearScale, TimeScale);
|
|
|
|
// minimal port of chartjs-adapter-dayjs-4, MIT license, Copyright (c) 2022 bolstycjw
|
|
_adapters._date.override({
|
|
formats: () => ({
|
|
datetime: 'MMM D, YYYY, h:mm:ss a',
|
|
millisecond: 'h:mm:ss.SSS a',
|
|
second: 'h:mm:ss a',
|
|
minute: 'h:mm a',
|
|
hour: 'hA',
|
|
day: 'MMM D',
|
|
week: 'MMM D, YYYY',
|
|
month: 'MMM YYYY',
|
|
quarter: '[Q]Q - YYYY',
|
|
year: 'YYYY',
|
|
}),
|
|
parse: (value: ConfigType) => {
|
|
const date = dayjs(value);
|
|
return date.isValid() ? date.valueOf() : null;
|
|
},
|
|
format: (time: number, format: string) => dayjs(time).format(format),
|
|
add: (time: number, amount: number, unit: TimeUnit) => dayjs(time).add(amount, unit as ManipulateType).valueOf(), // the quarter plugin widens this at runtime
|
|
diff: (max: number, min: number, unit: TimeUnit) => dayjs(max).diff(min, unit),
|
|
// chart.js only asks for `isoWeek` when `time.isoWeekday` is set, which we never do
|
|
startOf: (time: number, unit: TimeUnit) => dayjs(time).startOf(unit).valueOf(),
|
|
endOf: (time: number, unit: TimeUnit) => dayjs(time).endOf(unit).valueOf(),
|
|
});
|
|
|
|
const props = defineProps<{
|
|
type: 'bar' | 'line',
|
|
data: ChartData,
|
|
options: ChartOptions,
|
|
}>();
|
|
|
|
const elCanvas = useTemplateRef('elCanvas') as Readonly<ShallowRef<HTMLCanvasElement>>;
|
|
let chart: Chart | undefined;
|
|
|
|
// chart.js mutates what it gets, so it must never see a reactive proxy
|
|
onMounted(() => {
|
|
chart = new Chart(elCanvas.value, {type: props.type, data: toRaw(props.data), options: toRaw(props.options)});
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
chart?.destroy();
|
|
});
|
|
|
|
watch([() => props.data, () => props.options], ([data, options]) => {
|
|
if (!chart) return; // chart creation failed
|
|
chart.data = toRaw(data);
|
|
chart.options = toRaw(options);
|
|
chart.update();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<canvas ref="elCanvas" role="img"/>
|
|
</template>
|