mirror of
https://github.com/misskey-dev/misskey.git
synced 2025-01-01 04:56:19 +01:00
最新への追従とレイアウト微調整
This commit is contained in:
parent
7e0343d724
commit
fdf20a6605
6 changed files with 56 additions and 38 deletions
|
@ -4,26 +4,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkFolder :spacerMax="8" :spacerMin="8">
|
<div :class="$style.sortOrderArea">
|
||||||
<template #icon><i class="ti ti-arrows-sort"></i></template>
|
<div :class="$style.sortOrderAreaTags">
|
||||||
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.sortOrder }}</template>
|
<MkTagItem
|
||||||
<div :class="$style.sortOrderArea">
|
v-for="order in sortOrders"
|
||||||
<div :class="$style.sortOrderAreaTags">
|
:key="order.key"
|
||||||
<MkTagItem
|
:iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'"
|
||||||
v-for="order in sortOrders"
|
:exButtonIconClass="'ti ti-x'"
|
||||||
:key="order.key"
|
:content="order.key"
|
||||||
:iconClass="order.direction === 'ASC' ? 'ti ti-arrow-up' : 'ti ti-arrow-down'"
|
@click="onToggleSortOrderButtonClicked(order)"
|
||||||
:exButtonIconClass="'ti ti-x'"
|
@exButtonClick="onRemoveSortOrderButtonClicked(order.key)"
|
||||||
:content="order.key"
|
/>
|
||||||
@click="onToggleSortOrderButtonClicked(order)"
|
|
||||||
@exButtonClick="onRemoveSortOrderButtonClicked(order.key)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<MkButton :class="$style.sortOrderAddButton" @click="onAddSortOrderButtonClicked">
|
|
||||||
<span class="ti ti-plus"/>
|
|
||||||
</MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
<MkButton :class="$style.sortOrderAddButton" @click="onAddSortOrderButtonClicked">
|
||||||
|
<span class="ti ti-plus"/>
|
||||||
|
</MkButton>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
|
@ -5,6 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
v-if="cell.row.using"
|
||||||
ref="rootEl"
|
ref="rootEl"
|
||||||
class="mk_grid_td"
|
class="mk_grid_td"
|
||||||
:class="$style.cell"
|
:class="$style.cell"
|
||||||
|
@ -26,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
[needsContentCentering ? $style.center : {}],
|
[needsContentCentering ? $style.center : {}],
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<div v-if="!editing" ref="contentAreaEl">
|
<div v-if="!editing" ref="contentAreaEl" :class="$style.contentArea">
|
||||||
<div :class="$style.content">
|
<div :class="$style.content">
|
||||||
<div v-if="cellType === 'text'">
|
<div v-if="cellType === 'text'">
|
||||||
{{ cell.value }}
|
{{ cell.value }}
|
||||||
|
@ -51,7 +52,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else ref="inputAreaEl">
|
<div v-else ref="inputAreaEl" :class="$style.inputArea">
|
||||||
<input
|
<input
|
||||||
v-if="cellType === 'text'"
|
v-if="cellType === 'text'"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -105,13 +106,15 @@ const props = defineProps<{
|
||||||
bus: GridEventEmitter,
|
bus: GridEventEmitter,
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { cell, rowSetting, bus } = toRefs(props);
|
const { cell, bus } = toRefs(props);
|
||||||
|
|
||||||
const rootEl = shallowRef<InstanceType<typeof HTMLTableCellElement>>();
|
const rootEl = shallowRef<InstanceType<typeof HTMLTableCellElement>>();
|
||||||
const contentAreaEl = shallowRef<InstanceType<typeof HTMLDivElement>>();
|
const contentAreaEl = shallowRef<InstanceType<typeof HTMLDivElement>>();
|
||||||
const inputAreaEl = shallowRef<InstanceType<typeof HTMLDivElement>>();
|
const inputAreaEl = shallowRef<InstanceType<typeof HTMLDivElement>>();
|
||||||
|
|
||||||
|
/** 値が編集中かどうか */
|
||||||
const editing = ref<boolean>(false);
|
const editing = ref<boolean>(false);
|
||||||
|
/** 編集中の値. {@link beginEditing}と{@link endEditing}内、および各inputタグやそのコールバックからの操作のみを想定する */
|
||||||
const editingValue = ref<CellValue>(undefined);
|
const editingValue = ref<CellValue>(undefined);
|
||||||
|
|
||||||
const cellWidth = computed(() => cell.value.column.width);
|
const cellWidth = computed(() => cell.value.column.width);
|
||||||
|
@ -148,7 +151,8 @@ function onCellDoubleClick(ev: MouseEvent) {
|
||||||
function onOutsideMouseDown(ev: MouseEvent) {
|
function onOutsideMouseDown(ev: MouseEvent) {
|
||||||
const isOutside = ev.target instanceof Node && !rootEl.value?.contains(ev.target);
|
const isOutside = ev.target instanceof Node && !rootEl.value?.contains(ev.target);
|
||||||
if (isOutside || !equalCellAddress(cell.value.address, getCellAddress(ev.target as HTMLElement))) {
|
if (isOutside || !equalCellAddress(cell.value.address, getCellAddress(ev.target as HTMLElement))) {
|
||||||
endEditing(true);
|
endEditing(true, editingValue.value);
|
||||||
|
editingValue.value = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,13 +170,15 @@ function onCellKeyDown(ev: KeyboardEvent) {
|
||||||
} else {
|
} else {
|
||||||
switch (ev.code) {
|
switch (ev.code) {
|
||||||
case 'Escape': {
|
case 'Escape': {
|
||||||
endEditing(false);
|
endEditing(false, editingValue.value);
|
||||||
|
editingValue.value = undefined;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'NumpadEnter':
|
case 'NumpadEnter':
|
||||||
case 'Enter': {
|
case 'Enter': {
|
||||||
if (!ev.isComposing) {
|
if (!ev.isComposing) {
|
||||||
endEditing(true);
|
endEditing(true, editingValue.value);
|
||||||
|
editingValue.value = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +249,7 @@ async function beginEditing(target: HTMLElement) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function endEditing(applyValue: boolean) {
|
function endEditing(applyValue: boolean, newValue: CellValue) {
|
||||||
if (!editing.value) {
|
if (!editing.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -251,11 +257,10 @@ function endEditing(applyValue: boolean) {
|
||||||
emit('operation:endEdit', cell.value);
|
emit('operation:endEdit', cell.value);
|
||||||
unregisterOutsideMouseDown();
|
unregisterOutsideMouseDown();
|
||||||
|
|
||||||
if (applyValue && editingValue.value !== cell.value.value) {
|
if (applyValue && newValue !== cell.value.value) {
|
||||||
emitValueChange(editingValue.value);
|
emitValueChange(newValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
editingValue.value = undefined;
|
|
||||||
editing.value = false;
|
editing.value = false;
|
||||||
|
|
||||||
rootEl.value?.focus();
|
rootEl.value?.focus();
|
||||||
|
@ -279,11 +284,15 @@ useTooltip(rootEl, (showing) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = cell.value.violation.violations.filter(it => !it.valid).map(it => it.result.message).join('\n');
|
const content = cell.value.violation.violations.filter(it => !it.valid).map(it => it.result.message).join('\n');
|
||||||
os.popup(defineAsyncComponent(() => import('@/components/grid/MkCellTooltip.vue')), {
|
const result = os.popup(defineAsyncComponent(() => import('@/components/grid/MkCellTooltip.vue')), {
|
||||||
showing,
|
showing,
|
||||||
content,
|
content,
|
||||||
targetElement: rootEl.value!,
|
targetElement: rootEl.value!,
|
||||||
}, {}, 'closed');
|
}, {
|
||||||
|
closed: () => {
|
||||||
|
result.dispose();
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -339,6 +348,11 @@ $cellHeight: 28px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contentArea, .inputArea {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0 8px;
|
padding: 0 8px;
|
||||||
|
|
|
@ -82,14 +82,14 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// non-reactive
|
// non-reactive
|
||||||
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const rowSetting: Required<GridRowSetting> = {
|
const rowSetting: Required<GridRowSetting> = {
|
||||||
...defaultGridRowSetting,
|
...defaultGridRowSetting,
|
||||||
...props.settings.row,
|
...props.settings.row,
|
||||||
};
|
};
|
||||||
|
|
||||||
// non-reactive
|
// non-reactive
|
||||||
|
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||||
const columnSettings = props.settings.cols;
|
const columnSettings = props.settings.cols;
|
||||||
|
|
||||||
// non-reactive
|
// non-reactive
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { DataSource, SizeStyle } from '@/components/grid/grid.js';
|
||||||
import { CELL_ADDRESS_NONE, CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
|
import { CELL_ADDRESS_NONE, CellAddress, CellValue, GridCell } from '@/components/grid/cell.js';
|
||||||
import { GridRow } from '@/components/grid/row.js';
|
import { GridRow } from '@/components/grid/row.js';
|
||||||
import { GridContext } from '@/components/grid/grid-event.js';
|
import { GridContext } from '@/components/grid/grid-event.js';
|
||||||
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js';
|
||||||
import { GridColumn, GridColumnSetting } from '@/components/grid/column.js';
|
import { GridColumn, GridColumnSetting } from '@/components/grid/column.js';
|
||||||
|
|
||||||
export function isCellElement(elem: HTMLElement): boolean {
|
export function isCellElement(elem: HTMLElement): boolean {
|
||||||
|
|
|
@ -117,7 +117,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<XSortOrderFolder :sortOrders="sortOrders" @update="onSortOrderUpdate"/>
|
<MkFolder :spacerMax="8" :spacerMin="8">
|
||||||
|
<template #icon><i class="ti ti-arrows-sort"></i></template>
|
||||||
|
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.sortOrder }}</template>
|
||||||
|
<MkSortOrderEditor :sortOrders="sortOrders" @update="onSortOrderUpdate"/>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
|
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
|
||||||
<MkButton primary @click="onSearchRequest">
|
<MkButton primary @click="onSearchRequest">
|
||||||
|
@ -172,13 +176,13 @@ import { GridCellValidationEvent, GridCellValueChangeEvent, GridEvent } from '@/
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
||||||
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
||||||
import XSortOrderFolder from '@/pages/admin/custom-emojis-manager.sort-order-folder.vue';
|
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import { GridSetting } from '@/components/grid/grid.js';
|
import { GridSetting } from '@/components/grid/grid.js';
|
||||||
import { selectFile } from '@/scripts/select-file.js';
|
import { selectFile } from '@/scripts/select-file.js';
|
||||||
import { copyGridDataToClipboard, removeDataFromGrid } from '@/components/grid/grid-utils.js';
|
import { copyGridDataToClipboard, removeDataFromGrid } from '@/components/grid/grid-utils.js';
|
||||||
|
import MkSortOrderEditor from '@/components/MkSortOrderEditor.vue';
|
||||||
|
|
||||||
type GridItem = {
|
type GridItem = {
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
|
|
@ -53,7 +53,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<XSortOrderFolder :sortOrders="sortOrders" @update="onSortOrderChanged"/>
|
<MkFolder :spacerMax="8" :spacerMin="8">
|
||||||
|
<template #icon><i class="ti ti-arrows-sort"></i></template>
|
||||||
|
<template #label>{{ i18n.ts._customEmojisManager._gridCommon.sortOrder }}</template>
|
||||||
|
<MkSortOrderEditor :sortOrders="sortOrders" @update="onSortOrderChanged"/>
|
||||||
|
</MkFolder>
|
||||||
|
|
||||||
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
|
<div :class="[[spMode ? $style.searchButtonsSp : $style.searchButtons]]">
|
||||||
<MkButton primary @click="onSearchRequest">
|
<MkButton primary @click="onSearchRequest">
|
||||||
|
@ -93,11 +97,11 @@ import { emptyStrToUndefined, GridSortOrder, RequestLogItem } from '@/pages/admi
|
||||||
import { GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
import { GridCellValueChangeEvent, GridEvent } from '@/components/grid/grid-event.js';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
import XRegisterLogsFolder from '@/pages/admin/custom-emojis-manager.logs-folder.vue';
|
||||||
import XSortOrderFolder from '@/pages/admin/custom-emojis-manager.sort-order-folder.vue';
|
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { GridSetting } from '@/components/grid/grid.js';
|
import { GridSetting } from '@/components/grid/grid.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
import MkPagingButtons from '@/components/MkPagingButtons.vue';
|
||||||
|
import MkSortOrderEditor from '@/components/MkSortOrderEditor.vue';
|
||||||
|
|
||||||
type GridItem = {
|
type GridItem = {
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
|
|
Loading…
Reference in a new issue