improve(friendly): Improved design of note post form in mobile environment

This commit is contained in:
NoriDev 2022-09-12 01:32:31 +09:00
parent 8bc7fae241
commit 3dab9d32df
3 changed files with 59 additions and 5 deletions

View file

@ -15,6 +15,7 @@
- 클라이언트: (friendly) 모바일 환경에서 스크롤을 내리면 플로팅 버튼이 감춰지도록 변경
- 클라이언트: (friendly) 서버와 연결이 끊어졌을 때 10초간 경고를 표시한 후 자동으로 숨기기
- 클라이언트: (friendly) 서버와 연결이 끊어졌을 때 헤더에 연결 끊김 표시
- 클라이언트: (friendly) 모바일 환경에서 노트 작성 폼의 디자인 개선
- 클라이언트: Google Translate 서비스 추가 (thanks to @ltlapy)
- 클라이언트: DeepL과 Google Translate를 선택할 수 있는 옵션 추가
- 클라이언트: Enter 키를 눌러 보내기 옵션 추가

View file

@ -1,7 +1,7 @@
<template>
<div
v-size="{ max: [310, 500] }" class="gafaadew"
:class="{ modal, _popup: modal, friendly: isFriendly }"
:class="{ modal, _popup: modal, friendly: isFriendly, 'friendly-not-desktop': isFriendly && !isDesktop }"
@dragover.stop="onDragover"
@dragenter="onDragenter"
@dragleave="onDragleave"
@ -41,7 +41,7 @@
</div>
<MkInfo v-if="hasNotSpecifiedMentions" warn class="hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
<input v-show="useCw" ref="cwInputEl" v-model="cw" class="cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown">
<textarea ref="textareaEl" v-model="text" class="text" :class="{ withCw: useCw }" :disabled="posting" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
<textarea ref="textareaEl" v-model="text" class="text" :class="{ withCw: useCw, 'friendly-not-desktop': isFriendly && !isDesktop }" :disabled="posting" :placeholder="placeholder" data-cy-post-form-text @keydown="onKeydown" @paste="onPaste" @compositionupdate="onCompositionUpdate" @compositionend="onCompositionEnd"/>
<input v-show="withHashtags" ref="hashtagsInputEl" v-model="hashtags" class="hashtags" :placeholder="i18n.ts.hashtags" list="hashtags">
<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
<XPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
@ -64,7 +64,7 @@
</template>
<script lang="ts" setup>
import { inject, watch, nextTick, onMounted, defineAsyncComponent } from 'vue';
import { inject, watch, nextTick, onMounted, defineAsyncComponent, ref } from 'vue';
import * as mfm from 'mfm-js';
import * as misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor';
@ -90,8 +90,18 @@ import { i18n } from '@/i18n';
import { instance } from '@/instance';
import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account';
import { uploadFile } from '@/scripts/upload';
import { deviceKind } from '@/scripts/device-kind';
const isFriendly = $ref(localStorage.getItem('ui') === 'friendly');
const DESKTOP_THRESHOLD = 1100;
const MOBILE_THRESHOLD = 500;
// UI deviceKind === 'desktop'
const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD);
const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
window.addEventListener('resize', () => {
isMobile.value = deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD;
});
const modal = inject('modal');
@ -720,6 +730,12 @@ onMounted(() => {
nextTick(() => watchForDraft());
});
if (!isDesktop.value) {
window.addEventListener('resize', () => {
if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true;
}, { passive: true });
}
});
</script>
@ -736,6 +752,13 @@ onMounted(() => {
max-width: 800px;
}
&.friendly-not-desktop {
margin: initial !important;
padding: initial !important;
border-radius: initial !important;
max-width: 100% !important;
}
> header {
z-index: 1000;
height: 66px;
@ -924,6 +947,10 @@ onMounted(() => {
&.withCw {
padding-top: 8px;
}
&.friendly-not-desktop {
min-height: 200px !important;
}
}
> footer {
@ -984,6 +1011,10 @@ onMounted(() => {
min-height: 80px;
}
&.friendly-not-desktop {
min-height: 200px !important;
}
> footer {
padding: 0 8px 8px 8px;
}

View file

@ -2,7 +2,7 @@
<transition :name="$store.state.animation ? (type === 'drawer') ? 'modal-drawer' : (type === 'popup') ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? 200 : 0" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="onOpened">
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :class="{ drawer: type === 'drawer', dialog: type === 'dialog' || type === 'dialog:top', popup: type === 'popup' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div class="bg _modalBg" :class="{ transparent: transparentBg && (type === 'popup') }" :style="{ zIndex }" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top' }" :style="{ zIndex }" @click.self="onBgClick">
<div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top', friendly: isFriendly && !isDesktop }" :style="{ zIndex }" @click.self="onBgClick">
<slot :max-height="maxHeight" :type="type"></slot>
</div>
</div>
@ -10,12 +10,23 @@
</template>
<script lang="ts" setup>
import { nextTick, onMounted, watch, provide } from 'vue';
import { nextTick, onMounted, watch, provide, ref } from 'vue';
import * as os from '@/os';
import { isTouchUsing } from '@/scripts/touch';
import { defaultStore } from '@/store';
import { deviceKind } from '@/scripts/device-kind';
const isFriendly = $ref(localStorage.getItem('ui') === 'friendly');
const DESKTOP_THRESHOLD = 1100;
const MOBILE_THRESHOLD = 500;
// UI deviceKind === 'desktop'
const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD);
const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
window.addEventListener('resize', () => {
isMobile.value = deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD;
});
function getFixedContainer(el: Element | null): Element | null {
if (el == null || el.tagName === 'BODY') return null;
const position = window.getComputedStyle(el).getPropertyValue('position');
@ -246,6 +257,12 @@ onMounted(() => {
align();
}).observe(content!);
});
if (!isDesktop.value) {
window.addEventListener('resize', () => {
if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true;
}, { passive: true });
}
});
defineExpose({
@ -368,6 +385,11 @@ defineExpose({
margin-top: 0;
}
}
&.friendly {
padding: initial;
mask-image: initial;
}
}
}