Skip to content

Commit

Permalink
refactor(frontend): use composition api
Browse files Browse the repository at this point in the history
  • Loading branch information
syuilo committed May 14, 2023
1 parent 3d4a90b commit 0717afc
Show file tree
Hide file tree
Showing 8 changed files with 478 additions and 604 deletions.
123 changes: 55 additions & 68 deletions packages/frontend/src/components/MkFoldableSection.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="ssazuxis">
<div ref="el" class="ssazuxis">
<header class="_button" :style="{ background: bg }" @click="showBody = !showBody">
<div class="title"><div><slot name="header"></slot></div></div>
<div class="divider"></div>
Expand All @@ -22,80 +22,67 @@
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { onMounted, ref, shallowRef, watch } from 'vue';
import tinycolor from 'tinycolor2';
import { miLocalStorage } from '@/local-storage';
import { defaultStore } from '@/store';
const miLocalStoragePrefix = 'ui:folder:' as const;
export default defineComponent({
props: {
expanded: {
type: Boolean,
required: false,
default: true,
},
persistKey: {
type: String,
required: false,
default: null,
},
},
data() {
return {
defaultStore,
bg: null,
showBody: (this.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`) === 't') : this.expanded,
};
},
watch: {
showBody() {
if (this.persistKey) {
miLocalStorage.setItem(`${miLocalStoragePrefix}${this.persistKey}`, this.showBody ? 't' : 'f');
}
},
},
mounted() {
function getParentBg(el: Element | null): string {
if (el == null || el.tagName === 'BODY') return 'var(--bg)';
const bg = el.style.background || el.style.backgroundColor;
if (bg) {
return bg;
} else {
return getParentBg(el.parentElement);
}
const props = withDefaults(defineProps<{
expanded?: boolean;
persistKey?: string;
}>(), {
expanded: true,
});
const el = shallowRef<HTMLDivElement>();
const bg = ref<string | null>(null);
const showBody = ref((props.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${props.persistKey}`) === 't') : props.expanded);
watch(showBody, () => {
if (props.persistKey) {
miLocalStorage.setItem(`${miLocalStoragePrefix}${props.persistKey}`, showBody.value ? 't' : 'f');
}
});
function enter(el: Element) {
const elementHeight = el.getBoundingClientRect().height;
el.style.height = 0;
el.offsetHeight; // reflow
el.style.height = elementHeight + 'px';
}
function afterEnter(el: Element) {
el.style.height = null;
}
function leave(el: Element) {
const elementHeight = el.getBoundingClientRect().height;
el.style.height = elementHeight + 'px';
el.offsetHeight; // reflow
el.style.height = 0;
}
function afterLeave(el: Element) {
el.style.height = null;
}
onMounted(() => {
function getParentBg(el: HTMLElement | null): string {
if (el == null || el.tagName === 'BODY') return 'var(--bg)';
const bg = el.style.background || el.style.backgroundColor;
if (bg) {
return bg;
} else {
return getParentBg(el.parentElement);
}
const rawBg = getParentBg(this.$el);
const bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
bg.setAlpha(0.85);
this.bg = bg.toRgbString();
},
methods: {
toggleContent(show: boolean) {
this.showBody = show;
},
enter(el) {
const elementHeight = el.getBoundingClientRect().height;
el.style.height = 0;
el.offsetHeight; // reflow
el.style.height = elementHeight + 'px';
},
afterEnter(el) {
el.style.height = null;
},
leave(el) {
const elementHeight = el.getBoundingClientRect().height;
el.style.height = elementHeight + 'px';
el.offsetHeight; // reflow
el.style.height = 0;
},
afterLeave(el) {
el.style.height = null;
},
},
}
const rawBg = getParentBg(el.value);
const _bg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
_bg.setAlpha(0.85);
bg.value = _bg.toRgbString();
});
</script>

Expand Down
80 changes: 29 additions & 51 deletions packages/frontend/src/components/MkFormDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
</MkModalWindow>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { reactive, shallowRef } from 'vue';
import MkInput from './MkInput.vue';
import MkTextarea from './MkTextarea.vue';
import MkSwitch from './MkSwitch.vue';
Expand All @@ -66,58 +66,36 @@ import MkRadios from './MkRadios.vue';
import MkModalWindow from '@/components/MkModalWindow.vue';
import { i18n } from '@/i18n';
export default defineComponent({
components: {
MkModalWindow,
MkInput,
MkTextarea,
MkSwitch,
MkSelect,
MkRange,
MkButton,
MkRadios,
},
const props = defineProps<{
title: string;
form: any;
}>();
props: {
title: {
type: String,
required: true,
},
form: {
type: Object,
required: true,
},
},
const emit = defineEmits<{
(ev: 'done', v: {
canceled?: boolean;
result?: any;
}): void;
}>();
emits: ['done'],
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
const values = reactive({});
data() {
return {
values: {},
i18n,
};
},
for (const item in props.form) {
values[item] = props.form[item].default ?? null;
}
created() {
for (const item in this.form) {
this.values[item] = this.form[item].default ?? null;
}
},
function ok() {
emit('done', {
result: values,
});
dialog.value.close();
}
methods: {
ok() {
this.$emit('done', {
result: this.values,
});
this.$refs.dialog.close();
},
cancel() {
this.$emit('done', {
canceled: true,
});
this.$refs.dialog.close();
},
},
});
function cancel() {
emit('done', {
canceled: true,
});
dialog.value.close();
}
</script>
64 changes: 24 additions & 40 deletions packages/frontend/src/components/MkObjectView.value.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,54 +28,38 @@
</div>
</template>

<script lang="ts">
import { defineComponent, reactive } from 'vue';
<script lang="ts" setup>
import { reactive } from 'vue';
import number from '@/filters/number';
import XValue from '@/components/MkObjectView.value.vue';
export default defineComponent({
name: 'XValue',
const props = defineProps<{
value: any;
}>();
props: {
value: {
required: true,
},
},
const collapsed = reactive({});
setup(props) {
const collapsed = reactive({});
if (isObject(props.value)) {
for (const key in props.value) {
collapsed[key] = collapsable(props.value[key]);
}
}
function isObject(v): boolean {
return typeof v === 'object' && !Array.isArray(v) && v !== null;
}
if (isObject(props.value)) {
for (const key in props.value) {
collapsed[key] = collapsable(props.value[key]);
}
}
function isArray(v): boolean {
return Array.isArray(v);
}
function isObject(v): boolean {
return typeof v === 'object' && !Array.isArray(v) && v !== null;
}
function isEmpty(v): boolean {
return (isArray(v) && v.length === 0) || (isObject(v) && Object.keys(v).length === 0);
}
function isArray(v): boolean {
return Array.isArray(v);
}
function collapsable(v): boolean {
return (isObject(v) || isArray(v)) && !isEmpty(v);
}
function isEmpty(v): boolean {
return (isArray(v) && v.length === 0) || (isObject(v) && Object.keys(v).length === 0);
}
return {
number,
collapsed,
isObject,
isArray,
isEmpty,
collapsable,
};
},
});
function collapsable(v): boolean {
return (isObject(v) || isArray(v)) && !isEmpty(v);
}
</script>

<style lang="scss" scoped>
Expand Down
36 changes: 13 additions & 23 deletions packages/frontend/src/components/MkRadios.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,27 @@
<script lang="ts">
import { VNode, defineComponent, h } from 'vue';
import { VNode, defineComponent, h, ref, watch } from 'vue';
import MkRadio from './MkRadio.vue';
export default defineComponent({
components: {
MkRadio,
},
props: {
modelValue: {
required: false,
},
},
data() {
return {
value: this.modelValue,
};
},
watch: {
value() {
this.$emit('update:modelValue', this.value);
},
},
render() {
console.log(this.$slots, this.$slots.label && this.$slots.label());
if (!this.$slots.default) return null;
let options = this.$slots.default();
const label = this.$slots.label && this.$slots.label();
const caption = this.$slots.caption && this.$slots.caption();
setup(props, context) {
const value = ref(props.modelValue);
watch(value, () => {
context.emit('update:modelValue', value.value);
});
if (!context.slots.default) return null;
let options = context.slots.default();
const label = context.slots.label && context.slots.label();
const caption = context.slots.caption && context.slots.caption();
// なぜかFragmentになることがあるため
if (options.length === 1 && options[0].props == null) options = options[0].children as VNode[];
return h('div', {
return () => h('div', {
class: 'novjtcto',
}, [
...(label ? [h('div', {
Expand All @@ -42,8 +32,8 @@ export default defineComponent({
}, options.map(option => h(MkRadio, {
key: option.key,
value: option.props?.value,
modelValue: this.value,
'onUpdate:modelValue': value => this.value = value,
modelValue: value.value,
'onUpdate:modelValue': _v => value.value = _v,
}, () => option.children)),
),
...(caption ? [h('div', {
Expand Down
Loading

1 comment on commit 0717afc

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chromatic detects changes. Please review the changes on Chromatic.

Please sign in to comment.