iceshrimp-legacy/packages/client/src/widgets/clock.vue
ThatOneCalculator bdc35a343e
refactor: 🚨 linting fix
2023-07-16 15:32:32 -07:00

300 lines
5 KiB
Vue

<template>
<MkContainer
:naked="widgetProps.transparent"
:show-header="false"
class="mkw-clock"
>
<div class="vubelbmv" :class="widgetProps.size">
<div
v-if="
widgetProps.label === 'tz' ||
widgetProps.label === 'timeAndTz'
"
class="_monospace label a abbrev"
>
{{ tzAbbrev }}
</div>
<MkAnalogClock
class="clock"
:thickness="widgetProps.thickness"
:offset="tzOffset"
:graduations="widgetProps.graduations"
:fade-graduations="widgetProps.fadeGraduations"
:twentyfour="widgetProps.twentyFour"
:s-animation="widgetProps.sAnimation"
/>
<MkDigitalClock
v-if="
widgetProps.label === 'time' ||
widgetProps.label === 'timeAndTz'
"
class="_monospace label c time"
:show-s="false"
:offset="tzOffset"
/>
<div
v-if="
widgetProps.label === 'tz' ||
widgetProps.label === 'timeAndTz'
"
class="_monospace label d offset"
>
{{ tzOffsetLabel }}
</div>
</div>
</MkContainer>
</template>
<script lang="ts" setup>
import {} from "vue";
import type { Widget, WidgetComponentExpose } from "./widget";
import {
WidgetComponentEmits,
WidgetComponentProps,
useWidgetPropsManager,
} from "./widget";
import type { GetFormResultType } from "@/scripts/form";
import MkContainer from "@/components/MkContainer.vue";
import MkAnalogClock from "@/components/MkAnalogClock.vue";
import MkDigitalClock from "@/components/MkDigitalClock.vue";
import { timezones } from "@/scripts/timezones";
import { i18n } from "@/i18n";
const name = "clock";
const widgetPropsDef = {
transparent: {
type: "boolean" as const,
default: false,
},
size: {
type: "radio" as const,
default: "medium",
options: [
{
value: "small",
label: i18n.ts.small,
},
{
value: "medium",
label: i18n.ts.medium,
},
{
value: "large",
label: i18n.ts.large,
},
],
},
thickness: {
type: "radio" as const,
default: 0.2,
options: [
{
value: 0.1,
label: "thin",
},
{
value: 0.2,
label: "medium",
},
{
value: 0.3,
label: "thick",
},
],
},
graduations: {
type: "radio" as const,
default: "numbers",
options: [
{
value: "none",
label: "None",
},
{
value: "dots",
label: "Dots",
},
{
value: "numbers",
label: "Numbers",
},
],
},
fadeGraduations: {
type: "boolean" as const,
default: true,
},
sAnimation: {
type: "radio" as const,
default: "elastic",
options: [
{
value: "none",
label: "None",
},
{
value: "elastic",
label: "Elastic",
},
{
value: "easeOut",
label: "Ease out",
},
],
},
twentyFour: {
type: "boolean" as const,
default: false,
},
label: {
type: "radio" as const,
default: "none",
options: [
{
value: "none",
label: "None",
},
{
value: "time",
label: "Time",
},
{
value: "tz",
label: "TZ",
},
{
value: "timeAndTz",
label: "Time + TZ",
},
],
},
timezone: {
type: "enum" as const,
default: null,
enum: [
...timezones.map((tz) => ({
label: tz.name,
value: tz.name.toLowerCase(),
})),
{
label: "(auto)",
value: null,
},
],
},
};
type WidgetProps = GetFormResultType<typeof widgetPropsDef>;
// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない
// const props = defineProps<WidgetComponentProps<WidgetProps>>();
// const emit = defineEmits<WidgetComponentEmits<WidgetProps>>();
const props = defineProps<{ widget?: Widget<WidgetProps> }>();
const emit = defineEmits<{ (ev: "updateProps", props: WidgetProps) }>();
const { widgetProps, configure } = useWidgetPropsManager(
name,
widgetPropsDef,
props,
emit,
);
const tzAbbrev = $computed(
() =>
(widgetProps.timezone === null
? timezones.find(
(tz) =>
tz.name.toLowerCase() ===
Intl.DateTimeFormat()
.resolvedOptions()
.timeZone.toLowerCase(),
)?.abbrev
: timezones.find(
(tz) => tz.name.toLowerCase() === widgetProps.timezone,
)?.abbrev) ?? "?",
);
const tzOffset = $computed(() =>
widgetProps.timezone === null
? 0 - new Date().getTimezoneOffset()
: timezones.find((tz) => tz.name.toLowerCase() === widgetProps.timezone)
?.offset ?? 0,
);
const tzOffsetLabel = $computed(
() =>
(tzOffset >= 0 ? "+" : "-") +
Math.floor(tzOffset / 60)
.toString()
.padStart(2, "0") +
":" +
(tzOffset % 60).toString().padStart(2, "0"),
);
defineExpose<WidgetComponentExpose>({
name,
configure,
id: props.widget ? props.widget.id : null,
});
</script>
<style lang="scss" scoped>
.vubelbmv {
position: relative;
> .label {
position: absolute;
opacity: 0.7;
&.a {
top: 14px;
left: 14px;
}
&.b {
top: 14px;
right: 14px;
}
&.c {
bottom: 14px;
left: 14px;
}
&.d {
bottom: 14px;
right: 14px;
}
}
> .clock {
margin: auto;
}
&.small {
padding: 12px;
> .clock {
height: 100px;
}
}
&.medium {
padding: 14px;
> .clock {
height: 150px;
}
}
&.large {
padding: 16px;
> .clock {
height: 200px;
}
}
}
</style>