Skip to content

Commit

Permalink
feat: Alt周りの強化 (#142)
Browse files Browse the repository at this point in the history
* enhance: apngの場合apngと表示するように

* 画像のタイトルには必ずファイル名を使用するように

* ファイル名とALTを同時に表示するように

* ALTがない時にはALTのブロックを非表示に

* 隠すボタンのスタイル調整

* altが存在するときに投稿フォームでインジケータを表示するように

* Altが設定されてない場合警告を出すように

* add locale

* update changelog

* fix: 画像のクロップ時にモバイルUIでは画像の全体が表示されない問題

* update changelog

---------

Co-authored-by: Esurio <[email protected]>
  • Loading branch information
1673beta and Esurio authored Aug 14, 2024
1 parent 5f6acc5 commit 10f8e04
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 12 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG_engawa.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@

### Client
- 検索ウィジェットにオートフォーカスが当たらなくなりました
- 画像がAPNGの場合GIFではなくAPNGと表示するように
- 隠すボタンのスタイル調整
- ファイル名とALTを同時に表示するように
- ALTテキストが存在する場合投稿フォームのファイルにインジケータを表示するように
- ALTテキストがない場合警告を出すオプションを追加
- 画像のタイトルには必ずファイル名を使用するように
- fix: クロッパーで画像の全体が表示されないことがある問題

### Server
- 検索機能に新しいパラメータを追加( [1673beta/cherrypick#94](https://github.com/1673beta/cherrypick/issues/94) )
Expand Down
5 changes: 5 additions & 0 deletions locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3024,3 +3024,8 @@ _dice:
_isIndexable:
title: "Indexable"
description: "This is kmyblue compatible feature. If you want to prevent your account from being indexed by search engines, please disable this option."

_altWarning:
noAltWarning: "ファイルに代替テキストが設定されていません。"
showNoAltWarning: "画像に代替テキストが設定されていない場合に警告を表示する"
postAnyWay: "投稿フォームへ"
14 changes: 14 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11797,6 +11797,20 @@ export interface Locale extends ILocale {
*/
"description": string;
};
"_altWarning": {
/**
* ファイルに代替テキストが設定されていません。
*/
"noAltWarning": string;
/**
* 画像に代替テキストが設定されていない場合に警告を表示する
*/
"showNoAltWarning": string;
/**
* 投稿フォームへ
*/
"postAnyWay": string;
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
5 changes: 5 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3149,3 +3149,8 @@ _dice:
_isIndexable:
title: "公開ノートをインデックス化"
description: "kmy互換機能。公開ノートをインデックス化するかどうかを設定します。"

_altWarning:
noAltWarning: "ファイルに代替テキストが設定されていません。"
showNoAltWarning: "画像に代替テキストが設定されていない場合に警告を表示する"
postAnyWay: "投稿フォームへ"
3 changes: 3 additions & 0 deletions packages/frontend/src/components/MkCropperDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ const onImageLoad = () => {
loading.value = false;

if (cropper) {
cropper.getCropperCanvas();
cropper.getCropperImage()!.$center('contain');
cropper.getCropperSelection()!.$center();
}
Expand Down Expand Up @@ -159,6 +160,7 @@ onMounted(() => {
width: var(--vw);
height: var(--vh);
position: relative;
object-fit: contain;

> .loading {
position: absolute;
Expand All @@ -183,6 +185,7 @@ onMounted(() => {
> ::v-deep(cropper-canvas) {
width: 100%;
height: 100%;
object-fit: contain;

> cropper-selection > cropper-handle[action="move"] {
background: transparent;
Expand Down
11 changes: 7 additions & 4 deletions packages/frontend/src/components/MkDriveFileThumbnail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only

<template>
<div ref="thumbnail" :class="$style.root">
<ImgWithBlurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.name" :title="file.name" :cover="fit !== 'contain'"/>
<ImgWithBlurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.comment" :title="file.name" :cover="fit !== 'contain'" :show-alt-indicator="showAltIndicator" />
<i v-else-if="is === 'image'" class="ti ti-photo" :class="$style.icon"></i>
<i v-else-if="is === 'video'" class="ti ti-video" :class="$style.icon"></i>
<i v-else-if="is === 'audio' || is === 'midi'" class="ti ti-file-music" :class="$style.icon"></i>
Expand All @@ -24,10 +24,13 @@ import { computed } from 'vue';
import * as Misskey from 'cherrypick-js';
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';

const props = defineProps<{
const props = withDefaults(defineProps<{
file: Misskey.entities.DriveFile;
fit: 'cover' | 'contain';
}>();
fit: string;
showAltIndicator: boolean;
}>(), {
showAltIndicator: false,
})

const is = computed(() => {
if (props.file.type.startsWith('image/')) return 'image';
Expand Down
20 changes: 20 additions & 0 deletions packages/frontend/src/components/MkImgWithBlurhash.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
>
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="[$style.img, { [$style.noDrag]: noDrag }]" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
<i v-if="alt && showAltIndicator" :class="$style.altIndicator" class="ti ti-alt"></i>
</TransitionGroup>
</div>
</template>
Expand Down Expand Up @@ -82,6 +83,7 @@ const props = withDefaults(defineProps<{
forceBlurhash?: boolean;
onlyAvgColor?: boolean; // 軽量化のためにBlurhashを使わずに平均色だけを描画
noDrag?: boolean;
showAltIndicator?: boolean;
}>(), {
transition: null,
src: null,
Expand All @@ -93,6 +95,7 @@ const props = withDefaults(defineProps<{
forceBlurhash: false,
onlyAvgColor: false,
noDrag: false,
showAltIndicator: false,
});

const viewId = uuid();
Expand Down Expand Up @@ -269,4 +272,21 @@ onUnmounted(() => {
-webkit-user-drag: none;
}
}

.altIndicator {
display: flex;
gap: 4px;
position: absolute;
border-radius: 8px;
overflow: hidden;
top: 0;
right: 0;
background-color: var(--bg);
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
color: var(--accent);
font-size: 1em;
padding: 6px 8px;
text-align: center;
}
</style>
9 changes: 5 additions & 4 deletions packages/frontend/src/components/MkMediaImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:forceBlurhash="hide"
:cover="hide || cover"
:alt="image.comment || image.name"
:title="image.comment || image.name"
:title="image.name"
:width="image.properties.width"
:height="image.properties.height"
:style="hide ? 'filter: brightness(0.7);' : null"
Expand All @@ -44,7 +44,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<template v-else-if="controls">
<div :class="$style.indicators">
<div v-if="['image/gif', 'image/apng'].includes(image.type)" :class="$style.indicator">GIF</div>
<div v-if="['image/gif'].includes(image.type)" :class="$style.indicator">GIF</div>
<div v-if="['image/apng'].includes(image.type)" :class="$style.indicator">APNG</div>
<div v-if="image.comment" :class="$style.indicator">ALT</div>
<div v-if="image.isSensitive" :class="$style.indicator" style="color: var(--warn);" :title="i18n.ts.sensitive"><i class="ti ti-eye-exclamation"></i></div>
</div>
Expand Down Expand Up @@ -220,9 +221,9 @@ onUnmounted(() => {
display: block;
position: absolute;
border-radius: 6px;
background-color: var(--fg);
background-color: var(--bg);
color: var(--accentLighten);
font-size: 12px;
font-size: 18px;
opacity: .5;
padding: 5px 8px;
text-align: center;
Expand Down
53 changes: 51 additions & 2 deletions packages/frontend/src/components/MkMediaList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,9 @@ onMounted(() => {
[itemData.w, itemData.h] = [itemData.h, itemData.w];
}
itemData.msrc = file.thumbnailUrl ?? undefined;
itemData.alt = file.comment ?? file.name;
itemData.alt = file.comment || undefined;
itemData.comment = file.comment ?? file.name;
itemData.title = file.name;
itemData.thumbCropped = true;

return itemData;
Expand All @@ -179,7 +180,25 @@ onMounted(() => {
el.appendChild(textBox);

pswp.on('change', () => {
textBox.textContent = pswp.currSlide?.data.comment;
const altText = pswp.currSlide?.data.alt || null;
textBox.textContent = altText;
if (!altText) {
el.style.display = 'none';
}
});
},
});
lightbox?.pswp?.ui?.registerElement({
name: 'fileName',
className: 'pswp__file-name-container',
appendTo: 'wrapper',
onInit: (el, pswp) => {
const textBox = document.createElement('p');
textBox.className = 'pswp__file-name _acrylic';
el.appendChild(textBox);

pswp.on('change', () => {
textBox.textContent = pswp.currSlide?.data.title;
});
},
});
Expand Down Expand Up @@ -338,13 +357,31 @@ defineExpose({
flex-direction: row;
align-items: center;

position: absolute;
bottom: 100px;
left: 50%;
transform: translateX(-50%);

width: 75%;
max-width: 800px;

z-index: 2;
}

.pswp__file-name-container {
display: flex;
flex-direction: row;
align-items: center;

position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);

width: 75%;
max-width: 800px;

z-index: 1;
}

.pswp__alt-text {
Expand All @@ -358,4 +395,16 @@ defineExpose({
text-shadow: var(--bg) 0 0 10px, var(--bg) 0 0 3px, var(--bg) 0 0 3px;
white-space: pre-line;
}

.pswp__file-name {
color: var(--fg);
margin: 0 auto;
text-align: center;
padding: var(--margin);
border-radius: var(--radius);
max-height: 16em;
overflow-y: auto;
text-shadow: var(--bg) 0 0 10px, var(--bg) 0 0 3px, var(--bg) 0 0 3px;
white-space: pre-line;
}
</style>
13 changes: 12 additions & 1 deletion packages/frontend/src/components/MkPostForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ import { emojiPicker } from '@/scripts/emoji-picker.js';
import { vibrate } from '@/scripts/vibrate.js';
import * as sound from '@/scripts/sound.js';
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
import { file } from '.storybook/fakes';


const $i = signinRequired();
Expand Down Expand Up @@ -183,7 +184,7 @@ const visibilityButton = shallowRef<HTMLElement>();
const posting = ref(false);
const posted = ref(false);
const text = ref(props.initialText ?? '');
const files = ref(props.initialFiles ?? []);
const files = ref(props.initialFiles ?? ([] as Misskey.entities.DriveFile[]));
const poll = ref<PollEditorModelValue | null>(null);
const event = ref<{
title: string;
Expand Down Expand Up @@ -791,6 +792,16 @@ async function post(ev?: MouseEvent) {
});
return;
}
if (defaultStore.state.showNoAltTextWarning && files.value.some((f) => f.comment == null || f.comment.length === 0)) {
const { canceled } = await os.confirm({
type: 'warning',
text: i18n.ts._altWarning.noAltWarning,
okText: i18n.ts.goBack,
cancelText: i18n.ts._altWarning.postAnyWay,
});

if (!canceled) return;
}

if (ev) {
const el = (ev.currentTarget ?? ev.target) as HTMLElement | null;
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkPostFormAttaches.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Sortable :modelValue="props.modelValue" :class="$style.files" itemKey="id" :animation="150" :delay="100" :delayOnTouchOnly="true" @update:modelValue="v => emit('update:modelValue', v)">
<template #item="{element}">
<div :class="$style.file" @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)">
<MkDriveFileThumbnail :data-id="element.id" :class="$style.thumbnail" :file="element" fit="cover"/>
<MkDriveFileThumbnail :data-id="element.id" :class="$style.thumbnail" :file="element" fit="cover" :show-alt-indicator="true" />
<div v-if="element.isSensitive" :class="$style.sensitive">
<i class="ti ti-eye-exclamation" style="margin: auto;"></i>
</div>
Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/src/pages/settings/general.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSelect>
<MkSwitch v-model="showFixedPostFormInReplies">{{ i18n.ts.showFixedPostFormInReplies }}<template #caption>{{ i18n.ts.showFixedPostFormInRepliesDescription }}</template> <span class="_beta">CherryPick</span></MkSwitch>
<MkSwitch v-model="allMediaNoteCollapse">{{ i18n.ts.allMediaNoteCollapse }} <span class="_beta">CherryPick</span></MkSwitch>
<MkSwitch v-model="showNoAltTextWarning">{{ i18n.ts._altWarning.showNoAltWarning }}</MkSwitch>
</div>

<MkSelect v-model="instanceTicker">
Expand Down Expand Up @@ -471,6 +472,7 @@ const allMediaNoteCollapse = computed(defaultStore.makeGetterSetter('allMediaNot
const nsfwOpenBehavior = computed(defaultStore.makeGetterSetter('nsfwOpenBehavior'));
const renoteVisibilitySelection = computed(defaultStore.makeGetterSetter('renoteVisibilitySelection'));
const forceRenoteVisibilitySelection = computed(defaultStore.makeGetterSetter('forceRenoteVisibilitySelection'));
const showNoAltTextWarning = computed(defaultStore.makeGetterSetter('showNoAltTextWarning'));

watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string);
Expand Down
4 changes: 4 additions & 0 deletions packages/frontend/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'account',
default: [] as string[],
},
showNoAltTextWarning: {
where: 'account',
default: true,
},

menu: {
where: 'deviceAccount',
Expand Down

0 comments on commit 10f8e04

Please sign in to comment.