enhance(client): improve launch pad usability

This commit is contained in:
syuilo 2022-02-23 23:40:31 +09:00
parent 28a24d30d2
commit c0fd7697b9
5 changed files with 103 additions and 116 deletions

View file

@ -1,6 +1,6 @@
<template>
<MkModal ref="modal" :prefer-type="'dialog'" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="szkkfdyq _popup">
<MkModal ref="modal" v-slot="{ type, maxHeight }" :prefer-type="preferedModalType" :transparent-bg="type === 'popup'" :src="src" @click="modal.close()" @closed="emit('closed')">
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
<div class="main">
<template v-for="item in items">
<button v-if="item.action" v-click-anime class="_button" @click="$event => { item.action($event); close(); }">
@ -33,97 +33,94 @@
</MkModal>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { } from 'vue';
import MkModal from '@/components/ui/modal.vue';
import { menuDef } from '@/menu';
import { instanceName } from '@/config';
import { defaultStore } from '@/store';
import { i18n } from '@/i18n';
import { deviceKind } from '@/scripts/device-kind';
export default defineComponent({
components: {
MkModal,
},
emits: ['closed'],
data() {
return {
menuDef: menuDef,
items: [],
instanceName,
};
},
computed: {
menu(): string[] {
return this.$store.state.menu;
},
},
created() {
this.items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
type: def.to ? 'link' : 'button',
text: this.$ts[def.title],
icon: def.icon,
to: def.to,
action: def.action,
indicate: def.indicated,
}));
},
methods: {
close() {
this.$refs.modal.close();
}
}
const props = withDefaults(defineProps<{
src?: HTMLElement;
}>(), {
});
const emit = defineEmits<{
(ev: 'closed'): void;
}>();
const preferedModalType = (deviceKind === 'desktop' && props.src != null) ? 'popup' :
deviceKind === 'smartphone' ? 'drawer' :
'dialog';
const modal = $ref<InstanceType<typeof MkModal>>();
const menu = defaultStore.state.menu;
const items = Object.keys(menuDef).filter(k => !menu.includes(k)).map(k => menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
type: def.to ? 'link' : 'button',
text: i18n.ts[def.title],
icon: def.icon,
to: def.to,
action: def.action,
indicate: def.indicated,
}));
function close() {
modal.close();
}
</script>
<style lang="scss" scoped>
.szkkfdyq {
width: 100%;
max-height: 100%;
max-width: 800px;
padding: 32px;
width: min(460px, 100vw);
padding: 24px;
box-sizing: border-box;
overflow: auto;
text-align: center;
overscroll-behavior: contain;
text-align: left;
border-radius: 16px;
@media (max-width: 500px) {
padding: 16px;
&.asDrawer {
width: 100%;
padding: 16px 16px calc(env(safe-area-inset-bottom, 0px) + 16px) 16px;
border-radius: 24px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
text-align: center;
}
> .main, > .sub {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
> * {
position: relative;
display: inline-flex;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
vertical-align: bottom;
width: 128px;
height: 128px;
border-radius: var(--radius);
@media (max-width: 500px) {
width: 100px;
height: 100px;
}
height: 100px;
border-radius: 10px;
&:hover {
background: rgba(0, 0, 0, 0.05);
color: var(--accent);
background: var(--accentedBg);
text-decoration: none;
}
> .icon {
font-size: 26px;
height: 32px;
font-size: 24px;
height: 24px;
}
> .text {
margin-top: 8px;
font-size: 0.9em;
margin-top: 12px;
font-size: 0.8em;
line-height: 1.5em;
}

View file

@ -88,7 +88,7 @@ const onBgClick = () => {
};
if (type.value === 'drawer') {
maxHeight.value = window.innerHeight / 2;
maxHeight.value = window.innerHeight / 1.5;
}
const keymap = {
@ -100,6 +100,7 @@ const MARGIN = 16;
const align = () => {
if (props.src == null) return;
if (type.value === 'drawer') return;
if (type.value === 'dialog') return;
const popover = content.value!;
if (popover == null) return;

View file

@ -25,69 +25,55 @@
<MkA v-click-anime class="item" active-class="active" to="/settings">
<i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span>
</MkA>
<button class="item _button post" data-cy-open-post-form @click="post">
<button class="item _button post" data-cy-open-post-form @click="os.post">
<i class="fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span>
</button>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, ref, watch } from 'vue';
import { host } from '@/config';
import { search } from '@/scripts/search';
<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import * as os from '@/os';
import { menuDef } from '@/menu';
import { openAccountMenu } from '@/account';
import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
import { defaultStore } from '@/store';
export default defineComponent({
setup(props, context) {
const iconOnly = ref(false);
const iconOnly = ref(false);
const menu = computed(() => defaultStore.state.menu);
const otherMenuItemIndicated = computed(() => {
for (const def in menuDef) {
if (menu.value.includes(def)) continue;
if (menuDef[def].indicated) return true;
}
return false;
});
const calcViewState = () => {
iconOnly.value = (window.innerWidth <= 1279) || (defaultStore.state.menuDisplay === 'sideIcon');
};
calcViewState();
window.addEventListener('resize', calcViewState);
watch(defaultStore.reactiveState.menuDisplay, () => {
calcViewState();
});
return {
host: host,
accounts: [],
connection: null,
menu,
menuDef: menuDef,
otherMenuItemIndicated,
iconOnly,
post: os.post,
search,
openAccountMenu:(ev) => {
openAccountMenu({
withExtraOperation: true,
}, ev);
},
more: () => {
os.popup(import('@/components/launch-pad.vue'), {}, {
}, 'closed');
},
};
},
const menu = computed(() => defaultStore.state.menu);
const otherMenuItemIndicated = computed(() => {
for (const def in menuDef) {
if (menu.value.includes(def)) continue;
if (menuDef[def].indicated) return true;
}
return false;
});
const calcViewState = () => {
iconOnly.value = (window.innerWidth <= 1279) || (defaultStore.state.menuDisplay === 'sideIcon');
};
calcViewState();
window.addEventListener('resize', calcViewState);
watch(defaultStore.reactiveState.menuDisplay, () => {
calcViewState();
});
function openAccountMenu(ev: MouseEvent) {
openAccountMenu_({
withExtraOperation: true,
}, ev);
}
function more(ev: MouseEvent) {
os.popup(import('@/components/launch-pad.vue'), {
src: ev.currentTarget ?? ev.target,
}, {
}, 'closed');
}
</script>
<style lang="scss" scoped>

View file

@ -101,11 +101,13 @@ export default defineComponent({
},
more(ev) {
os.popup(import('@/components/launch-pad.vue'), {}, {
os.popup(import('@/components/launch-pad.vue'), {
src: ev.currentTarget ?? ev.target,
}, {
}, 'closed');
},
openAccountMenu:(ev) => {
openAccountMenu: (ev) => {
openAccountMenu({
withExtraOperation: true,
}, ev);

View file

@ -122,6 +122,7 @@ export default defineComponent({
more(ev) {
os.popup(import('@/components/launch-pad.vue'), {}, {
src: ev.currentTarget ?? ev.target,
}, 'closed');
},