feat: モバイルでユーザーページのヘッダーデザインを変更することができる

This commit is contained in:
NoriDev 2023-09-25 20:30:27 +09:00
parent 87e9fc302e
commit fbbb31ef03
11 changed files with 41 additions and 16 deletions

View file

@ -54,7 +54,8 @@
- Feat: 알림에서 답글이 달린 노트의 상위 노트를 표시하지 않도록 하는 설정 추가
- Feat: 리노트와 인용 버튼을 표시하는 방법을 선택할 수 있음
- Feat: 알림 위젯에 필터, 모두 읽은 상태로 표시 버튼 추가
- Feat: 답글에 글 작성란을 표시하는 기능 추가
- Feat: 답글에 글 작성란을 표시하는 기능 추가인
- Feat: 모바일 환경에서 유저 페이지의 헤더 디자인을 변경할 수 있음
- Spec: 사용자 정의 이모티콘 라이센스를 여러 항목으로 추가할 수 있도록 (MisskeyIO/misskey#130)
- Enhance: 새로운 신고가 있는 경우, 네비게이션 바의 제어판 아이콘과 제어판 페이지의 신고 섹션에 점을 표시
- Enhance: 스크롤 시 요소 표시 기능을 Friendly 이외의 UI에도 대응

View file

@ -1237,7 +1237,7 @@ _cherrypick:
patchDescription: "Make changes to Misskey's functionality"
reactableRemoteReaction: "Allow remote custom emoji reactions to react if there is an emoji with the same name on this server."
showFollowingMessageInsteadOfButton: "Do not show the follow button in the notification field if you are already following someone"
mobileTimelineHeaderChange: "Timeline header design change in mobile environment"
mobileHeaderChange: "Header design change in mobile environment"
renameTheButtonInPostFormToNya: "Change the \"Note\" button on the note-posting form to \"Nyan!\""
renameTheButtonInPostFormToNyaDescription: "Outside of the note-posting form, they are still as \"Note\"."
_bannerDisplay:

2
locales/index.d.ts vendored
View file

@ -1245,7 +1245,7 @@ export interface Locale {
"patchDescription": string;
"reactableRemoteReaction": string;
"showFollowingMessageInsteadOfButton": string;
"mobileTimelineHeaderChange": string;
"mobileHeaderChange": string;
"renameTheButtonInPostFormToNya": string;
"renameTheButtonInPostFormToNyaDescription": string;
};

View file

@ -1242,7 +1242,7 @@ _cherrypick:
patchDescription: "Misskeyの機能に変更を加えます。"
reactableRemoteReaction: "リモートのカスタム絵文字リアクションでも、このサーバーに同じ名前の絵文字があればリアクションできるようにする"
showFollowingMessageInsteadOfButton: "既にフォローしている場合、通知欄にフォローボタンを表示しない"
mobileTimelineHeaderChange: "モバイル環境でタイムラインのヘッダーデザインを変更"
mobileHeaderChange: "モバイル環境でヘッダーデザインを変更"
renameTheButtonInPostFormToNya: "ノート作成画面の「ノート」ボタンを「にゃ!」に変更する"
renameTheButtonInPostFormToNyaDescription: "にゃあにゃんにゃんにゃんにゃにゃん?"

View file

@ -1226,7 +1226,7 @@ _cherrypick:
patchDescription: "Misskey의 기능을 변경해요."
reactableRemoteReaction: "서버에 리모트 이모지와 이름이 같은 이모지가 있으면 리모트 이모지에도 반응할 수 있음"
showFollowingMessageInsteadOfButton: "이미 팔로우한 경우 알림 필드에 팔로우 버튼을 표시하지 않음"
mobileTimelineHeaderChange: "모바일 환경에서 타임라인의 헤더 디자인을 변경"
mobileHeaderChange: "모바일 환경에서 헤더 디자인을 변경"
renameTheButtonInPostFormToNya: "노트 작성 화면의 '노트' 버튼을 '냥!'으로 변경"
renameTheButtonInPostFormToNyaDescription: "냐앙냥냥냥냐냥?"
_bannerDisplay:

View file

@ -16,13 +16,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="metadata">
<div v-if="!hideTitle" :class="[$style.titleContainer, { [$style.titleContainer_canBack]: !canBack }]">
<MkAvatar v-if="metadata.avatar" :class="$style.titleAvatar" :user="metadata.avatar" indicator/>
<div v-if="metadata.avatar" :class="$style.titleAvatarContainer" @click="top">
<MkAvatar :class="$style.titleAvatar" :user="metadata.avatar" indicator/>
</div>
<i v-else-if="metadata.icon" :class="[$style.titleIcon, metadata.icon]" @click="top"></i>
<div :class="$style.title">
<MkUserName v-if="metadata.userName" :user="metadata.userName" :nowrap="true"/>
<MkUserName v-if="metadata.userName" :user="metadata.userName" :nowrap="true" @click="top"/>
<div v-else-if="metadata.title" @click="top">{{ metadata.title }}</div>
<div v-if="!narrow && metadata.subtitle" :class="$style.subtitle">
<div v-if="!narrow && metadata.subtitle" :class="$style.subtitle" @click="top">
{{ metadata.subtitle }}
</div>
<div v-if="narrow && hasTabs" :class="[$style.subtitle, $style.activeTab]" @click="showTabsPopup">
@ -359,6 +361,16 @@ onUnmounted(() => {
margin-left: -32px;
}
.titleAvatarContainer {
$size: 32px;
contain: strict;
overflow: clip;
width: $size;
height: $size;
padding: 8px;
flex-shrink: 0;
}
.titleAvatar {
width: 100%;
height: 100%;

View file

@ -50,7 +50,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="reactableRemoteReactionEnabled">{{ i18n.ts._cherrypick.reactableRemoteReaction }}</MkSwitch>
<MkSwitch v-model="showFollowingMessageInsteadOfButtonEnabled">{{ i18n.ts._cherrypick.showFollowingMessageInsteadOfButton }}</MkSwitch>
<MkSwitch v-model="mobileTimelineHeaderChange">{{ i18n.ts._cherrypick.mobileTimelineHeaderChange }}</MkSwitch>
<MkSwitch v-model="mobileHeaderChange">{{ i18n.ts._cherrypick.mobileHeaderChange }}</MkSwitch>
<MkSwitch v-model="renameTheButtonInPostFormToNya">
{{ i18n.ts._cherrypick.renameTheButtonInPostFormToNya }}
<template #caption>{{ i18n.ts._cherrypick.renameTheButtonInPostFormToNyaDescription }}</template>
@ -87,7 +87,7 @@ const postFormVisibilityHotkey = computed(defaultStore.makeGetterSetter('postFor
const showRenoteConfirmPopup = computed(defaultStore.makeGetterSetter('showRenoteConfirmPopup'));
const reactableRemoteReactionEnabled = computed(defaultStore.makeGetterSetter('reactableRemoteReactionEnabled'));
const showFollowingMessageInsteadOfButtonEnabled = computed(defaultStore.makeGetterSetter('showFollowingMessageInsteadOfButtonEnabled'));
const mobileTimelineHeaderChange = computed(defaultStore.makeGetterSetter('mobileTimelineHeaderChange'));
const mobileHeaderChange = computed(defaultStore.makeGetterSetter('mobileHeaderChange'));
const displayHeaderNavBarWhenScroll = computed(defaultStore.makeGetterSetter('displayHeaderNavBarWhenScroll'));
const renameTheButtonInPostFormToNya = computed(defaultStore.makeGetterSetter('renameTheButtonInPostFormToNya'));

View file

@ -118,7 +118,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'infoButtonForNoteActionsEnabled',
'reactableRemoteReactionEnabled',
'showFollowingMessageInsteadOfButtonEnabled',
'mobileTimelineHeaderChange',
'mobileHeaderChange',
'renameTheButtonInPostFormToNya',
'showReplyInNotification',
'renoteQuoteButtonSeparation',

View file

@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<MkStickyContainer>
<template #header>
<CPPageHeader v-if="isMobile && defaultStore.state.mobileTimelineHeaderChange" v-model:tab="src" style="position: relative; z-index: 1001" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/>
<CPPageHeader v-if="isMobile && defaultStore.state.mobileHeaderChange" v-model:tab="src" style="position: relative; z-index: 1001" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/>
<MkPageHeader v-else-if="isMobile || !isFriendly" v-model:tab="src" style="position: relative; z-index: 1001" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/>
<MkPageHeader v-else v-model:tab="src" style="position: relative; z-index: 1001" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/>
</template>
@ -67,7 +67,7 @@ import { unisonReload } from '@/scripts/unison-reload.js';
let showEl = $ref(false);
const isFriendly = ref(miLocalStorage.getItem('ui') === 'friendly');
if (!isFriendly.value && !defaultStore.state.mobileTimelineHeaderChange) provide('shouldOmitHeaderTitle', true);
if (!isFriendly.value && !defaultStore.state.mobileHeaderChange) provide('shouldOmitHeaderTitle', true);
const MOBILE_THRESHOLD = 500;

View file

@ -5,7 +5,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<MkStickyContainer>
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<template #header>
<CPPageHeader v-if="isMobile && defaultStore.state.mobileHeaderChange" v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/>
<MkPageHeader v-else v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/>
</template>
<div>
<div v-if="user">
<XHome v-if="tab === 'home'" :user="user"/>
@ -27,7 +30,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { defineAsyncComponent, computed, watch } from 'vue';
import { defineAsyncComponent, computed, watch, ref } from 'vue';
import * as Misskey from 'cherrypick-js';
import { acct as getAcct } from '@/filters/user.js';
import * as os from '@/os.js';
@ -36,6 +39,15 @@ import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
import { getUserMenu } from '@/scripts/get-user-menu.js';
import { mainRouter } from '@/router.js';
import { defaultStore } from '@/store.js';
import { deviceKind } from '@/scripts/device-kind.js';
const MOBILE_THRESHOLD = 500;
const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
window.addEventListener('resize', () => {
isMobile.value = deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD;
});
const XHome = defineAsyncComponent(() => import('./home.vue'));
const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue'));

View file

@ -525,7 +525,7 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'account',
default: true,
},
mobileTimelineHeaderChange: {
mobileHeaderChange: {
where: 'device',
default: false,
},