mirror of
https://iceshrimp.dev/iceshrimp/iceshrimp
synced 2024-11-27 22:38:10 +09:00
enhance(client): improve launch pad usability
This commit is contained in:
parent
bf72af1289
commit
680e1ed3ac
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :prefer-type="'dialog'" @click="$refs.modal.close()" @closed="$emit('closed')">
|
<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">
|
<div class="szkkfdyq _popup _shadow" :class="{ asDrawer: type === 'drawer' }" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : '' }">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<template v-for="item in items">
|
<template v-for="item in items">
|
||||||
<button v-if="item.action" v-click-anime class="_button" @click="$event => { item.action($event); close(); }">
|
<button v-if="item.action" v-click-anime class="_button" @click="$event => { item.action($event); close(); }">
|
||||||
@ -33,97 +33,94 @@
|
|||||||
</MkModal>
|
</MkModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent } from 'vue';
|
import { } from 'vue';
|
||||||
import MkModal from '@/components/ui/modal.vue';
|
import MkModal from '@/components/ui/modal.vue';
|
||||||
import { menuDef } from '@/menu';
|
import { menuDef } from '@/menu';
|
||||||
import { instanceName } from '@/config';
|
import { instanceName } from '@/config';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
import { deviceKind } from '@/scripts/device-kind';
|
||||||
|
|
||||||
export default defineComponent({
|
const props = withDefaults(defineProps<{
|
||||||
components: {
|
src?: HTMLElement;
|
||||||
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 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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.szkkfdyq {
|
.szkkfdyq {
|
||||||
width: 100%;
|
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
max-width: 800px;
|
width: min(460px, 100vw);
|
||||||
padding: 32px;
|
padding: 24px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
text-align: center;
|
overscroll-behavior: contain;
|
||||||
|
text-align: left;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
&.asDrawer {
|
||||||
padding: 16px;
|
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 {
|
> .main, > .sub {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
width: 128px;
|
height: 100px;
|
||||||
height: 128px;
|
border-radius: 10px;
|
||||||
border-radius: var(--radius);
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
width: 100px;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba(0, 0, 0, 0.05);
|
color: var(--accent);
|
||||||
|
background: var(--accentedBg);
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .icon {
|
> .icon {
|
||||||
font-size: 26px;
|
font-size: 24px;
|
||||||
height: 32px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .text {
|
> .text {
|
||||||
margin-top: 8px;
|
margin-top: 12px;
|
||||||
font-size: 0.9em;
|
font-size: 0.8em;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ const onBgClick = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (type.value === 'drawer') {
|
if (type.value === 'drawer') {
|
||||||
maxHeight.value = window.innerHeight / 2;
|
maxHeight.value = window.innerHeight / 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
@ -100,6 +100,7 @@ const MARGIN = 16;
|
|||||||
const align = () => {
|
const align = () => {
|
||||||
if (props.src == null) return;
|
if (props.src == null) return;
|
||||||
if (type.value === 'drawer') return;
|
if (type.value === 'drawer') return;
|
||||||
|
if (type.value === 'dialog') return;
|
||||||
|
|
||||||
const popover = content.value!;
|
const popover = content.value!;
|
||||||
if (popover == null) return;
|
if (popover == null) return;
|
||||||
|
@ -25,69 +25,55 @@
|
|||||||
<MkA v-click-anime class="item" active-class="active" to="/settings">
|
<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>
|
<i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span>
|
||||||
</MkA>
|
</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>
|
<i class="fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { computed, defineComponent, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import { host } from '@/config';
|
|
||||||
import { search } from '@/scripts/search';
|
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { menuDef } from '@/menu';
|
import { menuDef } from '@/menu';
|
||||||
import { openAccountMenu } from '@/account';
|
import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
|
|
||||||
export default defineComponent({
|
const iconOnly = ref(false);
|
||||||
setup(props, context) {
|
|
||||||
const iconOnly = ref(false);
|
|
||||||
|
|
||||||
const menu = computed(() => defaultStore.state.menu);
|
const menu = computed(() => defaultStore.state.menu);
|
||||||
const otherMenuItemIndicated = computed(() => {
|
const otherMenuItemIndicated = computed(() => {
|
||||||
for (const def in menuDef) {
|
for (const def in menuDef) {
|
||||||
if (menu.value.includes(def)) continue;
|
if (menu.value.includes(def)) continue;
|
||||||
if (menuDef[def].indicated) return true;
|
if (menuDef[def].indicated) return true;
|
||||||
}
|
}
|
||||||
return false;
|
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 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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -101,11 +101,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
more(ev) {
|
more(ev) {
|
||||||
os.popup(import('@/components/launch-pad.vue'), {}, {
|
os.popup(import('@/components/launch-pad.vue'), {
|
||||||
|
src: ev.currentTarget ?? ev.target,
|
||||||
|
}, {
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
openAccountMenu:(ev) => {
|
openAccountMenu: (ev) => {
|
||||||
openAccountMenu({
|
openAccountMenu({
|
||||||
withExtraOperation: true,
|
withExtraOperation: true,
|
||||||
}, ev);
|
}, ev);
|
||||||
|
@ -122,6 +122,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
more(ev) {
|
more(ev) {
|
||||||
os.popup(import('@/components/launch-pad.vue'), {}, {
|
os.popup(import('@/components/launch-pad.vue'), {}, {
|
||||||
|
src: ev.currentTarget ?? ev.target,
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user