summaryrefslogtreecommitdiff
path: root/packages/client/src/components
diff options
context:
space:
mode:
authortamaina <tamaina@hotmail.co.jp>2022-05-28 01:31:23 +0900
committertamaina <tamaina@hotmail.co.jp>2022-05-28 01:31:23 +0900
commitfa99d9c6fee3a7d6f72e254e0aa55972cd6538fb (patch)
tree43d941bbacc9cfaa911fc785fce0b34af4ef6fcc /packages/client/src/components
parentMerge branch 'develop' into pizzax-indexeddb (diff)
parentfix(docs): correct information for drive upload (#8736) (diff)
downloadmisskey-fa99d9c6fee3a7d6f72e254e0aa55972cd6538fb.tar.gz
misskey-fa99d9c6fee3a7d6f72e254e0aa55972cd6538fb.tar.bz2
misskey-fa99d9c6fee3a7d6f72e254e0aa55972cd6538fb.zip
Merge branch 'develop' into pizzax-indexeddb
Diffstat (limited to 'packages/client/src/components')
-rw-r--r--packages/client/src/components/abuse-report-window.vue2
-rw-r--r--packages/client/src/components/abuse-report.vue10
-rw-r--r--packages/client/src/components/analog-clock.vue2
-rw-r--r--packages/client/src/components/channel-follow-button.vue4
-rw-r--r--packages/client/src/components/chart.vue1540
-rw-r--r--packages/client/src/components/cw-button.vue2
-rw-r--r--packages/client/src/components/dialog.vue16
-rw-r--r--packages/client/src/components/drive-file-thumbnail.vue2
-rw-r--r--packages/client/src/components/drive-select-dialog.vue4
-rw-r--r--packages/client/src/components/drive-window.vue2
-rw-r--r--packages/client/src/components/drive.file.vue26
-rw-r--r--packages/client/src/components/drive.folder.vue18
-rw-r--r--packages/client/src/components/drive.nav-folder.vue42
-rw-r--r--packages/client/src/components/drive.vue82
-rw-r--r--packages/client/src/components/emoji-picker-window.vue4
-rw-r--r--packages/client/src/components/emoji-picker.section.vue2
-rw-r--r--packages/client/src/components/emoji-picker.vue14
-rw-r--r--packages/client/src/components/follow-button.vue6
-rw-r--r--packages/client/src/components/forgot-password.vue4
-rw-r--r--packages/client/src/components/form-dialog.vue2
-rw-r--r--packages/client/src/components/form/range.vue4
-rw-r--r--packages/client/src/components/form/switch.vue2
-rw-r--r--packages/client/src/components/global/avatar.vue2
-rw-r--r--packages/client/src/components/global/emoji.vue2
-rw-r--r--packages/client/src/components/global/header.vue2
-rw-r--r--packages/client/src/components/global/loading.vue52
-rw-r--r--packages/client/src/components/global/misskey-flavored-markdown.vue26
-rw-r--r--packages/client/src/components/global/time.vue2
-rw-r--r--packages/client/src/components/global/url.vue4
-rw-r--r--packages/client/src/components/image-viewer.vue2
-rw-r--r--packages/client/src/components/instance-ticker.vue13
-rw-r--r--packages/client/src/components/link.vue4
-rw-r--r--packages/client/src/components/media-caption.vue16
-rw-r--r--packages/client/src/components/mention.vue42
-rw-r--r--packages/client/src/components/mfm.ts27
-rw-r--r--packages/client/src/components/note-detailed.vue4
-rw-r--r--packages/client/src/components/note.vue2
-rw-r--r--packages/client/src/components/page/page.image.vue28
-rw-r--r--packages/client/src/components/page/page.post.vue10
-rw-r--r--packages/client/src/components/page/page.vue10
-rw-r--r--packages/client/src/components/poll-editor.vue2
-rw-r--r--packages/client/src/components/post-form-attaches.vue4
-rw-r--r--packages/client/src/components/post-form.vue103
-rw-r--r--packages/client/src/components/reactions-viewer.reaction.vue12
-rw-r--r--packages/client/src/components/signin-dialog.vue16
-rw-r--r--packages/client/src/components/signin.vue359
-rw-r--r--packages/client/src/components/signup-dialog.vue4
-rw-r--r--packages/client/src/components/signup.vue28
-rw-r--r--packages/client/src/components/timeline.vue6
-rw-r--r--packages/client/src/components/toast.vue2
-rw-r--r--packages/client/src/components/ui/button.vue14
-rw-r--r--packages/client/src/components/ui/context-menu.vue6
-rw-r--r--packages/client/src/components/ui/folder.vue2
-rw-r--r--packages/client/src/components/ui/menu.vue2
-rw-r--r--packages/client/src/components/ui/modal-window.vue8
-rw-r--r--packages/client/src/components/ui/pagination.vue23
-rw-r--r--packages/client/src/components/ui/popup-menu.vue2
-rw-r--r--packages/client/src/components/ui/window.vue54
-rw-r--r--packages/client/src/components/user-preview.vue2
-rw-r--r--packages/client/src/components/user-select-dialog.vue6
-rw-r--r--packages/client/src/components/visibility-picker.vue6
-rw-r--r--packages/client/src/components/waiting-dialog.vue4
-rw-r--r--packages/client/src/components/widgets.vue4
63 files changed, 1390 insertions, 1317 deletions
diff --git a/packages/client/src/components/abuse-report-window.vue b/packages/client/src/components/abuse-report-window.vue
index f2cb369802..5114349620 100644
--- a/packages/client/src/components/abuse-report-window.vue
+++ b/packages/client/src/components/abuse-report-window.vue
@@ -37,7 +37,7 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'closed'): void;
+ (ev: 'closed'): void;
}>();
const window = ref<InstanceType<typeof XWindow>>();
diff --git a/packages/client/src/components/abuse-report.vue b/packages/client/src/components/abuse-report.vue
index b67cef209b..a947406f88 100644
--- a/packages/client/src/components/abuse-report.vue
+++ b/packages/client/src/components/abuse-report.vue
@@ -2,7 +2,7 @@
<div class="bcekxzvu _card _gap">
<div class="_content target">
<MkAvatar class="avatar" :user="report.targetUser" :show-indicator="true"/>
- <MkA class="info" :to="userPage(report.targetUser)" v-user-preview="report.targetUserId">
+ <MkA v-user-preview="report.targetUserId" class="info" :to="userPage(report.targetUser)">
<MkUserName class="name" :user="report.targetUser"/>
<MkAcct class="acct" :user="report.targetUser" style="display: block;"/>
</MkA>
@@ -43,20 +43,20 @@ export default defineComponent({
MkSwitch,
},
- emits: ['resolved'],
-
props: {
report: {
type: Object,
required: true,
}
- }
+ },
+
+ emits: ['resolved'],
data() {
return {
forward: this.report.forwarded,
};
- }
+ },
methods: {
acct,
diff --git a/packages/client/src/components/analog-clock.vue b/packages/client/src/components/analog-clock.vue
index 59b8e97304..18dd1e3f41 100644
--- a/packages/client/src/components/analog-clock.vue
+++ b/packages/client/src/components/analog-clock.vue
@@ -42,7 +42,7 @@
<script lang="ts" setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
-import * as tinycolor from 'tinycolor2';
+import tinycolor from 'tinycolor2';
withDefaults(defineProps<{
thickness: number;
diff --git a/packages/client/src/components/channel-follow-button.vue b/packages/client/src/components/channel-follow-button.vue
index 7bbf5ae663..dff02beec0 100644
--- a/packages/client/src/components/channel-follow-button.vue
+++ b/packages/client/src/components/channel-follow-button.vue
@@ -48,8 +48,8 @@ async function onClick() {
});
isFollowing.value = true;
}
- } catch (e) {
- console.error(e);
+ } catch (err) {
+ console.error(err);
} finally {
wait.value = false;
}
diff --git a/packages/client/src/components/chart.vue b/packages/client/src/components/chart.vue
index cc1aa9c20a..4e9c4e587a 100644
--- a/packages/client/src/components/chart.vue
+++ b/packages/client/src/components/chart.vue
@@ -7,8 +7,13 @@
</div>
</template>
-<script lang="ts">
-import { defineComponent, onMounted, ref, watch, PropType, onUnmounted, shallowRef } from 'vue';
+<script lang="ts" setup>
+/* eslint-disable id-denylist --
+ Chart.js has a `data` attribute in most chart definitions, which triggers the
+ id-denylist violation when setting it. This is causing about 60+ lint issues.
+ As this is part of Chart.js's API it makes sense to disable the check here.
+*/
+import { defineProps, onMounted, ref, watch, PropType, onUnmounted } from 'vue';
import {
Chart,
ArcElement,
@@ -29,11 +34,53 @@ import {
import 'chartjs-adapter-date-fns';
import { enUS } from 'date-fns/locale';
import zoomPlugin from 'chartjs-plugin-zoom';
-import gradient from 'chartjs-plugin-gradient';
+// https://github.com/misskey-dev/misskey/pull/8575#issuecomment-1114242002
+// We can't use gradient because Vite throws a error.
+//import gradient from 'chartjs-plugin-gradient';
import * as os from '@/os';
import { defaultStore } from '@/store';
import MkChartTooltip from '@/components/chart-tooltip.vue';
+const props = defineProps({
+ src: {
+ type: String,
+ required: true,
+ },
+ args: {
+ type: Object,
+ required: false,
+ },
+ limit: {
+ type: Number,
+ required: false,
+ default: 90
+ },
+ span: {
+ type: String as PropType<'hour' | 'day'>,
+ required: true,
+ },
+ detailed: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
+ stacked: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
+ bar: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
+ aspectRatio: {
+ type: Number,
+ required: false,
+ default: null
+ },
+});
+
Chart.register(
ArcElement,
LineElement,
@@ -50,7 +97,7 @@ Chart.register(
SubTitle,
Filler,
zoomPlugin,
- gradient,
+ //gradient,
);
const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b));
@@ -78,826 +125,777 @@ const getColor = (i) => {
return colorSets[i % colorSets.length];
};
-export default defineComponent({
- props: {
- src: {
- type: String,
- required: true,
- },
- args: {
- type: Object,
- required: false,
- },
- limit: {
- type: Number,
- required: false,
- default: 90
- },
- span: {
- type: String as PropType<'hour' | 'day'>,
- required: true,
- },
- detailed: {
- type: Boolean,
- required: false,
- default: false
- },
- stacked: {
- type: Boolean,
- required: false,
- default: false
- },
- bar: {
- type: Boolean,
- required: false,
- default: false
- },
- aspectRatio: {
- type: Number,
- required: false,
- default: null
- },
- },
+const now = new Date();
+let chartInstance: Chart = null;
+let chartData: {
+ series: {
+ name: string;
+ type: 'line' | 'area';
+ color?: string;
+ dashed?: boolean;
+ hidden?: boolean;
+ data: {
+ x: number;
+ y: number;
+ }[];
+ }[];
+} = null;
- setup(props) {
- const now = new Date();
- let chartInstance: Chart = null;
- let data: {
- series: {
- name: string;
- type: 'line' | 'area';
- color?: string;
- dashed?: boolean;
- hidden?: boolean;
- data: {
- x: number;
- y: number;
- }[];
- }[];
- } = null;
+const chartEl = ref<HTMLCanvasElement>(null);
+const fetching = ref(true);
- const chartEl = ref<HTMLCanvasElement>(null);
- const fetching = ref(true);
+const getDate = (ago: number) => {
+ const y = now.getFullYear();
+ const m = now.getMonth();
+ const d = now.getDate();
+ const h = now.getHours();
- const getDate = (ago: number) => {
- const y = now.getFullYear();
- const m = now.getMonth();
- const d = now.getDate();
- const h = now.getHours();
-
- return props.span === 'day' ? new Date(y, m, d - ago) : new Date(y, m, d, h - ago);
- };
+ return props.span === 'day' ? new Date(y, m, d - ago) : new Date(y, m, d, h - ago);
+};
- const format = (arr) => {
- return arr.map((v, i) => ({
- x: getDate(i).getTime(),
- y: v
- }));
- };
+const format = (arr) => {
+ return arr.map((v, i) => ({
+ x: getDate(i).getTime(),
+ y: v
+ }));
+};
- const tooltipShowing = ref(false);
- const tooltipX = ref(0);
- const tooltipY = ref(0);
- const tooltipTitle = ref(null);
- const tooltipSeries = ref(null);
- let disposeTooltipComponent;
+const tooltipShowing = ref(false);
+const tooltipX = ref(0);
+const tooltipY = ref(0);
+const tooltipTitle = ref(null);
+const tooltipSeries = ref(null);
+let disposeTooltipComponent;
- os.popup(MkChartTooltip, {
- showing: tooltipShowing,
- x: tooltipX,
- y: tooltipY,
- title: tooltipTitle,
- series: tooltipSeries,
- }, {}).then(({ dispose }) => {
- disposeTooltipComponent = dispose;
- });
+os.popup(MkChartTooltip, {
+ showing: tooltipShowing,
+ x: tooltipX,
+ y: tooltipY,
+ title: tooltipTitle,
+ series: tooltipSeries,
+}, {}).then(({ dispose }) => {
+ disposeTooltipComponent = dispose;
+});
- function externalTooltipHandler(context) {
- if (context.tooltip.opacity === 0) {
- tooltipShowing.value = false;
- return;
- }
+function externalTooltipHandler(context) {
+ if (context.tooltip.opacity === 0) {
+ tooltipShowing.value = false;
+ return;
+ }
- tooltipTitle.value = context.tooltip.title[0];
- tooltipSeries.value = context.tooltip.body.map((b, i) => ({
- backgroundColor: context.tooltip.labelColors[i].backgroundColor,
- borderColor: context.tooltip.labelColors[i].borderColor,
- text: b.lines[0],
- }));
+ tooltipTitle.value = context.tooltip.title[0];
+ tooltipSeries.value = context.tooltip.body.map((b, i) => ({
+ backgroundColor: context.tooltip.labelColors[i].backgroundColor,
+ borderColor: context.tooltip.labelColors[i].borderColor,
+ text: b.lines[0],
+ }));
- const rect = context.chart.canvas.getBoundingClientRect();
+ const rect = context.chart.canvas.getBoundingClientRect();
- tooltipShowing.value = true;
- tooltipX.value = rect.left + window.pageXOffset + context.tooltip.caretX;
- tooltipY.value = rect.top + window.pageYOffset + context.tooltip.caretY;
- }
+ tooltipShowing.value = true;
+ tooltipX.value = rect.left + window.pageXOffset + context.tooltip.caretX;
+ tooltipY.value = rect.top + window.pageYOffset + context.tooltip.caretY;
+}
- const render = () => {
- if (chartInstance) {
- chartInstance.destroy();
- }
+const render = () => {
+ if (chartInstance) {
+ chartInstance.destroy();
+ }
- const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
- const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
+ const gridColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)';
+ const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
- // フォントカラー
- Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
+ // フォントカラー
+ Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--fg');
- const maxes = data.series.map((x, i) => Math.max(...x.data.map(d => d.y)));
+ const maxes = chartData.series.map((x, i) => Math.max(...x.data.map(d => d.y)));
- chartInstance = new Chart(chartEl.value, {
- type: props.bar ? 'bar' : 'line',
- data: {
- labels: new Array(props.limit).fill(0).map((_, i) => getDate(i).toLocaleString()).slice().reverse(),
- datasets: data.series.map((x, i) => ({
- parsing: false,
- label: x.name,
- data: x.data.slice().reverse(),
- tension: 0.3,
- pointRadius: 0,
- borderWidth: props.bar ? 0 : 2,
- borderColor: x.color ? x.color : getColor(i),
- borderDash: x.dashed ? [5, 5] : [],
- borderJoinStyle: 'round',
- borderRadius: props.bar ? 3 : undefined,
- backgroundColor: props.bar ? (x.color ? x.color : getColor(i)) : alpha(x.color ? x.color : getColor(i), 0.1),
- gradient: props.bar ? undefined : {
- backgroundColor: {
- axis: 'y',
- colors: {
- 0: alpha(x.color ? x.color : getColor(i), 0),
- [maxes[i]]: alpha(x.color ? x.color : getColor(i), 0.2),
- },
- },
+ chartInstance = new Chart(chartEl.value, {
+ type: props.bar ? 'bar' : 'line',
+ data: {
+ labels: new Array(props.limit).fill(0).map((_, i) => getDate(i).toLocaleString()).slice().reverse(),
+ datasets: chartData.series.map((x, i) => ({
+ parsing: false,
+ label: x.name,
+ data: x.data.slice().reverse(),
+ tension: 0.3,
+ pointRadius: 0,
+ borderWidth: props.bar ? 0 : 2,
+ borderColor: x.color ? x.color : getColor(i),
+ borderDash: x.dashed ? [5, 5] : [],
+ borderJoinStyle: 'round',
+ borderRadius: props.bar ? 3 : undefined,
+ backgroundColor: props.bar ? (x.color ? x.color : getColor(i)) : alpha(x.color ? x.color : getColor(i), 0.1),
+ /*gradient: props.bar ? undefined : {
+ backgroundColor: {
+ axis: 'y',
+ colors: {
+ 0: alpha(x.color ? x.color : getColor(i), 0),
+ [maxes[i]]: alpha(x.color ? x.color : getColor(i), 0.2),
},
- barPercentage: 0.9,
- categoryPercentage: 0.9,
- fill: x.type === 'area',
- clip: 8,
- hidden: !!x.hidden,
- })),
+ },
+ },*/
+ barPercentage: 0.9,
+ categoryPercentage: 0.9,
+ fill: x.type === 'area',
+ clip: 8,
+ hidden: !!x.hidden,
+ })),
+ },
+ options: {
+ aspectRatio: props.aspectRatio || 2.5,
+ layout: {
+ padding: {
+ left: 0,
+ right: 8,
+ top: 0,
+ bottom: 0,
},
- options: {
- aspectRatio: props.aspectRatio || 2.5,
- layout: {
- padding: {
- left: 0,
- right: 8,
- top: 0,
- bottom: 0,
- },
+ },
+ scales: {
+ x: {
+ type: 'time',
+ stacked: props.stacked,
+ offset: false,
+ time: {
+ stepSize: 1,
+ unit: props.span === 'day' ? 'month' : 'day',
},
- scales: {
- x: {
- type: 'time',
- stacked: props.stacked,
- offset: false,
- time: {
- stepSize: 1,
- unit: props.span === 'day' ? 'month' : 'day',
- },
- grid: {
- color: gridColor,
- borderColor: 'rgb(0, 0, 0, 0)',
- },
- ticks: {
- display: props.detailed,
- maxRotation: 0,
- autoSkipPadding: 16,
- },
- adapters: {
- date: {
- locale: enUS,
- },
- },
- min: getDate(props.limit).getTime(),
- },
- y: {
- position: 'left',
- stacked: props.stacked,
- suggestedMax: 50,
- grid: {
- color: gridColor,
- borderColor: 'rgb(0, 0, 0, 0)',
- },
- ticks: {
- display: props.detailed,
- //mirror: true,
- },
- },
+ grid: {
+ color: gridColor,
+ borderColor: 'rgb(0, 0, 0, 0)',
},
- interaction: {
- intersect: false,
- mode: 'index',
+ ticks: {
+ display: props.detailed,
+ maxRotation: 0,
+ autoSkipPadding: 16,
},
- elements: {
- point: {
- hoverRadius: 5,
- hoverBorderWidth: 2,
+ adapters: {
+ date: {
+ locale: enUS,
},
},
- animation: false,
- plugins: {
- legend: {
- display: props.detailed,
- position: 'bottom',
- labels: {
- boxWidth: 16,
- },
+ min: getDate(props.limit).getTime(),
+ },
+ y: {
+ position: 'left',
+ stacked: props.stacked,
+ suggestedMax: 50,
+ grid: {
+ color: gridColor,
+ borderColor: 'rgb(0, 0, 0, 0)',
+ },
+ ticks: {
+ display: props.detailed,
+ //mirror: true,
+ },
+ },
+ },
+ interaction: {
+ intersect: false,
+ mode: 'index',
+ },
+ elements: {
+ point: {
+ hoverRadius: 5,
+ hoverBorderWidth: 2,
+ },
+ },
+ animation: false,
+ plugins: {
+ legend: {
+ display: props.detailed,
+ position: 'bottom',
+ labels: {
+ boxWidth: 16,
+ },
+ },
+ tooltip: {
+ enabled: false,
+ mode: 'index',
+ animation: {
+ duration: 0,
+ },
+ external: externalTooltipHandler,
+ },
+ zoom: props.detailed ? {
+ pan: {
+ enabled: true,
+ },
+ zoom: {
+ wheel: {
+ enabled: true,
},
- tooltip: {
+ pinch: {
+ enabled: true,
+ },
+ drag: {
enabled: false,
- mode: 'index',
- animation: {
- duration: 0,
- },
- external: externalTooltipHandler,
},
- zoom: props.detailed ? {
- pan: {
- enabled: true,
- },
- zoom: {
- wheel: {
- enabled: true,
- },
- pinch: {
- enabled: true,
- },
- drag: {
- enabled: false,
- },
- mode: 'x',
- },
- limits: {
- x: {
- min: 'original',
- max: 'original',
- },
- y: {
- min: 'original',
- max: 'original',
- },
- }
- } : undefined,
- gradient,
+ mode: 'x',
},
- },
- plugins: [{
- id: 'vLine',
- beforeDraw(chart, args, options) {
- if (chart.tooltip._active && chart.tooltip._active.length) {
- const activePoint = chart.tooltip._active[0];
- const ctx = chart.ctx;
- const x = activePoint.element.x;
- const topY = chart.scales.y.top;
- const bottomY = chart.scales.y.bottom;
-
- ctx.save();
- ctx.beginPath();
- ctx.moveTo(x, bottomY);
- ctx.lineTo(x, topY);
- ctx.lineWidth = 1;
- ctx.strokeStyle = vLineColor;
- ctx.stroke();
- ctx.restore();
- }
+ limits: {
+ x: {
+ min: 'original',
+ max: 'original',
+ },
+ y: {
+ min: 'original',
+ max: 'original',
+ },
}
- }]
- });
- };
+ } : undefined,
+ //gradient,
+ },
+ },
+ plugins: [{
+ id: 'vLine',
+ beforeDraw(chart, args, options) {
+ if (chart.tooltip._active && chart.tooltip._active.length) {
+ const activePoint = chart.tooltip._active[0];
+ const ctx = chart.ctx;
+ const x = activePoint.element.x;
+ const topY = chart.scales.y.top;
+ const bottomY = chart.scales.y.bottom;
- const exportData = () => {
- // TODO
- };
+ ctx.save();
+ ctx.beginPath();
+ ctx.moveTo(x, bottomY);
+ ctx.lineTo(x, topY);
+ ctx.lineWidth = 1;
+ ctx.strokeStyle = vLineColor;
+ ctx.stroke();
+ ctx.restore();
+ }
+ }
+ }]
+ });
+};
- const fetchFederationChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/federation', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Received',
- type: 'area',
- data: format(raw.inboxInstances),
- color: colors.blue,
- }, {
- name: 'Delivered',
- type: 'area',
- data: format(raw.deliveredInstances),
- color: colors.green,
- }, {
- name: 'Stalled',
- type: 'area',
- data: format(raw.stalled),
- color: colors.red,
- }, {
- name: 'Pub Active',
- type: 'line',
- data: format(raw.pubActive),
- color: colors.purple,
- }, {
- name: 'Sub Active',
- type: 'line',
- data: format(raw.subActive),
- color: colors.orange,
- }, {
- name: 'Pub & Sub',
- type: 'line',
- data: format(raw.pubsub),
- dashed: true,
- color: colors.cyan,
- }, {
- name: 'Pub',
- type: 'line',
- data: format(raw.pub),
- dashed: true,
- color: colors.purple,
- }, {
- name: 'Sub',
- type: 'line',
- data: format(raw.sub),
- dashed: true,
- color: colors.orange,
- }],
- };
- };
+const exportData = () => {
+ // TODO
+};
- const fetchApRequestChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/ap-request', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'In',
- type: 'area',
- color: '#008FFB',
- data: format(raw.inboxReceived)
- }, {
- name: 'Out (succ)',
- type: 'area',
- color: '#00E396',
- data: format(raw.deliverSucceeded)
- }, {
- name: 'Out (fail)',
- type: 'area',
- color: '#FEB019',
- data: format(raw.deliverFailed)
- }]
- };
- };
+const fetchFederationChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/federation', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Received',
+ type: 'area',
+ data: format(raw.inboxInstances),
+ color: colors.blue,
+ }, {
+ name: 'Delivered',
+ type: 'area',
+ data: format(raw.deliveredInstances),
+ color: colors.green,
+ }, {
+ name: 'Stalled',
+ type: 'area',
+ data: format(raw.stalled),
+ color: colors.red,
+ }, {
+ name: 'Pub Active',
+ type: 'line',
+ data: format(raw.pubActive),
+ color: colors.purple,
+ }, {
+ name: 'Sub Active',
+ type: 'line',
+ data: format(raw.subActive),
+ color: colors.orange,
+ }, {
+ name: 'Pub & Sub',
+ type: 'line',
+ data: format(raw.pubsub),
+ dashed: true,
+ color: colors.cyan,
+ }, {
+ name: 'Pub',
+ type: 'line',
+ data: format(raw.pub),
+ dashed: true,
+ color: colors.purple,
+ }, {
+ name: 'Sub',
+ type: 'line',
+ data: format(raw.sub),
+ dashed: true,
+ color: colors.orange,
+ }],
+ };
+};
- const fetchNotesChart = async (type: string): Promise<typeof data> => {
- const raw = await os.api('charts/notes', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'All',
- type: 'line',
- data: format(type == 'combined'
- ? sum(raw.local.inc, negate(raw.local.dec), raw.remote.inc, negate(raw.remote.dec))
- : sum(raw[type].inc, negate(raw[type].dec))
- ),
- color: '#888888',
- }, {
- name: 'Renotes',
- type: 'area',
- data: format(type == 'combined'
- ? sum(raw.local.diffs.renote, raw.remote.diffs.renote)
- : raw[type].diffs.renote
- ),
- color: colors.green,
- }, {
- name: 'Replies',
- type: 'area',
- data: format(type == 'combined'
- ? sum(raw.local.diffs.reply, raw.remote.diffs.reply)
- : raw[type].diffs.reply
- ),
- color: colors.yellow,
- }, {
- name: 'Normal',
- type: 'area',
- data: format(type == 'combined'
- ? sum(raw.local.diffs.normal, raw.remote.diffs.normal)
- : raw[type].diffs.normal
- ),
- color: colors.blue,
- }, {
- name: 'With file',
- type: 'area',
- data: format(type == 'combined'
- ? sum(raw.local.diffs.withFile, raw.remote.diffs.withFile)
- : raw[type].diffs.withFile
- ),
- color: colors.purple,
- }],
- };
- };
+const fetchApRequestChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/ap-request', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'In',
+ type: 'area',
+ color: '#008FFB',
+ data: format(raw.inboxReceived)
+ }, {
+ name: 'Out (succ)',
+ type: 'area',
+ color: '#00E396',
+ data: format(raw.deliverSucceeded)
+ }, {
+ name: 'Out (fail)',
+ type: 'area',
+ color: '#FEB019',
+ data: format(raw.deliverFailed)
+ }]
+ };
+};
- const fetchNotesTotalChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/notes', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Combined',
- type: 'line',
- data: format(sum(raw.local.total, raw.remote.total)),
- }, {
- name: 'Local',
- type: 'area',
- data: format(raw.local.total),
- }, {
- name: 'Remote',
- type: 'area',
- data: format(raw.remote.total),
- }],
- };
- };
+const fetchNotesChart = async (type: string): Promise<typeof chartData> => {
+ const raw = await os.api('charts/notes', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'All',
+ type: 'line',
+ data: format(type === 'combined'
+ ? sum(raw.local.inc, negate(raw.local.dec), raw.remote.inc, negate(raw.remote.dec))
+ : sum(raw[type].inc, negate(raw[type].dec))
+ ),
+ color: '#888888',
+ }, {
+ name: 'Renotes',
+ type: 'area',
+ data: format(type === 'combined'
+ ? sum(raw.local.diffs.renote, raw.remote.diffs.renote)
+ : raw[type].diffs.renote
+ ),
+ color: colors.green,
+ }, {
+ name: 'Replies',
+ type: 'area',
+ data: format(type === 'combined'
+ ? sum(raw.local.diffs.reply, raw.remote.diffs.reply)
+ : raw[type].diffs.reply
+ ),
+ color: colors.yellow,
+ }, {
+ name: 'Normal',
+ type: 'area',
+ data: format(type === 'combined'
+ ? sum(raw.local.diffs.normal, raw.remote.diffs.normal)
+ : raw[type].diffs.normal
+ ),
+ color: colors.blue,
+ }, {
+ name: 'With file',
+ type: 'area',
+ data: format(type === 'combined'
+ ? sum(raw.local.diffs.withFile, raw.remote.diffs.withFile)
+ : raw[type].diffs.withFile
+ ),
+ color: colors.purple,
+ }],
+ };
+};
- const fetchUsersChart = async (total: boolean): Promise<typeof data> => {
- const raw = await os.api('charts/users', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Combined',
- type: 'line',
- data: format(total
- ? sum(raw.local.total, raw.remote.total)
- : sum(raw.local.inc, negate(raw.local.dec), raw.remote.inc, negate(raw.remote.dec))
- ),
- }, {
- name: 'Local',
- type: 'area',
- data: format(total
- ? raw.local.total
- : sum(raw.local.inc, negate(raw.local.dec))
- ),
- }, {
- name: 'Remote',
- type: 'area',
- data: format(total
- ? raw.remote.total
- : sum(raw.remote.inc, negate(raw.remote.dec))
- ),
- }],
- };
- };
+const fetchNotesTotalChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/notes', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Combined',
+ type: 'line',
+ data: format(sum(raw.local.total, raw.remote.total)),
+ }, {
+ name: 'Local',
+ type: 'area',
+ data: format(raw.local.total),
+ }, {
+ name: 'Remote',
+ type: 'area',
+ data: format(raw.remote.total),
+ }],
+ };
+};
- const fetchActiveUsersChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/active-users', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Read & Write',
- type: 'area',
- data: format(raw.readWrite),
- color: colors.orange,
- }, {
- name: 'Write',
- type: 'area',
- data: format(raw.write),
- color: colors.lime,
- }, {
- name: 'Read',
- type: 'area',
- data: format(raw.read),
- color: colors.blue,
- }, {
- name: '< Week',
- type: 'area',
- data: format(raw.registeredWithinWeek),
- color: colors.green,
- }, {
- name: '< Month',
- type: 'area',
- data: format(raw.registeredWithinMonth),
- color: colors.yellow,
- }, {
- name: '< Year',
- type: 'area',
- data: format(raw.registeredWithinYear),
- color: colors.red,
- }, {
- name: '> Week',
- type: 'area',
- data: format(raw.registeredOutsideWeek),
- color: colors.yellow,
- }, {
- name: '> Month',
- type: 'area',
- data: format(raw.registeredOutsideMonth),
- color: colors.red,
- }, {
- name: '> Year',
- type: 'area',
- data: format(raw.registeredOutsideYear),
- color: colors.purple,
- }],
- };
- };
+const fetchUsersChart = async (total: boolean): Promise<typeof chartData> => {
+ const raw = await os.api('charts/users', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Combined',
+ type: 'line',
+ data: format(total
+ ? sum(raw.local.total, raw.remote.total)
+ : sum(raw.local.inc, negate(raw.local.dec), raw.remote.inc, negate(raw.remote.dec))
+ ),
+ }, {
+ name: 'Local',
+ type: 'area',
+ data: format(total
+ ? raw.local.total
+ : sum(raw.local.inc, negate(raw.local.dec))
+ ),
+ }, {
+ name: 'Remote',
+ type: 'area',
+ data: format(total
+ ? raw.remote.total
+ : sum(raw.remote.inc, negate(raw.remote.dec))
+ ),
+ }],
+ };
+};
- const fetchDriveChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/drive', { limit: props.limit, span: props.span });
- return {
- bytes: true,
- series: [{
- name: 'All',
- type: 'line',
- dashed: true,
- data: format(
- sum(
- raw.local.incSize,
- negate(raw.local.decSize),
- raw.remote.incSize,
- negate(raw.remote.decSize)
- )
- ),
- }, {
- name: 'Local +',
- type: 'area',
- data: format(raw.local.incSize),
- }, {
- name: 'Local -',
- type: 'area',
- data: format(negate(raw.local.decSize)),
- }, {
- name: 'Remote +',
- type: 'area',
- data: format(raw.remote.incSize),
- }, {
- name: 'Remote -',
- type: 'area',
- data: format(negate(raw.remote.decSize)),
- }],
- };
- };
+const fetchActiveUsersChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/active-users', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Read & Write',
+ type: 'area',
+ data: format(raw.readWrite),
+ color: colors.orange,
+ }, {
+ name: 'Write',
+ type: 'area',
+ data: format(raw.write),
+ color: colors.lime,
+ }, {
+ name: 'Read',
+ type: 'area',
+ data: format(raw.read),
+ color: colors.blue,
+ }, {
+ name: '< Week',
+ type: 'area',
+ data: format(raw.registeredWithinWeek),
+ color: colors.green,
+ }, {
+ name: '< Month',
+ type: 'area',
+ data: format(raw.registeredWithinMonth),
+ color: colors.yellow,
+ }, {
+ name: '< Year',
+ type: 'area',
+ data: format(raw.registeredWithinYear),
+ color: colors.red,
+ }, {
+ name: '> Week',
+ type: 'area',
+ data: format(raw.registeredOutsideWeek),
+ color: colors.yellow,
+ }, {
+ name: '> Month',
+ type: 'area',
+ data: format(raw.registeredOutsideMonth),
+ color: colors.red,
+ }, {
+ name: '> Year',
+ type: 'area',
+ data: format(raw.registeredOutsideYear),
+ color: colors.purple,
+ }],
+ };
+};
- const fetchDriveFilesChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/drive', { limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'All',
- type: 'line',
- dashed: true,
- data: format(
- sum(
- raw.local.incCount,
- negate(raw.local.decCount),
- raw.remote.incCount,
- negate(raw.remote.decCount)
- )
- ),
- }, {
- name: 'Local +',
- type: 'area',
- data: format(raw.local.incCount),
- }, {
- name: 'Local -',
- type: 'area',
- data: format(negate(raw.local.decCount)),
- }, {
- name: 'Remote +',
- type: 'area',
- data: format(raw.remote.incCount),
- }, {
- name: 'Remote -',
- type: 'area',
- data: format(negate(raw.remote.decCount)),
- }],
- };
- };
+const fetchDriveChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/drive', { limit: props.limit, span: props.span });
+ return {
+ bytes: true,
+ series: [{
+ name: 'All',
+ type: 'line',
+ dashed: true,
+ data: format(
+ sum(
+ raw.local.incSize,
+ negate(raw.local.decSize),
+ raw.remote.incSize,
+ negate(raw.remote.decSize)
+ )
+ ),
+ }, {
+ name: 'Local +',
+ type: 'area',
+ data: format(raw.local.incSize),
+ }, {
+ name: 'Local -',
+ type: 'area',
+ data: format(negate(raw.local.decSize)),
+ }, {
+ name: 'Remote +',
+ type: 'area',
+ data: format(raw.remote.incSize),
+ }, {
+ name: 'Remote -',
+ type: 'area',
+ data: format(negate(raw.remote.decSize)),
+ }],
+ };
+};
- const fetchInstanceRequestsChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'In',
- type: 'area',
- color: '#008FFB',
- data: format(raw.requests.received)
- }, {
- name: 'Out (succ)',
- type: 'area',
- color: '#00E396',
- data: format(raw.requests.succeeded)
- }, {
- name: 'Out (fail)',
- type: 'area',
- color: '#FEB019',
- data: format(raw.requests.failed)
- }]
- };
- };
+const fetchDriveFilesChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/drive', { limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'All',
+ type: 'line',
+ dashed: true,
+ data: format(
+ sum(
+ raw.local.incCount,
+ negate(raw.local.decCount),
+ raw.remote.incCount,
+ negate(raw.remote.decCount)
+ )
+ ),
+ }, {
+ name: 'Local +',
+ type: 'area',
+ data: format(raw.local.incCount),
+ }, {
+ name: 'Local -',
+ type: 'area',
+ data: format(negate(raw.local.decCount)),
+ }, {
+ name: 'Remote +',
+ type: 'area',
+ data: format(raw.remote.incCount),
+ }, {
+ name: 'Remote -',
+ type: 'area',
+ data: format(negate(raw.remote.decCount)),
+ }],
+ };
+};
- const fetchInstanceUsersChart = async (total: boolean): Promise<typeof data> => {
- const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Users',
- type: 'area',
- color: '#008FFB',
- data: format(total
- ? raw.users.total
- : sum(raw.users.inc, negate(raw.users.dec))
- )
- }]
- };
- };
+const fetchInstanceRequestsChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'In',
+ type: 'area',
+ color: '#008FFB',
+ data: format(raw.requests.received)
+ }, {
+ name: 'Out (succ)',
+ type: 'area',
+ color: '#00E396',
+ data: format(raw.requests.succeeded)
+ }, {
+ name: 'Out (fail)',
+ type: 'area',
+ color: '#FEB019',
+ data: format(raw.requests.failed)
+ }]
+ };
+};
- const fetchInstanceNotesChart = async (total: boolean): Promise<typeof data> => {
- const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Notes',
- type: 'area',
- color: '#008FFB',
- data: format(total
- ? raw.notes.total
- : sum(raw.notes.inc, negate(raw.notes.dec))
- )
- }]
- };
- };
+const fetchInstanceUsersChart = async (total: boolean): Promise<typeof chartData> => {
+ const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Users',
+ type: 'area',
+ color: '#008FFB',
+ data: format(total
+ ? raw.users.total
+ : sum(raw.users.inc, negate(raw.users.dec))
+ )
+ }]
+ };
+};
- const fetchInstanceFfChart = async (total: boolean): Promise<typeof data> => {
- const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Following',
- type: 'area',
- color: '#008FFB',
- data: format(total
- ? raw.following.total
- : sum(raw.following.inc, negate(raw.following.dec))
- )
- }, {
- name: 'Followers',
- type: 'area',
- color: '#00E396',
- data: format(total
- ? raw.followers.total
- : sum(raw.followers.inc, negate(raw.followers.dec))
- )
- }]
- };
- };
+const fetchInstanceNotesChart = async (total: boolean): Promise<typeof chartData> => {
+ const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Notes',
+ type: 'area',
+ color: '#008FFB',
+ data: format(total
+ ? raw.notes.total
+ : sum(raw.notes.inc, negate(raw.notes.dec))
+ )
+ }]
+ };
+};
- const fetchInstanceDriveUsageChart = async (total: boolean): Promise<typeof data> => {
- const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
- return {
- bytes: true,
- series: [{
- name: 'Drive usage',
- type: 'area',
- color: '#008FFB',
- data: format(total
- ? raw.drive.totalUsage
- : sum(raw.drive.incUsage, negate(raw.drive.decUsage))
- )
- }]
- };
- };
+const fetchInstanceFfChart = async (total: boolean): Promise<typeof chartData> => {
+ const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Following',
+ type: 'area',
+ color: '#008FFB',
+ data: format(total
+ ? raw.following.total
+ : sum(raw.following.inc, negate(raw.following.dec))
+ )
+ }, {
+ name: 'Followers',
+ type: 'area',
+ color: '#00E396',
+ data: format(total
+ ? raw.followers.total
+ : sum(raw.followers.inc, negate(raw.followers.dec))
+ )
+ }]
+ };
+};
- const fetchInstanceDriveFilesChart = async (total: boolean): Promise<typeof data> => {
- const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Drive files',
- type: 'area',
- color: '#008FFB',
- data: format(total
- ? raw.drive.totalFiles
- : sum(raw.drive.incFiles, negate(raw.drive.decFiles))
- )
- }]
- };
- };
+const fetchInstanceDriveUsageChart = async (total: boolean): Promise<typeof chartData> => {
+ const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
+ return {
+ bytes: true,
+ series: [{
+ name: 'Drive usage',
+ type: 'area',
+ color: '#008FFB',
+ data: format(total
+ ? raw.drive.totalUsage
+ : sum(raw.drive.incUsage, negate(raw.drive.decUsage))
+ )
+ }]
+ };
+};
- const fetchPerUserNotesChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span });
- return {
- series: [...(props.args.withoutAll ? [] : [{
- name: 'All',
- type: 'line',
- data: format(sum(raw.inc, negate(raw.dec))),
- color: '#888888',
- }]), {
- name: 'With file',
- type: 'area',
- data: format(raw.diffs.withFile),
- color: colors.purple,
- }, {
- name: 'Renotes',
- type: 'area',
- data: format(raw.diffs.renote),
- color: colors.green,
- }, {
- name: 'Replies',
- type: 'area',
- data: format(raw.diffs.reply),
- color: colors.yellow,
- }, {
- name: 'Normal',
- type: 'area',
- data: format(raw.diffs.normal),
- color: colors.blue,
- }],
- };
- };
+const fetchInstanceDriveFilesChart = async (total: boolean): Promise<typeof chartData> => {
+ const raw = await os.api('charts/instance', { host: props.args.host, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Drive files',
+ type: 'area',
+ color: '#008FFB',
+ data: format(total
+ ? raw.drive.totalFiles
+ : sum(raw.drive.incFiles, negate(raw.drive.decFiles))
+ )
+ }]
+ };
+};
- const fetchPerUserFollowingChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Local',
- type: 'area',
- data: format(raw.local.followings.total),
- }, {
- name: 'Remote',
- type: 'area',
- data: format(raw.remote.followings.total),
- }],
- };
- };
+const fetchPerUserNotesChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span });
+ return {
+ series: [...(props.args.withoutAll ? [] : [{
+ name: 'All',
+ type: 'line',
+ data: format(sum(raw.inc, negate(raw.dec))),
+ color: '#888888',
+ }]), {
+ name: 'With file',
+ type: 'area',
+ data: format(raw.diffs.withFile),
+ color: colors.purple,
+ }, {
+ name: 'Renotes',
+ type: 'area',
+ data: format(raw.diffs.renote),
+ color: colors.green,
+ }, {
+ name: 'Replies',
+ type: 'area',
+ data: format(raw.diffs.reply),
+ color: colors.yellow,
+ }, {
+ name: 'Normal',
+ type: 'area',
+ data: format(raw.diffs.normal),
+ color: colors.blue,
+ }],
+ };
+};
- const fetchPerUserFollowersChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Local',
- type: 'area',
- data: format(raw.local.followers.total),
- }, {
- name: 'Remote',
- type: 'area',
- data: format(raw.remote.followers.total),
- }],
- };
- };
+const fetchPerUserFollowingChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Local',
+ type: 'area',
+ data: format(raw.local.followings.total),
+ }, {
+ name: 'Remote',
+ type: 'area',
+ data: format(raw.remote.followings.total),
+ }],
+ };
+};
- const fetchPerUserDriveChart = async (): Promise<typeof data> => {
- const raw = await os.api('charts/user/drive', { userId: props.args.user.id, limit: props.limit, span: props.span });
- return {
- series: [{
- name: 'Inc',
- type: 'area',
- data: format(raw.incSize),
- }, {
- name: 'Dec',
- type: 'area',
- data: format(raw.decSize),
- }],
- };
- };
+const fetchPerUserFollowersChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/user/following', { userId: props.args.user.id, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Local',
+ type: 'area',
+ data: format(raw.local.followers.total),
+ }, {
+ name: 'Remote',
+ type: 'area',
+ data: format(raw.remote.followers.total),
+ }],
+ };
+};
- const fetchAndRender = async () => {
- const fetchData = () => {
- switch (props.src) {
- case 'federation': return fetchFederationChart();
- case 'ap-request': return fetchApRequestChart();
- case 'users': return fetchUsersChart(false);
- case 'users-total': return fetchUsersChart(true);
- case 'active-users': return fetchActiveUsersChart();
- case 'notes': return fetchNotesChart('combined');
- case 'local-notes': return fetchNotesChart('local');
- case 'remote-notes': return fetchNotesChart('remote');
- case 'notes-total': return fetchNotesTotalChart();
- case 'drive': return fetchDriveChart();
- case 'drive-files': return fetchDriveFilesChart();
-
- case 'instance-requests': return fetchInstanceRequestsChart();
- case 'instance-users': return fetchInstanceUsersChart(false);
- case 'instance-users-total': return fetchInstanceUsersChart(true);
- case 'instance-notes': return fetchInstanceNotesChart(false);
- case 'instance-notes-total': return fetchInstanceNotesChart(true);
- case 'instance-ff': return fetchInstanceFfChart(false);
- case 'instance-ff-total': return fetchInstanceFfChart(true);
- case 'instance-drive-usage': return fetchInstanceDriveUsageChart(false);
- case 'instance-drive-usage-total': return fetchInstanceDriveUsageChart(true);
- case 'instance-drive-files': return fetchInstanceDriveFilesChart(false);
- case 'instance-drive-files-total': return fetchInstanceDriveFilesChart(true);
+const fetchPerUserDriveChart = async (): Promise<typeof chartData> => {
+ const raw = await os.api('charts/user/drive', { userId: props.args.user.id, limit: props.limit, span: props.span });
+ return {
+ series: [{
+ name: 'Inc',
+ type: 'area',
+ data: format(raw.incSize),
+ }, {
+ name: 'Dec',
+ type: 'area',
+ data: format(raw.decSize),
+ }],
+ };
+};
- case 'per-user-notes': return fetchPerUserNotesChart();
- case 'per-user-following': return fetchPerUserFollowingChart();
- case 'per-user-followers': return fetchPerUserFollowersChart();
- case 'per-user-drive': return fetchPerUserDriveChart();
- }
- };
- fetching.value = true;
- data = await fetchData();
- fetching.value = false;
- render();
- };
+const fetchAndRender = async () => {
+ const fetchData = () => {
+ switch (props.src) {
+ case 'federation': return fetchFederationChart();
+ case 'ap-request': return fetchApRequestChart();
+ case 'users': return fetchUsersChart(false);
+ case 'users-total': return fetchUsersChart(true);
+ case 'active-users': return fetchActiveUsersChart();
+ case 'notes': return fetchNotesChart('combined');
+ case 'local-notes': return fetchNotesChart('local');
+ case 'remote-notes': return fetchNotesChart('remote');
+ case 'notes-total': return fetchNotesTotalChart();
+ case 'drive': return fetchDriveChart();
+ case 'drive-files': return fetchDriveFilesChart();
+ case 'instance-requests': return fetchInstanceRequestsChart();
+ case 'instance-users': return fetchInstanceUsersChart(false);
+ case 'instance-users-total': return fetchInstanceUsersChart(true);
+ case 'instance-notes': return fetchInstanceNotesChart(false);
+ case 'instance-notes-total': return fetchInstanceNotesChart(true);
+ case 'instance-ff': return fetchInstanceFfChart(false);
+ case 'instance-ff-total': return fetchInstanceFfChart(true);
+ case 'instance-drive-usage': return fetchInstanceDriveUsageChart(false);
+ case 'instance-drive-usage-total': return fetchInstanceDriveUsageChart(true);
+ case 'instance-drive-files': return fetchInstanceDriveFilesChart(false);
+ case 'instance-drive-files-total': return fetchInstanceDriveFilesChart(true);
- watch(() => [props.src, props.span], fetchAndRender);
+ case 'per-user-notes': return fetchPerUserNotesChart();
+ case 'per-user-following': return fetchPerUserFollowingChart();
+ case 'per-user-followers': return fetchPerUserFollowersChart();
+ case 'per-user-drive': return fetchPerUserDriveChart();
+ }
+ };
+ fetching.value = true;
+ chartData = await fetchData();
+ fetching.value = false;
+ render();
+};
- onMounted(() => {
- fetchAndRender();
- });
+watch(() => [props.src, props.span], fetchAndRender);
- onUnmounted(() => {
- if (disposeTooltipComponent) disposeTooltipComponent();
- });
+onMounted(() => {
+ fetchAndRender();
+});
- return {
- chartEl,
- fetching,
- };
- },
+onUnmounted(() => {
+ if (disposeTooltipComponent) disposeTooltipComponent();
});
+/* eslint-enable id-denylist */
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/cw-button.vue b/packages/client/src/components/cw-button.vue
index e7c9aabe4e..dd906f9bf3 100644
--- a/packages/client/src/components/cw-button.vue
+++ b/packages/client/src/components/cw-button.vue
@@ -18,7 +18,7 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'update:modelValue', v: boolean): void;
+ (ev: 'update:modelValue', v: boolean): void;
}>();
const label = computed(() => {
diff --git a/packages/client/src/components/dialog.vue b/packages/client/src/components/dialog.vue
index 3e106a4f0c..b090f3cb4e 100644
--- a/packages/client/src/components/dialog.vue
+++ b/packages/client/src/components/dialog.vue
@@ -90,8 +90,8 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'done', v: { canceled: boolean; result: any }): void;
- (e: 'closed'): void;
+ (ev: 'done', v: { canceled: boolean; result: any }): void;
+ (ev: 'closed'): void;
}>();
const modal = ref<InstanceType<typeof MkModal>>();
@@ -122,14 +122,14 @@ function onBgClick() {
if (props.cancelableByBgClick) cancel();
}
*/
-function onKeydown(e: KeyboardEvent) {
- if (e.key === 'Escape') cancel();
+function onKeydown(evt: KeyboardEvent) {
+ if (evt.key === 'Escape') cancel();
}
-function onInputKeydown(e: KeyboardEvent) {
- if (e.key === 'Enter') {
- e.preventDefault();
- e.stopPropagation();
+function onInputKeydown(evt: KeyboardEvent) {
+ if (evt.key === 'Enter') {
+ evt.preventDefault();
+ evt.stopPropagation();
ok();
}
}
diff --git a/packages/client/src/components/drive-file-thumbnail.vue b/packages/client/src/components/drive-file-thumbnail.vue
index 81b80e7e8e..dd24440e82 100644
--- a/packages/client/src/components/drive-file-thumbnail.vue
+++ b/packages/client/src/components/drive-file-thumbnail.vue
@@ -42,7 +42,7 @@ const is = computed(() => {
"application/x-tar",
"application/gzip",
"application/x-7z-compressed"
- ].some(e => e === props.file.type)) return 'archive';
+ ].some(archiveType => archiveType === props.file.type)) return 'archive';
return 'unknown';
});
diff --git a/packages/client/src/components/drive-select-dialog.vue b/packages/client/src/components/drive-select-dialog.vue
index f6c59457d1..03974559d2 100644
--- a/packages/client/src/components/drive-select-dialog.vue
+++ b/packages/client/src/components/drive-select-dialog.vue
@@ -33,8 +33,8 @@ withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'done', r?: Misskey.entities.DriveFile[]): void;
- (e: 'closed'): void;
+ (ev: 'done', r?: Misskey.entities.DriveFile[]): void;
+ (ev: 'closed'): void;
}>();
const dialog = ref<InstanceType<typeof XModalWindow>>();
diff --git a/packages/client/src/components/drive-window.vue b/packages/client/src/components/drive-window.vue
index d08c5fb674..5bbfca83c9 100644
--- a/packages/client/src/components/drive-window.vue
+++ b/packages/client/src/components/drive-window.vue
@@ -24,6 +24,6 @@ defineProps<{
}>();
const emit = defineEmits<{
- (e: 'closed'): void;
+ (ev: 'closed'): void;
}>();
</script>
diff --git a/packages/client/src/components/drive.file.vue b/packages/client/src/components/drive.file.vue
index 262eae0de1..aaf7ca3ca3 100644
--- a/packages/client/src/components/drive.file.vue
+++ b/packages/client/src/components/drive.file.vue
@@ -31,7 +31,7 @@
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, defineAsyncComponent, ref } from 'vue';
import * as Misskey from 'misskey-js';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import MkDriveFileThumbnail from './drive-file-thumbnail.vue';
@@ -50,9 +50,9 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'chosen', r: Misskey.entities.DriveFile): void;
- (e: 'dragstart'): void;
- (e: 'dragend'): void;
+ (ev: 'chosen', r: Misskey.entities.DriveFile): void;
+ (ev: 'dragstart'): void;
+ (ev: 'dragend'): void;
}>();
const isDragging = ref(false);
@@ -99,14 +99,14 @@ function onClick(ev: MouseEvent) {
}
}
-function onContextmenu(e: MouseEvent) {
- os.contextMenu(getMenu(), e);
+function onContextmenu(ev: MouseEvent) {
+ os.contextMenu(getMenu(), ev);
}
-function onDragstart(e: DragEvent) {
- if (e.dataTransfer) {
- e.dataTransfer.effectAllowed = 'move';
- e.dataTransfer.setData(_DATA_TRANSFER_DRIVE_FILE_, JSON.stringify(props.file));
+function onDragstart(ev: DragEvent) {
+ if (ev.dataTransfer) {
+ ev.dataTransfer.effectAllowed = 'move';
+ ev.dataTransfer.setData(_DATA_TRANSFER_DRIVE_FILE_, JSON.stringify(props.file));
}
isDragging.value = true;
@@ -133,11 +133,11 @@ function rename() {
}
function describe() {
- os.popup(import('@/components/media-caption.vue'), {
+ os.popup(defineAsyncComponent(() => import('@/components/media-caption.vue')), {
title: i18n.ts.describeFile,
input: {
placeholder: i18n.ts.inputNewDescription,
- default: props.file.comment !== null ? props.file.comment : '',
+ default: props.file.comment != null ? props.file.comment : '',
},
image: props.file
}, {
@@ -146,7 +146,7 @@ function describe() {
let comment = result.result;
os.api('drive/files/update', {
fileId: props.file.id,
- comment: comment.length == 0 ? null : comment
+ comment: comment.length === 0 ? null : comment
});
}
}, 'closed');
diff --git a/packages/client/src/components/drive.folder.vue b/packages/client/src/components/drive.folder.vue
index 57621bf097..d530f8beff 100644
--- a/packages/client/src/components/drive.folder.vue
+++ b/packages/client/src/components/drive.folder.vue
@@ -27,7 +27,7 @@
</template>
<script lang="ts" setup>
-import { computed, ref } from 'vue';
+import { computed, defineAsyncComponent, ref } from 'vue';
import * as Misskey from 'misskey-js';
import * as os from '@/os';
import { i18n } from '@/i18n';
@@ -84,12 +84,12 @@ function onDragover(ev: DragEvent) {
return;
}
- const isFile = ev.dataTransfer.items[0].kind == 'file';
- const isDriveFile = ev.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FILE_;
- const isDriveFolder = ev.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FOLDER_;
+ const isFile = ev.dataTransfer.items[0].kind === 'file';
+ const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
+ const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
if (isFile || isDriveFile || isDriveFolder) {
- ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move';
+ ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
} else {
ev.dataTransfer.dropEffect = 'none';
}
@@ -118,7 +118,7 @@ function onDrop(ev: DragEvent) {
//#region ドライブのファイル
const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
- if (driveFile != null && driveFile != '') {
+ if (driveFile != null && driveFile !== '') {
const file = JSON.parse(driveFile);
emit('removeFile', file.id);
os.api('drive/files/update', {
@@ -130,11 +130,11 @@ function onDrop(ev: DragEvent) {
//#region ドライブのフォルダ
const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
- if (driveFolder != null && driveFolder != '') {
+ if (driveFolder != null && driveFolder !== '') {
const folder = JSON.parse(driveFolder);
// 移動先が自分自身ならreject
- if (folder.id == props.folder.id) return;
+ if (folder.id === props.folder.id) return;
emit('removeFolder', folder.id);
os.api('drive/folders/update', {
@@ -230,7 +230,7 @@ function onContextmenu(ev: MouseEvent) {
text: i18n.ts.openInWindow,
icon: 'fas fa-window-restore',
action: () => {
- os.popup(import('./drive-window.vue'), {
+ os.popup(defineAsyncComponent(() => import('./drive-window.vue')), {
initialFolder: props.folder
}, {
}, 'closed');
diff --git a/packages/client/src/components/drive.nav-folder.vue b/packages/client/src/components/drive.nav-folder.vue
index 67223267c1..5482703317 100644
--- a/packages/client/src/components/drive.nav-folder.vue
+++ b/packages/client/src/components/drive.nav-folder.vue
@@ -24,10 +24,10 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'move', v?: Misskey.entities.DriveFolder): void;
- (e: 'upload', file: File, folder?: Misskey.entities.DriveFolder | null): void;
- (e: 'removeFile', v: Misskey.entities.DriveFile['id']): void;
- (e: 'removeFolder', v: Misskey.entities.DriveFolder['id']): void;
+ (ev: 'move', v?: Misskey.entities.DriveFolder): void;
+ (ev: 'upload', file: File, folder?: Misskey.entities.DriveFolder | null): void;
+ (ev: 'removeFile', v: Misskey.entities.DriveFile['id']): void;
+ (ev: 'removeFolder', v: Misskey.entities.DriveFolder['id']): void;
}>();
const hover = ref(false);
@@ -45,22 +45,22 @@ function onMouseout() {
hover.value = false;
}
-function onDragover(e: DragEvent) {
- if (!e.dataTransfer) return;
+function onDragover(ev: DragEvent) {
+ if (!ev.dataTransfer) return;
// このフォルダがルートかつカレントディレクトリならドロップ禁止
if (props.folder == null && props.parentFolder == null) {
- e.dataTransfer.dropEffect = 'none';
+ ev.dataTransfer.dropEffect = 'none';
}
- const isFile = e.dataTransfer.items[0].kind == 'file';
- const isDriveFile = e.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FILE_;
- const isDriveFolder = e.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FOLDER_;
+ const isFile = ev.dataTransfer.items[0].kind === 'file';
+ const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
+ const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
if (isFile || isDriveFile || isDriveFolder) {
- e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move';
+ ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
} else {
- e.dataTransfer.dropEffect = 'none';
+ ev.dataTransfer.dropEffect = 'none';
}
return false;
@@ -74,22 +74,22 @@ function onDragleave() {
if (props.folder || props.parentFolder) draghover.value = false;
}
-function onDrop(e: DragEvent) {
+function onDrop(ev: DragEvent) {
draghover.value = false;
- if (!e.dataTransfer) return;
+ if (!ev.dataTransfer) return;
// ファイルだったら
- if (e.dataTransfer.files.length > 0) {
- for (const file of Array.from(e.dataTransfer.files)) {
+ if (ev.dataTransfer.files.length > 0) {
+ for (const file of Array.from(ev.dataTransfer.files)) {
emit('upload', file, props.folder);
}
return;
}
//#region ドライブのファイル
- const driveFile = e.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
- if (driveFile != null && driveFile != '') {
+ const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
+ if (driveFile != null && driveFile !== '') {
const file = JSON.parse(driveFile);
emit('removeFile', file.id);
os.api('drive/files/update', {
@@ -100,11 +100,11 @@ function onDrop(e: DragEvent) {
//#endregion
//#region ドライブのフォルダ
- const driveFolder = e.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
- if (driveFolder != null && driveFolder != '') {
+ const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
+ if (driveFolder != null && driveFolder !== '') {
const folder = JSON.parse(driveFolder);
// 移動先が自分自身ならreject
- if (props.folder && folder.id == props.folder.id) return;
+ if (props.folder && folder.id === props.folder.id) return;
emit('removeFolder', folder.id);
os.api('drive/folders/update', {
folderId: folder.id,
diff --git a/packages/client/src/components/drive.vue b/packages/client/src/components/drive.vue
index 2ec885b00c..42ec3a5995 100644
--- a/packages/client/src/components/drive.vue
+++ b/packages/client/src/components/drive.vue
@@ -110,11 +110,11 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'selected', v: Misskey.entities.DriveFile | Misskey.entities.DriveFolder): void;
- (e: 'change-selection', v: Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[]): void;
- (e: 'move-root'): void;
- (e: 'cd', v: Misskey.entities.DriveFolder | null): void;
- (e: 'open-folder', v: Misskey.entities.DriveFolder): void;
+ (ev: 'selected', v: Misskey.entities.DriveFile | Misskey.entities.DriveFolder): void;
+ (ev: 'change-selection', v: Misskey.entities.DriveFile[] | Misskey.entities.DriveFolder[]): void;
+ (ev: 'move-root'): void;
+ (ev: 'cd', v: Misskey.entities.DriveFolder | null): void;
+ (ev: 'open-folder', v: Misskey.entities.DriveFolder): void;
}>();
const loadMoreFiles = ref<InstanceType<typeof MkButton>>();
@@ -153,7 +153,7 @@ function onStreamDriveFileCreated(file: Misskey.entities.DriveFile) {
function onStreamDriveFileUpdated(file: Misskey.entities.DriveFile) {
const current = folder.value ? folder.value.id : null;
- if (current != file.folderId) {
+ if (current !== file.folderId) {
removeFile(file);
} else {
addFile(file, true);
@@ -170,7 +170,7 @@ function onStreamDriveFolderCreated(createdFolder: Misskey.entities.DriveFolder)
function onStreamDriveFolderUpdated(updatedFolder: Misskey.entities.DriveFolder) {
const current = folder.value ? folder.value.id : null;
- if (current != updatedFolder.parentId) {
+ if (current !== updatedFolder.parentId) {
removeFolder(updatedFolder);
} else {
addFolder(updatedFolder, true);
@@ -181,23 +181,23 @@ function onStreamDriveFolderDeleted(folderId: string) {
removeFolder(folderId);
}
-function onDragover(e: DragEvent): any {
- if (!e.dataTransfer) return;
+function onDragover(ev: DragEvent): any {
+ if (!ev.dataTransfer) return;
// ドラッグ元が自分自身の所有するアイテムだったら
if (isDragSource.value) {
// 自分自身にはドロップさせない
- e.dataTransfer.dropEffect = 'none';
+ ev.dataTransfer.dropEffect = 'none';
return;
}
- const isFile = e.dataTransfer.items[0].kind == 'file';
- const isDriveFile = e.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FILE_;
- const isDriveFolder = e.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FOLDER_;
+ const isFile = ev.dataTransfer.items[0].kind === 'file';
+ const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
+ const isDriveFolder = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;
if (isFile || isDriveFile || isDriveFolder) {
- e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move';
+ ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
} else {
- e.dataTransfer.dropEffect = 'none';
+ ev.dataTransfer.dropEffect = 'none';
}
return false;
@@ -211,24 +211,24 @@ function onDragleave() {
draghover.value = false;
}
-function onDrop(e: DragEvent): any {
+function onDrop(ev: DragEvent): any {
draghover.value = false;
- if (!e.dataTransfer) return;
+ if (!ev.dataTransfer) return;
// ドロップされてきたものがファイルだったら
- if (e.dataTransfer.files.length > 0) {
- for (const file of Array.from(e.dataTransfer.files)) {
+ if (ev.dataTransfer.files.length > 0) {
+ for (const file of Array.from(ev.dataTransfer.files)) {
upload(file, folder.value);
}
return;
}
//#region ドライブのファイル
- const driveFile = e.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
- if (driveFile != null && driveFile != '') {
+ const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
+ if (driveFile != null && driveFile !== '') {
const file = JSON.parse(driveFile);
- if (files.value.some(f => f.id == file.id)) return;
+ if (files.value.some(f => f.id === file.id)) return;
removeFile(file.id);
os.api('drive/files/update', {
fileId: file.id,
@@ -238,13 +238,13 @@ function onDrop(e: DragEvent): any {
//#endregion
//#region ドライブのフォルダ
- const driveFolder = e.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
- if (driveFolder != null && driveFolder != '') {
+ const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
+ if (driveFolder != null && driveFolder !== '') {
const droppedFolder = JSON.parse(driveFolder);
// 移動先が自分自身ならreject
- if (folder.value && droppedFolder.id == folder.value.id) return false;
- if (folders.value.some(f => f.id == droppedFolder.id)) return false;
+ if (folder.value && droppedFolder.id === folder.value.id) return false;
+ if (folders.value.some(f => f.id === droppedFolder.id)) return false;
removeFolder(droppedFolder.id);
os.api('drive/folders/update', {
folderId: droppedFolder.id,
@@ -357,16 +357,16 @@ function onChangeFileInput() {
}
function upload(file: File, folderToUpload?: Misskey.entities.DriveFolder | null) {
- uploadFile(file, (folderToUpload && typeof folderToUpload == 'object') ? folderToUpload.id : null, undefined, keepOriginal.value).then(res => {
+ uploadFile(file, (folderToUpload && typeof folderToUpload === 'object') ? folderToUpload.id : null, undefined, keepOriginal.value).then(res => {
addFile(res, true);
});
}
function chooseFile(file: Misskey.entities.DriveFile) {
- const isAlreadySelected = selectedFiles.value.some(f => f.id == file.id);
+ const isAlreadySelected = selectedFiles.value.some(f => f.id === file.id);
if (props.multiple) {
if (isAlreadySelected) {
- selectedFiles.value = selectedFiles.value.filter(f => f.id != file.id);
+ selectedFiles.value = selectedFiles.value.filter(f => f.id !== file.id);
} else {
selectedFiles.value.push(file);
}
@@ -382,10 +382,10 @@ function chooseFile(file: Misskey.entities.DriveFile) {
}
function chooseFolder(folderToChoose: Misskey.entities.DriveFolder) {
- const isAlreadySelected = selectedFolders.value.some(f => f.id == folderToChoose.id);
+ const isAlreadySelected = selectedFolders.value.some(f => f.id === folderToChoose.id);
if (props.multiple) {
if (isAlreadySelected) {
- selectedFolders.value = selectedFolders.value.filter(f => f.id != folderToChoose.id);
+ selectedFolders.value = selectedFolders.value.filter(f => f.id !== folderToChoose.id);
} else {
selectedFolders.value.push(folderToChoose);
}
@@ -404,7 +404,7 @@ function move(target?: Misskey.entities.DriveFolder) {
if (!target) {
goRoot();
return;
- } else if (typeof target == 'object') {
+ } else if (typeof target === 'object') {
target = target.id;
}
@@ -430,9 +430,9 @@ function move(target?: Misskey.entities.DriveFolder) {
function addFolder(folderToAdd: Misskey.entities.DriveFolder, unshift = false) {
const current = folder.value ? folder.value.id : null;
- if (current != folderToAdd.parentId) return;
+ if (current !== folderToAdd.parentId) return;
- if (folders.value.some(f => f.id == folderToAdd.id)) {
+ if (folders.value.some(f => f.id === folderToAdd.id)) {
const exist = folders.value.map(f => f.id).indexOf(folderToAdd.id);
folders.value[exist] = folderToAdd;
return;
@@ -447,9 +447,9 @@ function addFolder(folderToAdd: Misskey.entities.DriveFolder, unshift = false) {
function addFile(fileToAdd: Misskey.entities.DriveFile, unshift = false) {
const current = folder.value ? folder.value.id : null;
- if (current != fileToAdd.folderId) return;
+ if (current !== fileToAdd.folderId) return;
- if (files.value.some(f => f.id == fileToAdd.id)) {
+ if (files.value.some(f => f.id === fileToAdd.id)) {
const exist = files.value.map(f => f.id).indexOf(fileToAdd.id);
files.value[exist] = fileToAdd;
return;
@@ -464,12 +464,12 @@ function addFile(fileToAdd: Misskey.entities.DriveFile, unshift = false) {
function removeFolder(folderToRemove: Misskey.entities.DriveFolder | string) {
const folderIdToRemove = typeof folderToRemove === 'object' ? folderToRemove.id : folderToRemove;
- folders.value = folders.value.filter(f => f.id != folderIdToRemove);
+ folders.value = folders.value.filter(f => f.id !== folderIdToRemove);
}
function removeFile(file: Misskey.entities.DriveFile | string) {
const fileId = typeof file === 'object' ? file.id : file;
- files.value = files.value.filter(f => f.id != fileId);
+ files.value = files.value.filter(f => f.id !== fileId);
}
function appendFile(file: Misskey.entities.DriveFile) {
@@ -512,7 +512,7 @@ async function fetch() {
folderId: folder.value ? folder.value.id : null,
limit: foldersMax + 1
}).then(fetchedFolders => {
- if (fetchedFolders.length == foldersMax + 1) {
+ if (fetchedFolders.length === foldersMax + 1) {
moreFolders.value = true;
fetchedFolders.pop();
}
@@ -524,7 +524,7 @@ async function fetch() {
type: props.type,
limit: filesMax + 1
}).then(fetchedFiles => {
- if (fetchedFiles.length == filesMax + 1) {
+ if (fetchedFiles.length === filesMax + 1) {
moreFiles.value = true;
fetchedFiles.pop();
}
@@ -551,7 +551,7 @@ function fetchMoreFiles() {
untilId: files.value[files.value.length - 1].id,
limit: max + 1
}).then(files => {
- if (files.length == max + 1) {
+ if (files.length === max + 1) {
moreFiles.value = true;
files.pop();
} else {
diff --git a/packages/client/src/components/emoji-picker-window.vue b/packages/client/src/components/emoji-picker-window.vue
index 4d27fb48ba..610690d701 100644
--- a/packages/client/src/components/emoji-picker-window.vue
+++ b/packages/client/src/components/emoji-picker-window.vue
@@ -25,8 +25,8 @@ withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'chosen', v: any): void;
- (e: 'closed'): void;
+ (ev: 'chosen', v: any): void;
+ (ev: 'closed'): void;
}>();
function chosen(emoji: any) {
diff --git a/packages/client/src/components/emoji-picker.section.vue b/packages/client/src/components/emoji-picker.section.vue
index 1026e894d1..52f7047487 100644
--- a/packages/client/src/components/emoji-picker.section.vue
+++ b/packages/client/src/components/emoji-picker.section.vue
@@ -24,7 +24,7 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'chosen', v: string, ev: MouseEvent): void;
+ (ev: 'chosen', v: string, event: MouseEvent): void;
}>();
const shown = ref(!!props.initialShown);
diff --git a/packages/client/src/components/emoji-picker.vue b/packages/client/src/components/emoji-picker.vue
index 8601ea121c..522f636474 100644
--- a/packages/client/src/components/emoji-picker.vue
+++ b/packages/client/src/components/emoji-picker.vue
@@ -61,7 +61,7 @@
</div>
<div>
<header class="_acrylic">{{ i18n.ts.emoji }}</header>
- <XSection v-for="category in categories" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)" @chosen="chosen">{{ category }}</XSection>
+ <XSection v-for="category in categories" :key="category" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)" @chosen="chosen">{{ category }}</XSection>
</div>
</div>
<div class="tabs">
@@ -97,7 +97,7 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'chosen', v: string): void;
+ (ev: 'chosen', v: string): void;
}>();
const search = ref<HTMLInputElement>();
@@ -138,7 +138,7 @@ watch(q, () => {
const emojis = customEmojis;
const matches = new Set<Misskey.entities.CustomEmoji>();
- const exactMatch = emojis.find(e => e.name === newQ);
+ const exactMatch = emojis.find(emoji => emoji.name === newQ);
if (exactMatch) matches.add(exactMatch);
if (newQ.includes(' ')) { // AND検索
@@ -201,7 +201,7 @@ watch(q, () => {
const emojis = emojilist;
const matches = new Set<UnicodeEmojiDef>();
- const exactMatch = emojis.find(e => e.name === newQ);
+ const exactMatch = emojis.find(emoji => emoji.name === newQ);
if (exactMatch) matches.add(exactMatch);
if (newQ.includes(' ')) { // AND検索
@@ -295,7 +295,7 @@ function chosen(emoji: any, ev?: MouseEvent) {
// 最近使った絵文字更新
if (!pinned.value.includes(key)) {
let recents = defaultStore.state.recentlyUsedEmojis;
- recents = recents.filter((e: any) => e !== key);
+ recents = recents.filter((emoji: any) => emoji !== key);
recents.unshift(key);
defaultStore.set('recentlyUsedEmojis', recents.splice(0, 32));
}
@@ -313,12 +313,12 @@ function done(query?: any): boolean | void {
if (query == null || typeof query !== 'string') return;
const q2 = query.replace(/:/g, '');
- const exactMatchCustom = customEmojis.find(e => e.name === q2);
+ const exactMatchCustom = customEmojis.find(emoji => emoji.name === q2);
if (exactMatchCustom) {
chosen(exactMatchCustom);
return true;
}
- const exactMatchUnicode = emojilist.find(e => e.char === q2 || e.name === q2);
+ const exactMatchUnicode = emojilist.find(emoji => emoji.char === q2 || emoji.name === q2);
if (exactMatchUnicode) {
chosen(exactMatchUnicode);
return true;
diff --git a/packages/client/src/components/follow-button.vue b/packages/client/src/components/follow-button.vue
index 93c9e891c1..b3540bc316 100644
--- a/packages/client/src/components/follow-button.vue
+++ b/packages/client/src/components/follow-button.vue
@@ -58,7 +58,7 @@ if (props.user.isFollowing == null) {
}
function onFollowChange(user: Misskey.entities.UserDetailed) {
- if (user.id == props.user.id) {
+ if (user.id === props.user.id) {
isFollowing.value = user.isFollowing;
hasPendingFollowRequestFromYou.value = user.hasPendingFollowRequestFromYou;
}
@@ -96,8 +96,8 @@ async function onClick() {
hasPendingFollowRequestFromYou.value = true;
}
}
- } catch (e) {
- console.error(e);
+ } catch (err) {
+ console.error(err);
} finally {
wait.value = false;
}
diff --git a/packages/client/src/components/forgot-password.vue b/packages/client/src/components/forgot-password.vue
index 46cbf6bd70..19c1f23c85 100644
--- a/packages/client/src/components/forgot-password.vue
+++ b/packages/client/src/components/forgot-password.vue
@@ -41,8 +41,8 @@ import { instance } from '@/instance';
import { i18n } from '@/i18n';
const emit = defineEmits<{
- (e: 'done'): void;
- (e: 'closed'): void;
+ (ev: 'done'): void;
+ (ev: 'closed'): void;
}>();
let dialog: InstanceType<typeof XModalWindow> = $ref();
diff --git a/packages/client/src/components/form-dialog.vue b/packages/client/src/components/form-dialog.vue
index efd0da443d..11459f5937 100644
--- a/packages/client/src/components/form-dialog.vue
+++ b/packages/client/src/components/form-dialog.vue
@@ -44,7 +44,7 @@
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
</FormRange>
- <MkButton v-else-if="form[item].type === 'button'" @click="form[item].action($event, values)" class="_formBlock">
+ <MkButton v-else-if="form[item].type === 'button'" class="_formBlock" @click="form[item].action($event, values)">
<span v-text="form[item].content || item"></span>
</MkButton>
</template>
diff --git a/packages/client/src/components/form/range.vue b/packages/client/src/components/form/range.vue
index a82348d317..07f2c23124 100644
--- a/packages/client/src/components/form/range.vue
+++ b/packages/client/src/components/form/range.vue
@@ -16,7 +16,7 @@
</template>
<script lang="ts">
-import { computed, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
+import { computed, defineAsyncComponent, defineComponent, onMounted, onUnmounted, ref, watch } from 'vue';
import * as os from '@/os';
export default defineComponent({
@@ -112,7 +112,7 @@ export default defineComponent({
ev.preventDefault();
const tooltipShowing = ref(true);
- os.popup(import('@/components/ui/tooltip.vue'), {
+ os.popup(defineAsyncComponent(() => import('@/components/ui/tooltip.vue')), {
showing: tooltipShowing,
text: computed(() => {
return props.textConverter(finalValue.value);
diff --git a/packages/client/src/components/form/switch.vue b/packages/client/src/components/form/switch.vue
index b5a30d635c..fadb770aee 100644
--- a/packages/client/src/components/form/switch.vue
+++ b/packages/client/src/components/form/switch.vue
@@ -31,7 +31,7 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'update:modelValue', v: boolean): void;
+ (ev: 'update:modelValue', v: boolean): void;
}>();
let button = $ref<HTMLElement>();
diff --git a/packages/client/src/components/global/avatar.vue b/packages/client/src/components/global/avatar.vue
index 27cfb6e4d4..4868896c99 100644
--- a/packages/client/src/components/global/avatar.vue
+++ b/packages/client/src/components/global/avatar.vue
@@ -32,7 +32,7 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'click', ev: MouseEvent): void;
+ (ev: 'click', v: MouseEvent): void;
}>();
const url = $computed(() => defaultStore.state.disableShowingAnimatedImages
diff --git a/packages/client/src/components/global/emoji.vue b/packages/client/src/components/global/emoji.vue
index 92edb1caf9..0075e0867d 100644
--- a/packages/client/src/components/global/emoji.vue
+++ b/packages/client/src/components/global/emoji.vue
@@ -46,7 +46,7 @@ export default defineComponent({
const url = computed(() => {
if (char.value) {
let codes = Array.from(char.value).map(x => x.codePointAt(0).toString(16));
- if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f');
+ if (!codes.includes('200d')) codes = codes.filter(x => x !== 'fe0f');
codes = codes.filter(x => x && x.length);
return `${twemojiSvgBase}/${codes.join('-')}.svg`;
} else {
diff --git a/packages/client/src/components/global/header.vue b/packages/client/src/components/global/header.vue
index e558614c12..63db19a520 100644
--- a/packages/client/src/components/global/header.vue
+++ b/packages/client/src/components/global/header.vue
@@ -38,7 +38,7 @@
<script lang="ts">
import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, inject } from 'vue';
-import * as tinycolor from 'tinycolor2';
+import tinycolor from 'tinycolor2';
import { popupMenu } from '@/os';
import { url } from '@/config';
import { scrollToTop } from '@/scripts/scroll';
diff --git a/packages/client/src/components/global/loading.vue b/packages/client/src/components/global/loading.vue
index 43ea1395ed..fa2ce1800c 100644
--- a/packages/client/src/components/global/loading.vue
+++ b/packages/client/src/components/global/loading.vue
@@ -1,6 +1,17 @@
<template>
<div class="yxspomdl" :class="{ inline, colored, mini }">
- <div class="ring"></div>
+ <div class="container">
+ <svg class="spinner bg" viewBox="0 0 168 168" xmlns="http://www.w3.org/2000/svg">
+ <g transform="matrix(1.125,0,0,1.125,12,12)">
+ <circle cx="64" cy="64" r="64" style="fill:none;stroke:currentColor;stroke-width:21.33px;"/>
+ </g>
+ </svg>
+ <svg class="spinner fg" viewBox="0 0 168 168" xmlns="http://www.w3.org/2000/svg">
+ <g transform="matrix(1.125,0,0,1.125,12,12)">
+ <path d="M128,64C128,28.654 99.346,0 64,0C99.346,0 128,28.654 128,64Z" style="fill:none;stroke:currentColor;stroke-width:21.33px;"/>
+ </g>
+ </svg>
+ </div>
</div>
</template>
@@ -19,7 +30,7 @@ const props = withDefaults(defineProps<{
</script>
<style lang="scss" scoped>
-@keyframes ring {
+@keyframes spinner {
0% {
transform: rotate(0deg);
}
@@ -33,7 +44,7 @@ const props = withDefaults(defineProps<{
text-align: center;
cursor: wait;
- --size: 48px;
+ --size: 40px;
&.colored {
color: var(--accent);
@@ -50,32 +61,31 @@ const props = withDefaults(defineProps<{
--size: 32px;
}
- > .ring {
+ > .container {
position: relative;
- display: inline-block;
- vertical-align: middle;
+ width: var(--size);
+ height: var(--size);
+ margin: 0 auto;
- &:before,
- &:after {
- content: " ";
- display: block;
- box-sizing: border-box;
+ > .spinner {
+ position: absolute;
+ top: 0;
+ left: 0;
width: var(--size);
height: var(--size);
- border-radius: 50%;
- border: solid 4px;
+ fill-rule: evenodd;
+ clip-rule: evenodd;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-miterlimit: 1.5;
}
- &:before {
- border-color: currentColor;
- opacity: 0.3;
+ > .bg {
+ opacity: 0.275;
}
- &:after {
- position: absolute;
- top: 0;
- border-color: currentColor transparent transparent transparent;
- animation: ring 0.5s linear infinite;
+ > .fg {
+ animation: spinner 0.5s linear infinite;
}
}
}
diff --git a/packages/client/src/components/global/misskey-flavored-markdown.vue b/packages/client/src/components/global/misskey-flavored-markdown.vue
index 243d8614ba..70d0108e9f 100644
--- a/packages/client/src/components/global/misskey-flavored-markdown.vue
+++ b/packages/client/src/components/global/misskey-flavored-markdown.vue
@@ -31,6 +31,32 @@ const props = withDefaults(defineProps<{
}
}
+.mfm-x2 {
+ --mfm-zoom-size: 200%;
+}
+
+.mfm-x3 {
+ --mfm-zoom-size: 400%;
+}
+
+.mfm-x4 {
+ --mfm-zoom-size: 600%;
+}
+
+.mfm-x2, .mfm-x3, .mfm-x4 {
+ font-size: var(--mfm-zoom-size);
+
+ .mfm-x2, .mfm-x3, .mfm-x4 {
+ /* only half effective */
+ font-size: calc(var(--mfm-zoom-size) / 2 + 50%);
+
+ .mfm-x2, .mfm-x3, .mfm-x4 {
+ /* disabled */
+ font-size: 100%;
+ }
+ }
+}
+
@keyframes mfm-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
diff --git a/packages/client/src/components/global/time.vue b/packages/client/src/components/global/time.vue
index 5748d9de61..02351deb5f 100644
--- a/packages/client/src/components/global/time.vue
+++ b/packages/client/src/components/global/time.vue
@@ -17,7 +17,7 @@ const props = withDefaults(defineProps<{
mode: 'relative',
});
-const _time = typeof props.time == 'string' ? new Date(props.time) : props.time;
+const _time = typeof props.time === 'string' ? new Date(props.time) : props.time;
const absolute = _time.toLocaleString();
let now = $ref(new Date());
diff --git a/packages/client/src/components/global/url.vue b/packages/client/src/components/global/url.vue
index 55f6c5d5f9..34ba9024cc 100644
--- a/packages/client/src/components/global/url.vue
+++ b/packages/client/src/components/global/url.vue
@@ -18,7 +18,7 @@
</template>
<script lang="ts">
-import { defineComponent, ref } from 'vue';
+import { defineAsyncComponent, defineComponent, ref } from 'vue';
import { toUnicode as decodePunycode } from 'punycode/';
import { url as local } from '@/config';
import * as os from '@/os';
@@ -50,7 +50,7 @@ export default defineComponent({
const el = ref();
useTooltip(el, (showing) => {
- os.popup(import('@/components/url-preview-popup.vue'), {
+ os.popup(defineAsyncComponent(() => import('@/components/url-preview-popup.vue')), {
showing,
url: props.url,
source: el.value,
diff --git a/packages/client/src/components/image-viewer.vue b/packages/client/src/components/image-viewer.vue
index c39076df16..7bc88399ef 100644
--- a/packages/client/src/components/image-viewer.vue
+++ b/packages/client/src/components/image-viewer.vue
@@ -25,7 +25,7 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'closed'): void;
+ (ev: 'closed'): void;
}>();
const modal = $ref<InstanceType<typeof MkModal>>();
diff --git a/packages/client/src/components/instance-ticker.vue b/packages/client/src/components/instance-ticker.vue
index 9b0a18ec90..c32409ecf4 100644
--- a/packages/client/src/components/instance-ticker.vue
+++ b/packages/client/src/components/instance-ticker.vue
@@ -39,6 +39,19 @@ const bg = {
border-radius: 4px 0 0 4px;
overflow: hidden;
color: #fff;
+ text-shadow: /* .866 ≈ sin(60deg) */
+ 1px 0 1px #000,
+ .866px .5px 1px #000,
+ .5px .866px 1px #000,
+ 0 1px 1px #000,
+ -.5px .866px 1px #000,
+ -.866px .5px 1px #000,
+ -1px 0 1px #000,
+ -.866px -.5px 1px #000,
+ -.5px -.866px 1px #000,
+ 0 -1px 1px #000,
+ .5px -.866px 1px #000,
+ .866px -.5px 1px #000;
> .icon {
height: 100%;
diff --git a/packages/client/src/components/link.vue b/packages/client/src/components/link.vue
index 317c931cec..846a9a3a76 100644
--- a/packages/client/src/components/link.vue
+++ b/packages/client/src/components/link.vue
@@ -8,7 +8,7 @@
</template>
<script lang="ts" setup>
-import { } from 'vue';
+import { defineAsyncComponent } from 'vue';
import { url as local } from '@/config';
import { useTooltip } from '@/scripts/use-tooltip';
import * as os from '@/os';
@@ -26,7 +26,7 @@ const target = self ? null : '_blank';
const el = $ref();
useTooltip($$(el), (showing) => {
- os.popup(import('@/components/url-preview-popup.vue'), {
+ os.popup(defineAsyncComponent(() => import('@/components/url-preview-popup.vue')), {
showing,
url: props.url,
source: el,
diff --git a/packages/client/src/components/media-caption.vue b/packages/client/src/components/media-caption.vue
index ef546f3f70..feed3854f9 100644
--- a/packages/client/src/components/media-caption.vue
+++ b/packages/client/src/components/media-caption.vue
@@ -77,7 +77,7 @@ export default defineComponent({
computed: {
remainingLength(): number {
- if (typeof this.inputValue != "string") return 512;
+ if (typeof this.inputValue !== "string") return 512;
return 512 - length(this.inputValue);
}
},
@@ -116,17 +116,17 @@ export default defineComponent({
}
},
- onKeydown(e) {
- if (e.which === 27) { // ESC
+ onKeydown(evt) {
+ if (evt.which === 27) { // ESC
this.cancel();
}
},
- onInputKeydown(e) {
- if (e.which === 13) { // Enter
- if (e.ctrlKey) {
- e.preventDefault();
- e.stopPropagation();
+ onInputKeydown(evt) {
+ if (evt.which === 13) { // Enter
+ if (evt.ctrlKey) {
+ evt.preventDefault();
+ evt.stopPropagation();
this.ok();
}
}
diff --git a/packages/client/src/components/mention.vue b/packages/client/src/components/mention.vue
index 479acfbc8f..70c2f49afa 100644
--- a/packages/client/src/components/mention.vue
+++ b/packages/client/src/components/mention.vue
@@ -1,22 +1,22 @@
<template>
-<MkA v-if="url.startsWith('/')" v-user-preview="canonical" class="ldlomzub" :class="{ isMe }" :to="url" :style="{ background: bg }">
- <img class="icon" :src="`/avatar/@${username}@${host}`" alt="">
+<MkA v-if="url.startsWith('/')" v-user-preview="canonical" :class="[$style.root, { isMe }]" :to="url" :style="{ background: bg }">
+ <img :class="$style.icon" :src="`/avatar/@${username}@${host}`" alt="">
<span class="main">
<span class="username">@{{ username }}</span>
- <span v-if="(host != localHost) || $store.state.showFullAcct" class="host">@{{ toUnicode(host) }}</span>
+ <span v-if="(host != localHost) || $store.state.showFullAcct" :class="$style.mainHost">@{{ toUnicode(host) }}</span>
</span>
</MkA>
-<a v-else class="ldlomzub" :href="url" target="_blank" rel="noopener" :style="{ background: bg }">
+<a v-else :class="$style.root" :href="url" target="_blank" rel="noopener" :style="{ background: bg }">
<span class="main">
<span class="username">@{{ username }}</span>
- <span class="host">@{{ toUnicode(host) }}</span>
+ <span :class="$style.mainHost">@{{ toUnicode(host) }}</span>
</span>
</a>
</template>
<script lang="ts">
-import { defineComponent } from 'vue';
-import * as tinycolor from 'tinycolor2';
+import { defineComponent, useCssModule } from 'vue';
+import tinycolor from 'tinycolor2';
import { toUnicode } from 'punycode';
import { host as localHost } from '@/config';
import { $i } from '@/account';
@@ -45,6 +45,8 @@ export default defineComponent({
const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention'));
bg.setAlpha(0.1);
+ useCssModule();
+
return {
localHost,
isMe,
@@ -57,8 +59,8 @@ export default defineComponent({
});
</script>
-<style lang="scss" scoped>
-.ldlomzub {
+<style lang="scss" module>
+.root {
display: inline-block;
padding: 4px 8px 4px 4px;
border-radius: 999px;
@@ -67,18 +69,18 @@ export default defineComponent({
&.isMe {
color: var(--mentionMe);
}
+}
- > .icon {
- width: 1.5em;
- margin: 0 0.2em 0 0;
- vertical-align: bottom;
- border-radius: 100%;
- }
+.icon {
+ width: 1.5em;
+ height: 1.5em;
+ object-fit: cover;
+ margin: 0 0.2em 0 0;
+ vertical-align: bottom;
+ border-radius: 100%;
+}
- > .main {
- > .host {
- opacity: 0.5;
- }
- }
+.mainHost {
+ opacity: 0.5;
}
</style>
diff --git a/packages/client/src/components/mfm.ts b/packages/client/src/components/mfm.ts
index 37076652fd..4556a82d55 100644
--- a/packages/client/src/components/mfm.ts
+++ b/packages/client/src/components/mfm.ts
@@ -91,7 +91,8 @@ export default defineComponent({
let style;
switch (token.props.name) {
case 'tada': {
- style = `font-size: 150%;` + (this.$store.state.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
+ const speed = validTime(token.props.args.speed) || '1s';
+ style = 'font-size: 150%;' + (this.$store.state.animatedMfm ? `animation: tada ${speed} linear infinite both;` : '');
break;
}
case 'jelly': {
@@ -123,11 +124,13 @@ export default defineComponent({
break;
}
case 'jump': {
- style = this.$store.state.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
+ const speed = validTime(token.props.args.speed) || '0.75s';
+ style = this.$store.state.animatedMfm ? `animation: mfm-jump ${speed} linear infinite;` : '';
break;
}
case 'bounce': {
- style = this.$store.state.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : '';
+ const speed = validTime(token.props.args.speed) || '0.75s';
+ style = this.$store.state.animatedMfm ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : '';
break;
}
case 'flip': {
@@ -139,16 +142,19 @@ export default defineComponent({
break;
}
case 'x2': {
- style = `font-size: 200%;`;
- break;
+ return h('span', {
+ class: 'mfm-x2',
+ }, genEl(token.children));
}
case 'x3': {
- style = `font-size: 400%;`;
- break;
+ return h('span', {
+ class: 'mfm-x3',
+ }, genEl(token.children));
}
case 'x4': {
- style = `font-size: 600%;`;
- break;
+ return h('span', {
+ class: 'mfm-x4',
+ }, genEl(token.children));
}
case 'font': {
const family =
@@ -168,7 +174,8 @@ export default defineComponent({
}, genEl(token.children));
}
case 'rainbow': {
- style = this.$store.state.animatedMfm ? 'animation: mfm-rainbow 1s linear infinite;' : '';
+ const speed = validTime(token.props.args.speed) || '1s';
+ style = this.$store.state.animatedMfm ? `animation: mfm-rainbow ${speed} linear infinite;` : '';
break;
}
case 'sparkle': {
diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue
index d30284ca5f..14bbbd4f3c 100644
--- a/packages/client/src/components/note-detailed.vue
+++ b/packages/client/src/components/note-detailed.vue
@@ -2,9 +2,9 @@
<div
v-if="!muted"
v-show="!isDeleted"
+ ref="el"
v-hotkey="keymap"
v-size="{ max: [500, 450, 350, 300] }"
- ref="el"
class="lxwezrsl _block"
:tabindex="!isDeleted ? '-1' : null"
:class="{ renote: isRenote }"
@@ -197,7 +197,7 @@ const keymap = {
'q': () => renoteButton.value.renote(true),
'esc': blur,
'm|o': () => menu(true),
- 's': () => showContent.value != showContent.value,
+ 's': () => showContent.value !== showContent.value,
};
useNoteCapture({
diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue
index 3cd7a819d4..bc8a0dd19d 100644
--- a/packages/client/src/components/note.vue
+++ b/packages/client/src/components/note.vue
@@ -185,7 +185,7 @@ const keymap = {
'down|j|tab': focusAfter,
'esc': blur,
'm|o': () => menu(true),
- 's': () => showContent.value != showContent.value,
+ 's': () => showContent.value !== showContent.value,
};
useNoteCapture({
diff --git a/packages/client/src/components/page/page.image.vue b/packages/client/src/components/page/page.image.vue
index 04ce74bd7c..6e38a9f424 100644
--- a/packages/client/src/components/page/page.image.vue
+++ b/packages/client/src/components/page/page.image.vue
@@ -1,34 +1,22 @@
<template>
<div class="lzyxtsnt">
- <img v-if="image" :src="image.url"/>
+ <ImgWithBlurhash v-if="image" :hash="image.blurhash" :src="image.url" :alt="image.comment" :title="image.comment" :cover="false"/>
</div>
</template>
-<script lang="ts">
+<script lang="ts" setup>
import { defineComponent, PropType } from 'vue';
+import ImgWithBlurhash from '@/components/img-with-blurhash.vue';
import * as os from '@/os';
import { ImageBlock } from '@/scripts/hpml/block';
import { Hpml } from '@/scripts/hpml/evaluator';
-export default defineComponent({
- props: {
- block: {
- type: Object as PropType<ImageBlock>,
- required: true
- },
- hpml: {
- type: Object as PropType<Hpml>,
- required: true
- }
- },
- setup(props, ctx) {
- const image = props.hpml.page.attachedFiles.find(x => x.id === props.block.fileId);
+const props = defineProps<{
+ block: PropType<ImageBlock>,
+ hpml: PropType<Hpml>,
+}>();
- return {
- image
- };
- }
-});
+const image = props.hpml.page.attachedFiles.find(x => x.id === props.block.fileId);
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/page/page.post.vue b/packages/client/src/components/page/page.post.vue
index 847da37c51..8ac8c46692 100644
--- a/packages/client/src/components/page/page.post.vue
+++ b/packages/client/src/components/page/page.post.vue
@@ -52,16 +52,16 @@ export default defineComponent({
const promise = new Promise((ok) => {
const canvas = this.hpml.canvases[this.block.canvasId];
canvas.toBlob(blob => {
- const data = new FormData();
- data.append('file', blob);
- data.append('i', this.$i.token);
+ const formData = new FormData();
+ formData.append('file', blob);
+ formData.append('i', this.$i.token);
if (this.$store.state.uploadFolder) {
- data.append('folderId', this.$store.state.uploadFolder);
+ formData.append('folderId', this.$store.state.uploadFolder);
}
fetch(apiUrl + '/drive/files/create', {
method: 'POST',
- body: data
+ body: formData,
})
.then(response => response.json())
.then(f => {
diff --git a/packages/client/src/components/page/page.vue b/packages/client/src/components/page/page.vue
index e54147bbd0..a067762372 100644
--- a/packages/client/src/components/page/page.vue
+++ b/packages/client/src/components/page/page.vue
@@ -38,8 +38,8 @@ export default defineComponent({
let ast;
try {
ast = parse(props.page.script);
- } catch (e) {
- console.error(e);
+ } catch (err) {
+ console.error(err);
/*os.alert({
type: 'error',
text: 'Syntax error :('
@@ -48,11 +48,11 @@ export default defineComponent({
}
hpml.aiscript.exec(ast).then(() => {
hpml.eval();
- }).catch(e => {
- console.error(e);
+ }).catch(err => {
+ console.error(err);
/*os.alert({
type: 'error',
- text: e
+ text: err
});*/
});
} else {
diff --git a/packages/client/src/components/poll-editor.vue b/packages/client/src/components/poll-editor.vue
index 6f3f23a2d3..9aa5510c7f 100644
--- a/packages/client/src/components/poll-editor.vue
+++ b/packages/client/src/components/poll-editor.vue
@@ -104,7 +104,7 @@ function add() {
}
function remove(i) {
- choices.value = choices.value.filter((_, _i) => _i != i);
+ choices.value = choices.value.filter((_, _i) => _i !== i);
}
function get() {
diff --git a/packages/client/src/components/post-form-attaches.vue b/packages/client/src/components/post-form-attaches.vue
index 9dd69a0ee5..3807769118 100644
--- a/packages/client/src/components/post-form-attaches.vue
+++ b/packages/client/src/components/post-form-attaches.vue
@@ -88,7 +88,7 @@ export default defineComponent({
},
async describe(file) {
- os.popup(import("@/components/media-caption.vue"), {
+ os.popup(defineAsyncComponent(() => import("@/components/media-caption.vue")), {
title: this.$ts.describeFile,
input: {
placeholder: this.$ts.inputNewDescription,
@@ -98,7 +98,7 @@ export default defineComponent({
}, {
done: result => {
if (!result || result.canceled) return;
- let comment = result.result.length == 0 ? null : result.result;
+ let comment = result.result.length === 0 ? null : result.result;
os.api('drive/files/update', {
fileId: file.id,
comment: comment,
diff --git a/packages/client/src/components/post-form.vue b/packages/client/src/components/post-form.vue
index 241c726c11..64ee873fd7 100644
--- a/packages/client/src/components/post-form.vue
+++ b/packages/client/src/components/post-form.vue
@@ -62,7 +62,7 @@
</template>
<script lang="ts" setup>
-import { inject, watch, nextTick, onMounted } from 'vue';
+import { inject, watch, nextTick, onMounted, defineAsyncComponent } from 'vue';
import * as mfm from 'mfm-js';
import * as misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor';
@@ -107,7 +107,7 @@ const props = withDefaults(defineProps<{
fixed?: boolean;
autofocus?: boolean;
}>(), {
- initialVisibleUsers: [],
+ initialVisibleUsers: () => [],
autofocus: true,
});
@@ -228,7 +228,7 @@ if (props.mention) {
text += ' ';
}
-if (props.reply && (props.reply.user.username != $i.username || (props.reply.user.host != null && props.reply.user.host != host))) {
+if (props.reply && (props.reply.user.username !== $i.username || (props.reply.user.host != null && props.reply.user.host !== host))) {
text = `@${props.reply.user.username}${props.reply.user.host != null ? '@' + toASCII(props.reply.user.host) : ''} `;
}
@@ -239,16 +239,15 @@ if (props.reply && props.reply.text != null) {
for (const x of extractMentions(ast)) {
const mention = x.host ?
`@${x.username}@${toASCII(x.host)}` :
- (otherHost == null || otherHost == host) ?
+ (otherHost == null || otherHost === host) ?
`@${x.username}` :
`@${x.username}@${toASCII(otherHost)}`;
// 自分は除外
- if ($i.username == x.username && x.host == null) continue;
- if ($i.username == x.username && x.host == host) continue;
+ if ($i.username === x.username && (x.host == null || x.host === host)) continue;
// 重複は除外
- if (text.indexOf(`${mention} `) != -1) continue;
+ if (text.includes(`${mention} `)) continue;
text += `${mention} `;
}
@@ -303,7 +302,7 @@ function checkMissingMention() {
const ast = mfm.parse(text);
for (const x of extractMentions(ast)) {
- if (!visibleUsers.some(u => (u.username === x.username) && (u.host == x.host))) {
+ if (!visibleUsers.some(u => (u.username === x.username) && (u.host === x.host))) {
hasNotSpecifiedMentions = true;
return;
}
@@ -316,7 +315,7 @@ function addMissingMention() {
const ast = mfm.parse(text);
for (const x of extractMentions(ast)) {
- if (!visibleUsers.some(u => (u.username === x.username) && (u.host == x.host))) {
+ if (!visibleUsers.some(u => (u.username === x.username) && (u.host === x.host))) {
os.api('users/show', { username: x.username, host: x.host }).then(user => {
visibleUsers.push(user);
});
@@ -357,7 +356,7 @@ function chooseFileFrom(ev) {
}
function detachFile(id) {
- files = files.filter(x => x.id != id);
+ files = files.filter(x => x.id !== id);
}
function updateFiles(_files) {
@@ -384,7 +383,7 @@ function setVisibility() {
return;
}
- os.popup(import('./visibility-picker.vue'), {
+ os.popup(defineAsyncComponent(() => import('./visibility-picker.vue')), {
currentVisibility: visibility,
currentLocalOnly: localOnly,
src: visibilityButton,
@@ -427,24 +426,24 @@ function clear() {
quoteId = null;
}
-function onKeydown(e: KeyboardEvent) {
- if ((e.which === 10 || e.which === 13) && (e.ctrlKey || e.metaKey) && canPost) post();
- if (e.which === 27) emit('esc');
+function onKeydown(ev: KeyboardEvent) {
+ if ((ev.which === 10 || ev.which === 13) && (ev.ctrlKey || ev.metaKey) && canPost) post();
+ if (ev.which === 27) emit('esc');
typing();
}
-function onCompositionUpdate(e: CompositionEvent) {
- imeText = e.data;
+function onCompositionUpdate(ev: CompositionEvent) {
+ imeText = ev.data;
typing();
}
-function onCompositionEnd(e: CompositionEvent) {
+function onCompositionEnd(ev: CompositionEvent) {
imeText = '';
}
-async function onPaste(e: ClipboardEvent) {
- for (const { item, i } of Array.from(e.clipboardData.items).map((item, i) => ({item, i}))) {
- if (item.kind == 'file') {
+async function onPaste(ev: ClipboardEvent) {
+ for (const { item, i } of Array.from(ev.clipboardData.items).map((item, i) => ({item, i}))) {
+ if (item.kind === 'file') {
const file = item.getAsFile();
const lio = file.name.lastIndexOf('.');
const ext = lio >= 0 ? file.name.slice(lio) : '';
@@ -453,10 +452,10 @@ async function onPaste(e: ClipboardEvent) {
}
}
- const paste = e.clipboardData.getData('text');
+ const paste = ev.clipboardData.getData('text');
if (!props.renote && !quoteId && paste.startsWith(url + '/notes/')) {
- e.preventDefault();
+ ev.preventDefault();
os.confirm({
type: 'info',
@@ -472,49 +471,49 @@ async function onPaste(e: ClipboardEvent) {
}
}
-function onDragover(e) {
- if (!e.dataTransfer.items[0]) return;
- const isFile = e.dataTransfer.items[0].kind == 'file';
- const isDriveFile = e.dataTransfer.types[0] == _DATA_TRANSFER_DRIVE_FILE_;
+function onDragover(ev) {
+ if (!ev.dataTransfer.items[0]) return;
+ const isFile = ev.dataTransfer.items[0].kind === 'file';
+ const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
if (isFile || isDriveFile) {
- e.preventDefault();
+ ev.preventDefault();
draghover = true;
- e.dataTransfer.dropEffect = e.dataTransfer.effectAllowed == 'all' ? 'copy' : 'move';
+ ev.dataTransfer.dropEffect = ev.dataTransfer.effectAllowed === 'all' ? 'copy' : 'move';
}
}
-function onDragenter(e) {
+function onDragenter(ev) {
draghover = true;
}
-function onDragleave(e) {
+function onDragleave(ev) {
draghover = false;
}
-function onDrop(e): void {
+function onDrop(ev): void {
draghover = false;
// ファイルだったら
- if (e.dataTransfer.files.length > 0) {
- e.preventDefault();
- for (const x of Array.from(e.dataTransfer.files)) upload(x);
+ if (ev.dataTransfer.files.length > 0) {
+ ev.preventDefault();
+ for (const x of Array.from(ev.dataTransfer.files)) upload(x);
return;
}
//#region ドライブのファイル
- const driveFile = e.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
- if (driveFile != null && driveFile != '') {
+ const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
+ if (driveFile != null && driveFile !== '') {
const file = JSON.parse(driveFile);
files.push(file);
- e.preventDefault();
+ ev.preventDefault();
}
//#endregion
}
function saveDraft() {
- const data = JSON.parse(localStorage.getItem('drafts') || '{}');
+ const draftData = JSON.parse(localStorage.getItem('drafts') || '{}');
- data[draftKey] = {
+ draftData[draftKey] = {
updatedAt: new Date(),
data: {
text: text,
@@ -527,20 +526,20 @@ function saveDraft() {
}
};
- localStorage.setItem('drafts', JSON.stringify(data));
+ localStorage.setItem('drafts', JSON.stringify(draftData));
}
function deleteDraft() {
- const data = JSON.parse(localStorage.getItem('drafts') || '{}');
+ const draftData = JSON.parse(localStorage.getItem('drafts') || '{}');
- delete data[draftKey];
+ delete draftData[draftKey];
- localStorage.setItem('drafts', JSON.stringify(data));
+ localStorage.setItem('drafts', JSON.stringify(draftData));
}
async function post() {
- let data = {
- text: text == '' ? undefined : text,
+ let postData = {
+ text: text === '' ? undefined : text,
fileIds: files.length > 0 ? files.map(f => f.id) : undefined,
replyId: props.reply ? props.reply.id : undefined,
renoteId: props.renote ? props.renote.id : quoteId ? quoteId : undefined,
@@ -549,18 +548,18 @@ async function post() {
cw: useCw ? cw || '' : undefined,
localOnly: localOnly,
visibility: visibility,
- visibleUserIds: visibility == 'specified' ? visibleUsers.map(u => u.id) : undefined,
+ visibleUserIds: visibility === 'specified' ? visibleUsers.map(u => u.id) : undefined,
};
if (withHashtags && hashtags && hashtags.trim() !== '') {
const hashtags_ = hashtags.trim().split(' ').map(x => x.startsWith('#') ? x : '#' + x).join(' ');
- data.text = data.text ? `${data.text} ${hashtags_}` : hashtags_;
+ postData.text = postData.text ? `${postData.text} ${hashtags_}` : hashtags_;
}
// plugin
if (notePostInterruptors.length > 0) {
for (const interruptor of notePostInterruptors) {
- data = await interruptor.handler(JSON.parse(JSON.stringify(data)));
+ postData = await interruptor.handler(JSON.parse(JSON.stringify(postData)));
}
}
@@ -572,13 +571,13 @@ async function post() {
}
posting = true;
- os.api('notes/create', data, token).then(() => {
+ os.api('notes/create', postData, token).then(() => {
clear();
nextTick(() => {
deleteDraft();
emit('posted');
- if (data.text && data.text != '') {
- const hashtags_ = mfm.parse(data.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
+ if (postData.text && postData.text !== '') {
+ const hashtags_ = mfm.parse(postData.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag);
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history))));
}
@@ -662,7 +661,7 @@ onMounted(() => {
cw = draft.data.cw;
visibility = draft.data.visibility;
localOnly = draft.data.localOnly;
- files = (draft.data.files || []).filter(e => e);
+ files = (draft.data.files || []).filter(draftFile => draftFile);
if (draft.data.poll) {
poll = draft.data.poll;
}
diff --git a/packages/client/src/components/reactions-viewer.reaction.vue b/packages/client/src/components/reactions-viewer.reaction.vue
index 7dc079fde6..91a90a6996 100644
--- a/packages/client/src/components/reactions-viewer.reaction.vue
+++ b/packages/client/src/components/reactions-viewer.reaction.vue
@@ -7,8 +7,8 @@
:class="{ reacted: note.myReaction == reaction, canToggle }"
@click="toggleReaction()"
>
- <XReactionIcon :reaction="reaction" :custom-emojis="note.emojis"/>
- <span>{{ count }}</span>
+ <XReactionIcon class="icon" :reaction="reaction" :custom-emojis="note.emojis"/>
+ <span class="count">{{ count }}</span>
</button>
</template>
@@ -141,12 +141,16 @@ export default defineComponent({
background: var(--accent);
}
- > span {
+ > .count {
color: var(--fgOnAccent);
}
+
+ > .icon {
+ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
+ }
}
- > span {
+ > .count {
font-size: 0.9em;
line-height: 32px;
margin: 0 0 0 4px;
diff --git a/packages/client/src/components/signin-dialog.vue b/packages/client/src/components/signin-dialog.vue
index 5c2048e7b0..848b11fada 100644
--- a/packages/client/src/components/signin-dialog.vue
+++ b/packages/client/src/components/signin-dialog.vue
@@ -2,12 +2,12 @@
<XModalWindow ref="dialog"
:width="370"
:height="400"
- @close="dialog.close()"
+ @close="onClose"
@closed="emit('closed')"
>
<template #header>{{ $ts.login }}</template>
- <MkSignin :auto-set="autoSet" @login="onLogin"/>
+ <MkSignin :auto-set="autoSet" :message="message" @login="onLogin"/>
</XModalWindow>
</template>
@@ -18,17 +18,25 @@ import MkSignin from './signin.vue';
const props = withDefaults(defineProps<{
autoSet?: boolean;
+ message?: string,
}>(), {
autoSet: false,
+ message: ''
});
const emit = defineEmits<{
- (e: 'done'): void;
- (e: 'closed'): void;
+ (ev: 'done'): void;
+ (ev: 'closed'): void;
+ (ev: 'cancelled'): void;
}>();
const dialog = $ref<InstanceType<typeof XModalWindow>>();
+function onClose() {
+ emit('cancelled');
+ dialog.close();
+}
+
function onLogin(res) {
emit('done', res);
dialog.close();
diff --git a/packages/client/src/components/signin.vue b/packages/client/src/components/signin.vue
index f640e948ad..d283a758a6 100644
--- a/packages/client/src/components/signin.vue
+++ b/packages/client/src/components/signin.vue
@@ -1,39 +1,44 @@
<template>
<form class="eppvobhk _monolithic_" :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
<div class="auth _section _formRoot">
- <div v-show="withAvatar" class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }"></div>
+ <div v-show="withAvatar" class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null, marginBottom: message ? '1.5em' : null }"></div>
+ <MkInfo v-if="message">
+ {{ message }}
+ </MkInfo>
<div v-if="!totpLogin" class="normal-signin">
- <MkInput v-model="username" class="_formBlock" :placeholder="$ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange">
+ <MkInput v-model="username" class="_formBlock" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange">
<template #prefix>@</template>
<template #suffix>@{{ host }}</template>
</MkInput>
- <MkInput v-if="!user || user && !user.usePasswordLessLogin" v-model="password" class="_formBlock" :placeholder="$ts.password" type="password" :with-password-toggle="true" required data-cy-signin-password>
+ <MkInput v-if="!user || user && !user.usePasswordLessLogin" v-model="password" class="_formBlock" :placeholder="i18n.ts.password" type="password" :with-password-toggle="true" required data-cy-signin-password>
<template #prefix><i class="fas fa-lock"></i></template>
- <template #caption><button class="_textButton" type="button" @click="resetPassword">{{ $ts.forgotPassword }}</button></template>
+ <template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template>
</MkInput>
- <MkButton class="_formBlock" type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
+ <MkCaptcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
+ <MkCaptcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
+ <MkButton class="_formBlock" type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
</div>
<div v-if="totpLogin" class="2fa-signin" :class="{ securityKeys: user && user.securityKeys }">
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
- <p>{{ $ts.tapSecurityKey }}</p>
+ <p>{{ i18n.ts.tapSecurityKey }}</p>
<MkButton v-if="!queryingKey" @click="queryKey">
- {{ $ts.retry }}
+ {{ i18n.ts.retry }}
</MkButton>
</div>
<div v-if="user && user.securityKeys" class="or-hr">
- <p class="or-msg">{{ $ts.or }}</p>
+ <p class="or-msg">{{ i18n.ts.or }}</p>
</div>
<div class="twofa-group totp-group">
- <p style="margin-bottom:0;">{{ $ts.twoStepAuthentication }}</p>
+ <p style="margin-bottom:0;">{{ i18n.ts.twoStepAuthentication }}</p>
<MkInput v-if="user && user.usePasswordLessLogin" v-model="password" type="password" :with-password-toggle="true" required>
- <template #label>{{ $ts.password }}</template>
+ <template #label>{{ i18n.ts.password }}</template>
<template #prefix><i class="fas fa-lock"></i></template>
</MkInput>
<MkInput v-model="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
- <template #label>{{ $ts.token }}</template>
+ <template #label>{{ i18n.ts.token }}</template>
<template #prefix><i class="fas fa-gavel"></i></template>
</MkInput>
- <MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
+ <MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
</div>
</div>
</div>
@@ -45,190 +50,192 @@
</form>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { defineAsyncComponent } from 'vue';
import { toUnicode } from 'punycode/';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
-import { apiUrl, host } from '@/config';
+import MkInfo from '@/components/ui/info.vue';
+import { apiUrl, host as configHost } from '@/config';
import { byteify, hexify } from '@/scripts/2fa';
import * as os from '@/os';
import { login } from '@/account';
import { showSuspendedDialog } from '../scripts/show-suspended-dialog';
+import { instance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkButton,
- MkInput,
- },
+const MkCaptcha = defineAsyncComponent(() => import('./captcha.vue'));
- props: {
- withAvatar: {
- type: Boolean,
- required: false,
- default: true
- },
- autoSet: {
- type: Boolean,
- required: false,
- default: false,
- }
- },
+let signing = $ref(false);
+let user = $ref(null);
+let username = $ref('');
+let password = $ref('');
+let token = $ref('');
+let host = $ref(toUnicode(configHost));
+let totpLogin = $ref(false);
+let credential = $ref(null);
+let challengeData = $ref(null);
+let queryingKey = $ref(false);
+let hCaptchaResponse = $ref(null);
+let reCaptchaResponse = $ref(null);
- emits: ['login'],
+const meta = $computed(() => instance);
- data() {
- return {
- signing: false,
- user: null,
- username: '',
- password: '',
- token: '',
- apiUrl,
- host: toUnicode(host),
- totpLogin: false,
- credential: null,
- challengeData: null,
- queryingKey: false,
- };
- },
+const emit = defineEmits<{
+ (ev: 'login', v: any): void;
+}>();
- computed: {
- meta() {
- return this.$instance;
- },
+const props = defineProps({
+ withAvatar: {
+ type: Boolean,
+ required: false,
+ default: true
},
+ autoSet: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ message: {
+ type: String,
+ required: false,
+ default: ''
+ }
+});
- methods: {
- onUsernameChange() {
- os.api('users/show', {
- username: this.username
- }).then(user => {
- this.user = user;
- }, () => {
- this.user = null;
- });
- },
-
- onLogin(res) {
- if (this.autoSet) {
- return login(res.i);
- } else {
- return;
- }
- },
-
- queryKey() {
- this.queryingKey = true;
- return navigator.credentials.get({
- publicKey: {
- challenge: byteify(this.challengeData.challenge, 'base64'),
- allowCredentials: this.challengeData.securityKeys.map(key => ({
- id: byteify(key.id, 'hex'),
- type: 'public-key',
- transports: ['usb', 'nfc', 'ble', 'internal']
- })),
- timeout: 60 * 1000
- }
- }).catch(() => {
- this.queryingKey = false;
- return Promise.reject(null);
- }).then(credential => {
- this.queryingKey = false;
- this.signing = true;
- return os.api('signin', {
- username: this.username,
- password: this.password,
- signature: hexify(credential.response.signature),
- authenticatorData: hexify(credential.response.authenticatorData),
- clientDataJSON: hexify(credential.response.clientDataJSON),
- credentialId: credential.id,
- challengeId: this.challengeData.challengeId
- });
- }).then(res => {
- this.$emit('login', res);
- return this.onLogin(res);
- }).catch(err => {
- if (err === null) return;
- os.alert({
- type: 'error',
- text: this.$ts.signinFailed
- });
- this.signing = false;
- });
- },
+function onUsernameChange() {
+ os.api('users/show', {
+ username: username
+ }).then(userResponse => {
+ user = userResponse;
+ }, () => {
+ user = null;
+ });
+}
- onSubmit() {
- this.signing = true;
- if (!this.totpLogin && this.user && this.user.twoFactorEnabled) {
- if (window.PublicKeyCredential && this.user.securityKeys) {
- os.api('signin', {
- username: this.username,
- password: this.password
- }).then(res => {
- this.totpLogin = true;
- this.signing = false;
- this.challengeData = res;
- return this.queryKey();
- }).catch(this.loginFailed);
- } else {
- this.totpLogin = true;
- this.signing = false;
- }
- } else {
- os.api('signin', {
- username: this.username,
- password: this.password,
- token: this.user && this.user.twoFactorEnabled ? this.token : undefined
- }).then(res => {
- this.$emit('login', res);
- this.onLogin(res);
- }).catch(this.loginFailed);
- }
- },
+function onLogin(res) {
+ if (props.autoSet) {
+ return login(res.i);
+ }
+}
- loginFailed(err) {
- switch (err.id) {
- case '6cc579cc-885d-43d8-95c2-b8c7fc963280': {
- os.alert({
- type: 'error',
- title: this.$ts.loginFailed,
- text: this.$ts.noSuchUser
- });
- break;
- }
- case '932c904e-9460-45b7-9ce6-7ed33be7eb2c': {
- os.alert({
- type: 'error',
- title: this.$ts.loginFailed,
- text: this.$ts.incorrectPassword,
- });
- break;
- }
- case 'e03a5f46-d309-4865-9b69-56282d94e1eb': {
- showSuspendedDialog();
- break;
- }
- default: {
- os.alert({
- type: 'error',
- title: this.$ts.loginFailed,
- text: JSON.stringify(err)
- });
- }
- }
+function queryKey() {
+ queryingKey = true;
+ return navigator.credentials.get({
+ publicKey: {
+ challenge: byteify(challengeData.challenge, 'base64'),
+ allowCredentials: challengeData.securityKeys.map(key => ({
+ id: byteify(key.id, 'hex'),
+ type: 'public-key',
+ transports: ['usb', 'nfc', 'ble', 'internal']
+ })),
+ timeout: 60 * 1000
+ }
+ }).catch(() => {
+ queryingKey = false;
+ return Promise.reject(null);
+ }).then(credential => {
+ queryingKey = false;
+ signing = true;
+ return os.api('signin', {
+ username,
+ password,
+ signature: hexify(credential.response.signature),
+ authenticatorData: hexify(credential.response.authenticatorData),
+ clientDataJSON: hexify(credential.response.clientDataJSON),
+ credentialId: credential.id,
+ challengeId: challengeData.challengeId,
+ 'hcaptcha-response': hCaptchaResponse,
+ 'g-recaptcha-response': reCaptchaResponse,
+ });
+ }).then(res => {
+ emit('login', res);
+ return onLogin(res);
+ }).catch(err => {
+ if (err === null) return;
+ os.alert({
+ type: 'error',
+ text: i18n.ts.signinFailed
+ });
+ signing = false;
+ });
+}
- this.challengeData = null;
- this.totpLogin = false;
- this.signing = false;
- },
+function onSubmit() {
+ signing = true;
+ console.log('submit')
+ if (!totpLogin && user && user.twoFactorEnabled) {
+ if (window.PublicKeyCredential && user.securityKeys) {
+ os.api('signin', {
+ username,
+ password,
+ 'hcaptcha-response': hCaptchaResponse,
+ 'g-recaptcha-response': reCaptchaResponse,
+ }).then(res => {
+ totpLogin = true;
+ signing = false;
+ challengeData = res;
+ return queryKey();
+ }).catch(loginFailed);
+ } else {
+ totpLogin = true;
+ signing = false;
+ }
+ } else {
+ os.api('signin', {
+ username,
+ password,
+ 'hcaptcha-response': hCaptchaResponse,
+ 'g-recaptcha-response': reCaptchaResponse,
+ token: user && user.twoFactorEnabled ? token : undefined
+ }).then(res => {
+ emit('login', res);
+ onLogin(res);
+ }).catch(loginFailed);
+ }
+}
- resetPassword() {
- os.popup(import('@/components/forgot-password.vue'), {}, {
- }, 'closed');
+function loginFailed(err) {
+ switch (err.id) {
+ case '6cc579cc-885d-43d8-95c2-b8c7fc963280': {
+ os.alert({
+ type: 'error',
+ title: i18n.ts.loginFailed,
+ text: i18n.ts.noSuchUser
+ });
+ break;
+ }
+ case '932c904e-9460-45b7-9ce6-7ed33be7eb2c': {
+ os.alert({
+ type: 'error',
+ title: i18n.ts.loginFailed,
+ text: i18n.ts.incorrectPassword,
+ });
+ break;
+ }
+ case 'e03a5f46-d309-4865-9b69-56282d94e1eb': {
+ showSuspendedDialog();
+ break;
+ }
+ default: {
+ console.log(err)
+ os.alert({
+ type: 'error',
+ title: i18n.ts.loginFailed,
+ text: JSON.stringify(err)
+ });
}
}
-});
+
+ challengeData = null;
+ totpLogin = false;
+ signing = false;
+}
+
+function resetPassword() {
+ os.popup(defineAsyncComponent(() => import('@/components/forgot-password.vue')), {}, {
+ }, 'closed');
+}
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/components/signup-dialog.vue b/packages/client/src/components/signup-dialog.vue
index bda2495ba7..6dad9257a4 100644
--- a/packages/client/src/components/signup-dialog.vue
+++ b/packages/client/src/components/signup-dialog.vue
@@ -27,8 +27,8 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'done'): void;
- (e: 'closed'): void;
+ (ev: 'done'): void;
+ (ev: 'closed'): void;
}>();
const dialog = $ref<InstanceType<typeof XModalWindow>>();
diff --git a/packages/client/src/components/signup.vue b/packages/client/src/components/signup.vue
index 38a9fd55f1..58c15d81b1 100644
--- a/packages/client/src/components/signup.vue
+++ b/packages/client/src/components/signup.vue
@@ -58,8 +58,8 @@
</template>
</I18n>
</MkSwitch>
- <captcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
- <captcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
+ <MkCaptcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
+ <MkCaptcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
<MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ $ts.start }}</MkButton>
</template>
</form>
@@ -67,7 +67,7 @@
<script lang="ts">
import { defineComponent, defineAsyncComponent } from 'vue';
-const getPasswordStrength = require('syuilo-password-strength');
+const getPasswordStrength = await import('syuilo-password-strength');
import { toUnicode } from 'punycode/';
import { host, url } from '@/config';
import MkButton from './ui/button.vue';
@@ -81,7 +81,7 @@ export default defineComponent({
MkButton,
MkInput,
MkSwitch,
- captcha: defineAsyncComponent(() => import('./captcha.vue')),
+ MkCaptcha: defineAsyncComponent(() => import('./captcha.vue')),
},
props: {
@@ -124,20 +124,20 @@ export default defineComponent({
this.meta.tosUrl && !this.ToSAgreement ||
this.meta.enableHcaptcha && !this.hCaptchaResponse ||
this.meta.enableRecaptcha && !this.reCaptchaResponse ||
- this.passwordRetypeState == 'not-match';
+ this.passwordRetypeState === 'not-match';
},
shouldShowProfileUrl(): boolean {
- return (this.username != '' &&
- this.usernameState != 'invalid-format' &&
- this.usernameState != 'min-range' &&
- this.usernameState != 'max-range');
+ return (this.username !== '' &&
+ this.usernameState !== 'invalid-format' &&
+ this.usernameState !== 'min-range' &&
+ this.usernameState !== 'max-range');
}
},
methods: {
onChangeUsername() {
- if (this.username == '') {
+ if (this.username === '') {
this.usernameState = null;
return;
}
@@ -165,7 +165,7 @@ export default defineComponent({
},
onChangeEmail() {
- if (this.email == '') {
+ if (this.email === '') {
this.emailState = null;
return;
}
@@ -188,7 +188,7 @@ export default defineComponent({
},
onChangePassword() {
- if (this.password == '') {
+ if (this.password === '') {
this.passwordStrength = '';
return;
}
@@ -198,12 +198,12 @@ export default defineComponent({
},
onChangePasswordRetype() {
- if (this.retypedPassword == '') {
+ if (this.retypedPassword === '') {
this.passwordRetypeState = null;
return;
}
- this.passwordRetypeState = this.password == this.retypedPassword ? 'match' : 'not-match';
+ this.passwordRetypeState = this.password === this.retypedPassword ? 'match' : 'not-match';
},
onSubmit() {
diff --git a/packages/client/src/components/timeline.vue b/packages/client/src/components/timeline.vue
index 59956b9526..a3fa27ab78 100644
--- a/packages/client/src/components/timeline.vue
+++ b/packages/client/src/components/timeline.vue
@@ -19,8 +19,8 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'note'): void;
- (e: 'queue', count: number): void;
+ (ev: 'note'): void;
+ (ev: 'queue', count: number): void;
}>();
provide('inChannel', computed(() => props.src === 'channel'));
@@ -95,7 +95,7 @@ if (props.src === 'antenna') {
visibility: 'specified'
};
const onNote = note => {
- if (note.visibility == 'specified') {
+ if (note.visibility === 'specified') {
prepend(note);
}
};
diff --git a/packages/client/src/components/toast.vue b/packages/client/src/components/toast.vue
index 99933f3846..c9fad64eb6 100644
--- a/packages/client/src/components/toast.vue
+++ b/packages/client/src/components/toast.vue
@@ -19,7 +19,7 @@ defineProps<{
}>();
const emit = defineEmits<{
- (e: 'closed'): void;
+ (ev: 'closed'): void;
}>();
const zIndex = os.claimZIndex('high');
diff --git a/packages/client/src/components/ui/button.vue b/packages/client/src/components/ui/button.vue
index c7b6c8ba96..fe8f1c7cca 100644
--- a/packages/client/src/components/ui/button.vue
+++ b/packages/client/src/components/ui/button.vue
@@ -90,7 +90,7 @@ export default defineComponent({
}
},
methods: {
- onMousedown(e: MouseEvent) {
+ onMousedown(evt: MouseEvent) {
function distance(p, q) {
return Math.hypot(p.x - q.x, p.y - q.y);
}
@@ -104,18 +104,18 @@ export default defineComponent({
return Math.max(dist1, dist2, dist3, dist4) * 2;
}
- const rect = e.target.getBoundingClientRect();
+ const rect = evt.target.getBoundingClientRect();
const ripple = document.createElement('div');
- ripple.style.top = (e.clientY - rect.top - 1).toString() + 'px';
- ripple.style.left = (e.clientX - rect.left - 1).toString() + 'px';
+ ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px';
+ ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px';
this.$refs.ripples.appendChild(ripple);
- const circleCenterX = e.clientX - rect.left;
- const circleCenterY = e.clientY - rect.top;
+ const circleCenterX = evt.clientX - rect.left;
+ const circleCenterY = evt.clientY - rect.top;
- const scale = calcCircleScale(e.target.clientWidth, e.target.clientHeight, circleCenterX, circleCenterY);
+ const scale = calcCircleScale(evt.target.clientWidth, evt.target.clientHeight, circleCenterX, circleCenterY);
window.setTimeout(() => {
ripple.style.transform = 'scale(' + (scale / 2) + ')';
diff --git a/packages/client/src/components/ui/context-menu.vue b/packages/client/src/components/ui/context-menu.vue
index f491b43b46..e637d361cf 100644
--- a/packages/client/src/components/ui/context-menu.vue
+++ b/packages/client/src/components/ui/context-menu.vue
@@ -19,7 +19,7 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'closed'): void;
+ (ev: 'closed'): void;
}>();
let rootEl = $ref<HTMLDivElement>();
@@ -63,8 +63,8 @@ onBeforeUnmount(() => {
}
});
-function onMousedown(e: Event) {
- if (!contains(rootEl, e.target) && (rootEl != e.target)) emit('closed');
+function onMousedown(evt: Event) {
+ if (!contains(rootEl, evt.target) && (rootEl !== evt.target)) emit('closed');
}
</script>
diff --git a/packages/client/src/components/ui/folder.vue b/packages/client/src/components/ui/folder.vue
index fe1602b2bb..7daa82cbd3 100644
--- a/packages/client/src/components/ui/folder.vue
+++ b/packages/client/src/components/ui/folder.vue
@@ -23,7 +23,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
-import * as tinycolor from 'tinycolor2';
+import tinycolor from 'tinycolor2';
const localStoragePrefix = 'ui:folder:';
diff --git a/packages/client/src/components/ui/menu.vue b/packages/client/src/components/ui/menu.vue
index a93cc8cda8..ca56048262 100644
--- a/packages/client/src/components/ui/menu.vue
+++ b/packages/client/src/components/ui/menu.vue
@@ -60,7 +60,7 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'close'): void;
+ (ev: 'close'): void;
}>();
let itemsEl = $ref<HTMLDivElement>();
diff --git a/packages/client/src/components/ui/modal-window.vue b/packages/client/src/components/ui/modal-window.vue
index b4b8c2b965..6de29c83fa 100644
--- a/packages/client/src/components/ui/modal-window.vue
+++ b/packages/client/src/components/ui/modal-window.vue
@@ -79,10 +79,10 @@ export default defineComponent({
this.$refs.modal.close();
},
- onKeydown(e) {
- if (e.which === 27) { // Esc
- e.preventDefault();
- e.stopPropagation();
+ onKeydown(evt) {
+ if (evt.which === 27) { // Esc
+ evt.preventDefault();
+ evt.stopPropagation();
this.close();
}
},
diff --git a/packages/client/src/components/ui/pagination.vue b/packages/client/src/components/ui/pagination.vue
index ac6f59c332..c081e06acd 100644
--- a/packages/client/src/components/ui/pagination.vue
+++ b/packages/client/src/components/ui/pagination.vue
@@ -14,8 +14,14 @@
</div>
<div v-else ref="rootEl">
+ <div v-show="pagination.reversed && more" key="_more_" class="cxiknjgy _gap">
+ <MkButton v-if="!moreFetching" class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary @click="fetchMoreAhead">
+ {{ $ts.loadMore }}
+ </MkButton>
+ <MkLoading v-else class="loading"/>
+ </div>
<slot :items="items"></slot>
- <div v-show="more" key="_more_" class="cxiknjgy _gap">
+ <div v-show="!pagination.reversed && more" key="_more_" class="cxiknjgy _gap">
<MkButton v-if="!moreFetching" v-appear="($store.state.enableInfiniteScroll && !disableAutoLoad) ? fetchMore : null" class="button" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary @click="fetchMore">
{{ $ts.loadMore }}
</MkButton>
@@ -62,7 +68,7 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'queue', count: number): void;
+ (ev: 'queue', count: number): void;
}>();
type Item = { id: string; [another: string]: unknown; };
@@ -106,7 +112,7 @@ const init = async (): Promise<void> => {
offset.value = res.length;
error.value = false;
fetching.value = false;
- }, e => {
+ }, err => {
error.value = true;
fetching.value = false;
});
@@ -149,7 +155,7 @@ const fetchMore = async (): Promise<void> => {
}
offset.value += res.length;
moreFetching.value = false;
- }, e => {
+ }, err => {
moreFetching.value = false;
});
};
@@ -177,7 +183,7 @@ const fetchMoreAhead = async (): Promise<void> => {
}
offset.value += res.length;
moreFetching.value = false;
- }, e => {
+ }, err => {
moreFetching.value = false;
});
};
@@ -244,6 +250,11 @@ const append = (item: Item): void => {
items.value.push(item);
};
+const removeItem = (finder: (item: Item) => boolean) => {
+ const i = items.value.findIndex(finder);
+ items.value.splice(i, 1);
+};
+
const updateItem = (id: Item['id'], replacer: (old: Item) => Item): void => {
const i = items.value.findIndex(item => item.id === id);
items.value[i] = replacer(items.value[i]);
@@ -273,9 +284,9 @@ defineExpose({
queue,
backed,
reload,
- fetchMoreAhead,
prepend,
append,
+ removeItem,
updateItem,
});
</script>
diff --git a/packages/client/src/components/ui/popup-menu.vue b/packages/client/src/components/ui/popup-menu.vue
index 8d6c1b5695..2bc7030d77 100644
--- a/packages/client/src/components/ui/popup-menu.vue
+++ b/packages/client/src/components/ui/popup-menu.vue
@@ -19,7 +19,7 @@ defineProps<{
}>();
const emit = defineEmits<{
- (e: 'closed'): void;
+ (ev: 'closed'): void;
}>();
let modal = $ref<InstanceType<typeof MkModal>>();
diff --git a/packages/client/src/components/ui/window.vue b/packages/client/src/components/ui/window.vue
index fa32ecfdef..2066cf579d 100644
--- a/packages/client/src/components/ui/window.vue
+++ b/packages/client/src/components/ui/window.vue
@@ -139,10 +139,10 @@ export default defineComponent({
this.showing = false;
},
- onKeydown(e) {
- if (e.which === 27) { // Esc
- e.preventDefault();
- e.stopPropagation();
+ onKeydown(evt) {
+ if (evt.which === 27) { // Esc
+ evt.preventDefault();
+ evt.stopPropagation();
this.close();
}
},
@@ -162,15 +162,15 @@ export default defineComponent({
this.top();
},
- onHeaderMousedown(e) {
+ onHeaderMousedown(evt) {
const main = this.$el as any;
if (!contains(main, document.activeElement)) main.focus();
const position = main.getBoundingClientRect();
- const clickX = e.touches && e.touches.length > 0 ? e.touches[0].clientX : e.clientX;
- const clickY = e.touches && e.touches.length > 0 ? e.touches[0].clientY : e.clientY;
+ const clickX = evt.touches && evt.touches.length > 0 ? evt.touches[0].clientX : evt.clientX;
+ const clickY = evt.touches && evt.touches.length > 0 ? evt.touches[0].clientY : evt.clientY;
const moveBaseX = clickX - position.left;
const moveBaseY = clickY - position.top;
const browserWidth = window.innerWidth;
@@ -204,10 +204,10 @@ export default defineComponent({
},
// 上ハンドル掴み時
- onTopHandleMousedown(e) {
+ onTopHandleMousedown(evt) {
const main = this.$el as any;
- const base = e.clientY;
+ const base = evt.clientY;
const height = parseInt(getComputedStyle(main, '').height, 10);
const top = parseInt(getComputedStyle(main, '').top, 10);
@@ -230,10 +230,10 @@ export default defineComponent({
},
// 右ハンドル掴み時
- onRightHandleMousedown(e) {
+ onRightHandleMousedown(evt) {
const main = this.$el as any;
- const base = e.clientX;
+ const base = evt.clientX;
const width = parseInt(getComputedStyle(main, '').width, 10);
const left = parseInt(getComputedStyle(main, '').left, 10);
const browserWidth = window.innerWidth;
@@ -254,10 +254,10 @@ export default defineComponent({
},
// 下ハンドル掴み時
- onBottomHandleMousedown(e) {
+ onBottomHandleMousedown(evt) {
const main = this.$el as any;
- const base = e.clientY;
+ const base = evt.clientY;
const height = parseInt(getComputedStyle(main, '').height, 10);
const top = parseInt(getComputedStyle(main, '').top, 10);
const browserHeight = window.innerHeight;
@@ -278,10 +278,10 @@ export default defineComponent({
},
// 左ハンドル掴み時
- onLeftHandleMousedown(e) {
+ onLeftHandleMousedown(evt) {
const main = this.$el as any;
- const base = e.clientX;
+ const base = evt.clientX;
const width = parseInt(getComputedStyle(main, '').width, 10);
const left = parseInt(getComputedStyle(main, '').left, 10);
@@ -304,27 +304,27 @@ export default defineComponent({
},
// 左上ハンドル掴み時
- onTopLeftHandleMousedown(e) {
- this.onTopHandleMousedown(e);
- this.onLeftHandleMousedown(e);
+ onTopLeftHandleMousedown(evt) {
+ this.onTopHandleMousedown(evt);
+ this.onLeftHandleMousedown(evt);
},
// 右上ハンドル掴み時
- onTopRightHandleMousedown(e) {
- this.onTopHandleMousedown(e);
- this.onRightHandleMousedown(e);
+ onTopRightHandleMousedown(evt) {
+ this.onTopHandleMousedown(evt);
+ this.onRightHandleMousedown(evt);
},
// 右下ハンドル掴み時
- onBottomRightHandleMousedown(e) {
- this.onBottomHandleMousedown(e);
- this.onRightHandleMousedown(e);
+ onBottomRightHandleMousedown(evt) {
+ this.onBottomHandleMousedown(evt);
+ this.onRightHandleMousedown(evt);
},
// 左下ハンドル掴み時
- onBottomLeftHandleMousedown(e) {
- this.onBottomHandleMousedown(e);
- this.onLeftHandleMousedown(e);
+ onBottomLeftHandleMousedown(evt) {
+ this.onBottomHandleMousedown(evt);
+ this.onLeftHandleMousedown(evt);
},
// 高さを適用
diff --git a/packages/client/src/components/user-preview.vue b/packages/client/src/components/user-preview.vue
index 51c5330564..f80947f75a 100644
--- a/packages/client/src/components/user-preview.vue
+++ b/packages/client/src/components/user-preview.vue
@@ -70,7 +70,7 @@ export default defineComponent({
},
mounted() {
- if (typeof this.q == 'object') {
+ if (typeof this.q === 'object') {
this.user = this.q;
this.fetched = true;
} else {
diff --git a/packages/client/src/components/user-select-dialog.vue b/packages/client/src/components/user-select-dialog.vue
index dbef34d547..b34d21af07 100644
--- a/packages/client/src/components/user-select-dialog.vue
+++ b/packages/client/src/components/user-select-dialog.vue
@@ -60,9 +60,9 @@ import * as os from '@/os';
import { defaultStore } from '@/store';
const emit = defineEmits<{
- (e: 'ok', selected: misskey.entities.UserDetailed): void;
- (e: 'cancel'): void;
- (e: 'closed'): void;
+ (ev: 'ok', selected: misskey.entities.UserDetailed): void;
+ (ev: 'cancel'): void;
+ (ev: 'closed'): void;
}>();
let username = $ref('');
diff --git a/packages/client/src/components/visibility-picker.vue b/packages/client/src/components/visibility-picker.vue
index 4b20063a51..c717c3a461 100644
--- a/packages/client/src/components/visibility-picker.vue
+++ b/packages/client/src/components/visibility-picker.vue
@@ -57,9 +57,9 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
- (e: 'changeVisibility', v: typeof misskey.noteVisibilities[number]): void;
- (e: 'changeLocalOnly', v: boolean): void;
- (e: 'closed'): void;
+ (ev: 'changeVisibility', v: typeof misskey.noteVisibilities[number]): void;
+ (ev: 'changeLocalOnly', v: boolean): void;
+ (ev: 'closed'): void;
}>();
let v = $ref(props.currentVisibility);
diff --git a/packages/client/src/components/waiting-dialog.vue b/packages/client/src/components/waiting-dialog.vue
index 7dfcc55695..9e631b55b1 100644
--- a/packages/client/src/components/waiting-dialog.vue
+++ b/packages/client/src/components/waiting-dialog.vue
@@ -21,8 +21,8 @@ const props = defineProps<{
}>();
const emit = defineEmits<{
- (e: 'done');
- (e: 'closed');
+ (ev: 'done');
+ (ev: 'closed');
}>();
function done() {
diff --git a/packages/client/src/components/widgets.vue b/packages/client/src/components/widgets.vue
index da9d935281..b6835795cb 100644
--- a/packages/client/src/components/widgets.vue
+++ b/packages/client/src/components/widgets.vue
@@ -19,7 +19,7 @@
<div class="customize-container">
<button class="config _button" @click.prevent.stop="configWidget(element.id)"><i class="fas fa-cog"></i></button>
<button class="remove _button" @click.prevent.stop="removeWidget(element)"><i class="fas fa-times"></i></button>
- <component class="handle" :ref="el => widgetRefs[element.id] = el" :is="`mkw-${element.name}`" :widget="element" @updateProps="updateWidget(element.id, $event)"/>
+ <component :is="`mkw-${element.name}`" :ref="el => widgetRefs[element.id] = el" class="handle" :widget="element" @updateProps="updateWidget(element.id, $event)"/>
</div>
</template>
</XDraggable>
@@ -37,7 +37,7 @@ import { widgets as widgetDefs } from '@/widgets';
export default defineComponent({
components: {
- XDraggable: defineAsyncComponent(() => import('vuedraggable').then(x => x.default)),
+ XDraggable: defineAsyncComponent(() => import('vuedraggable')),
MkSelect,
MkButton,
},