enhance(client): improve user activity page
This commit is contained in:
		
							parent
							
								
									4ffbbbe6d8
								
							
						
					
					
						commit
						5320f23017
					
				
					 6 changed files with 386 additions and 68 deletions
				
			
		|  | @ -1,7 +1,7 @@ | ||||||
| <template> | <template> | ||||||
| <div class="ssazuxis"> | <div class="ssazuxis"> | ||||||
| 	<header class="_button" :style="{ background: bg }" @click="showBody = !showBody"> | 	<header class="_button" :style="{ background: bg }" @click="showBody = !showBody"> | ||||||
| 		<div class="title"><slot name="header"></slot></div> | 		<div class="title"><div><slot name="header"></slot></div></div> | ||||||
| 		<div class="divider"></div> | 		<div class="divider"></div> | ||||||
| 		<button class="_button"> | 		<button class="_button"> | ||||||
| 			<template v-if="showBody"><i class="ti ti-chevron-up"></i></template> | 			<template v-if="showBody"><i class="ti ti-chevron-up"></i></template> | ||||||
|  | @ -127,14 +127,6 @@ export default defineComponent({ | ||||||
| 			place-content: center; | 			place-content: center; | ||||||
| 			margin: 0; | 			margin: 0; | ||||||
| 			padding: 12px 16px 12px 0; | 			padding: 12px 16px 12px 0; | ||||||
| 
 |  | ||||||
| 			> i { |  | ||||||
| 				margin-right: 6px; |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			&:empty { |  | ||||||
| 				display: none; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		> .divider { | 		> .divider { | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ | ||||||
| 				<template #prefix><i class="ti ti-lock"></i></template> | 				<template #prefix><i class="ti ti-lock"></i></template> | ||||||
| 				<template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template> | 				<template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template> | ||||||
| 			</MkInput> | 			</MkInput> | ||||||
| 			<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton> | 			<MkButton type="submit" large primary rounded :disabled="signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton> | ||||||
| 		</div> | 		</div> | ||||||
| 		<div v-if="totpLogin" class="2fa-signin" :class="{ securityKeys: user && user.securityKeys }"> | 		<div v-if="totpLogin" class="2fa-signin" :class="{ securityKeys: user && user.securityKeys }"> | ||||||
| 			<div v-if="user && user.securityKeys" class="twofa-group tap-group"> | 			<div v-if="user && user.securityKeys" class="twofa-group tap-group"> | ||||||
|  | @ -36,7 +36,7 @@ | ||||||
| 					<template #label>{{ i18n.ts.token }}</template> | 					<template #label>{{ i18n.ts.token }}</template> | ||||||
| 					<template #prefix><i class="ti ti-123"></i></template> | 					<template #prefix><i class="ti ti-123"></i></template> | ||||||
| 				</MkInput> | 				</MkInput> | ||||||
| 				<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton> | 				<MkButton type="submit" :disabled="signing" large primary rounded style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton> | ||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 	</div> | 	</div> | ||||||
|  |  | ||||||
							
								
								
									
										174
									
								
								packages/frontend/src/pages/user/activity.following.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								packages/frontend/src/pages/user/activity.following.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,174 @@ | ||||||
|  | <template> | ||||||
|  | <div> | ||||||
|  | 	<MkLoading v-if="fetching"/> | ||||||
|  | 	<div v-show="!fetching" :class="$style.root" class="_panel"> | ||||||
|  | 		<canvas ref="chartEl"></canvas> | ||||||
|  | 		<MkChartLegend ref="legendEl" style="margin-top: 8px;"/> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } from 'vue'; | ||||||
|  | import { Chart, ChartDataset } from 'chart.js'; | ||||||
|  | import tinycolor from 'tinycolor2'; | ||||||
|  | import * as misskey from 'misskey-js'; | ||||||
|  | import gradient from 'chartjs-plugin-gradient'; | ||||||
|  | import { satisfies } from 'compare-versions'; | ||||||
|  | import * as os from '@/os'; | ||||||
|  | import { defaultStore } from '@/store'; | ||||||
|  | import { useChartTooltip } from '@/scripts/use-chart-tooltip'; | ||||||
|  | import { chartVLine } from '@/scripts/chart-vline'; | ||||||
|  | import { alpha } from '@/scripts/color'; | ||||||
|  | import { initChart } from '@/scripts/init-chart'; | ||||||
|  | import { chartLegend } from '@/scripts/chart-legend'; | ||||||
|  | import MkChartLegend from '@/components/MkChartLegend.vue'; | ||||||
|  | 
 | ||||||
|  | initChart(); | ||||||
|  | 
 | ||||||
|  | const props = defineProps<{ | ||||||
|  | 	user: misskey.entities.User; | ||||||
|  | }>(); | ||||||
|  | 
 | ||||||
|  | const chartEl = $shallowRef<HTMLCanvasElement>(null); | ||||||
|  | let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>(); | ||||||
|  | const now = new Date(); | ||||||
|  | let chartInstance: Chart = null; | ||||||
|  | const chartLimit = 50; | ||||||
|  | let fetching = $ref(true); | ||||||
|  | 
 | ||||||
|  | const { handler: externalTooltipHandler } = useChartTooltip(); | ||||||
|  | 
 | ||||||
|  | async function renderChart() { | ||||||
|  | 	if (chartInstance) { | ||||||
|  | 		chartInstance.destroy(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const getDate = (ago: number) => { | ||||||
|  | 		const y = now.getFullYear(); | ||||||
|  | 		const m = now.getMonth(); | ||||||
|  | 		const d = now.getDate(); | ||||||
|  | 
 | ||||||
|  | 		return new Date(y, m, d - ago); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	const format = (arr) => { | ||||||
|  | 		return arr.map((v, i) => ({ | ||||||
|  | 			x: getDate(i).getTime(), | ||||||
|  | 			y: v, | ||||||
|  | 		})); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	const raw = await os.api('charts/user/following', { userId: props.user.id, limit: chartLimit, span: 'day' }); | ||||||
|  | 
 | ||||||
|  | 	const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; | ||||||
|  | 
 | ||||||
|  | 	const colorFollowLocal = '#008FFB'; | ||||||
|  | 	const colorFollowRemote = '#008FFB88'; | ||||||
|  | 	const colorFollowedLocal = '#2ecc71'; | ||||||
|  | 	const colorFollowedRemote = '#2ecc7188'; | ||||||
|  | 
 | ||||||
|  | 	function makeDataset(label: string, data: ChartDataset['data'], extra: Partial<ChartDataset> = {}): ChartDataset { | ||||||
|  | 		return Object.assign({ | ||||||
|  | 			label: label, | ||||||
|  | 			data: data, | ||||||
|  | 			parsing: false, | ||||||
|  | 			pointRadius: 0, | ||||||
|  | 			borderWidth: 0, | ||||||
|  | 			borderJoinStyle: 'round', | ||||||
|  | 			borderRadius: 4, | ||||||
|  | 			barPercentage: 0.9, | ||||||
|  | 			fill: true, | ||||||
|  | 		} satisfies ChartDataset, extra); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	chartInstance = new Chart(chartEl, { | ||||||
|  | 		type: 'bar', | ||||||
|  | 		data: { | ||||||
|  | 			datasets: [ | ||||||
|  | 				makeDataset('Follow (local)', format(raw.local.followings.inc).slice().reverse(), { backgroundColor: colorFollowLocal }), | ||||||
|  | 				makeDataset('Follow (remote)', format(raw.remote.followings.inc).slice().reverse(), { backgroundColor: colorFollowRemote }), | ||||||
|  | 				makeDataset('Followed (local)', format(raw.local.followers.inc).slice().reverse(), { backgroundColor: colorFollowedLocal }), | ||||||
|  | 				makeDataset('Followed (remote)', format(raw.remote.followers.inc).slice().reverse(), { backgroundColor: colorFollowedRemote }), | ||||||
|  | 			], | ||||||
|  | 		}, | ||||||
|  | 		options: { | ||||||
|  | 			aspectRatio: 3, | ||||||
|  | 			layout: { | ||||||
|  | 				padding: { | ||||||
|  | 					left: 0, | ||||||
|  | 					right: 8, | ||||||
|  | 					top: 0, | ||||||
|  | 					bottom: 0, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			scales: { | ||||||
|  | 				x: { | ||||||
|  | 					type: 'time', | ||||||
|  | 					offset: true, | ||||||
|  | 					stacked: true, | ||||||
|  | 					time: { | ||||||
|  | 						stepSize: 1, | ||||||
|  | 						unit: 'day', | ||||||
|  | 						displayFormats: { | ||||||
|  | 							day: 'M/d', | ||||||
|  | 							month: 'Y/M', | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					grid: { | ||||||
|  | 						display: false, | ||||||
|  | 					}, | ||||||
|  | 					ticks: { | ||||||
|  | 						display: true, | ||||||
|  | 						maxRotation: 0, | ||||||
|  | 						autoSkipPadding: 8, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				y: { | ||||||
|  | 					position: 'left', | ||||||
|  | 					stacked: true, | ||||||
|  | 					suggestedMax: 10, | ||||||
|  | 					grid: { | ||||||
|  | 						display: true, | ||||||
|  | 					}, | ||||||
|  | 					ticks: { | ||||||
|  | 						display: true, | ||||||
|  | 						//mirror: true, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			interaction: { | ||||||
|  | 				intersect: false, | ||||||
|  | 				mode: 'index', | ||||||
|  | 			}, | ||||||
|  | 			plugins: { | ||||||
|  | 				legend: { | ||||||
|  | 					display: false, | ||||||
|  | 				}, | ||||||
|  | 				tooltip: { | ||||||
|  | 					enabled: false, | ||||||
|  | 					mode: 'index', | ||||||
|  | 					animation: { | ||||||
|  | 						duration: 0, | ||||||
|  | 					}, | ||||||
|  | 					external: externalTooltipHandler, | ||||||
|  | 				}, | ||||||
|  | 				gradient, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		plugins: [chartVLine(vLineColor), chartLegend(legendEl)], | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	fetching = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | onMounted(async () => { | ||||||
|  | 	renderChart(); | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" module> | ||||||
|  | .root { | ||||||
|  | 	padding: 20px; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										174
									
								
								packages/frontend/src/pages/user/activity.notes.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								packages/frontend/src/pages/user/activity.notes.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,174 @@ | ||||||
|  | <template> | ||||||
|  | <div> | ||||||
|  | 	<MkLoading v-if="fetching"/> | ||||||
|  | 	<div v-show="!fetching" :class="$style.root" class="_panel"> | ||||||
|  | 		<canvas ref="chartEl"></canvas> | ||||||
|  | 		<MkChartLegend ref="legendEl" style="margin-top: 8px;"/> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  | </template> | ||||||
|  | 
 | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } from 'vue'; | ||||||
|  | import { Chart, ChartDataset } from 'chart.js'; | ||||||
|  | import tinycolor from 'tinycolor2'; | ||||||
|  | import * as misskey from 'misskey-js'; | ||||||
|  | import gradient from 'chartjs-plugin-gradient'; | ||||||
|  | import { satisfies } from 'compare-versions'; | ||||||
|  | import * as os from '@/os'; | ||||||
|  | import { defaultStore } from '@/store'; | ||||||
|  | import { useChartTooltip } from '@/scripts/use-chart-tooltip'; | ||||||
|  | import { chartVLine } from '@/scripts/chart-vline'; | ||||||
|  | import { alpha } from '@/scripts/color'; | ||||||
|  | import { initChart } from '@/scripts/init-chart'; | ||||||
|  | import { chartLegend } from '@/scripts/chart-legend'; | ||||||
|  | import MkChartLegend from '@/components/MkChartLegend.vue'; | ||||||
|  | 
 | ||||||
|  | initChart(); | ||||||
|  | 
 | ||||||
|  | const props = defineProps<{ | ||||||
|  | 	user: misskey.entities.User; | ||||||
|  | }>(); | ||||||
|  | 
 | ||||||
|  | const chartEl = $shallowRef<HTMLCanvasElement>(null); | ||||||
|  | let legendEl = $shallowRef<InstanceType<typeof MkChartLegend>>(); | ||||||
|  | const now = new Date(); | ||||||
|  | let chartInstance: Chart = null; | ||||||
|  | const chartLimit = 50; | ||||||
|  | let fetching = $ref(true); | ||||||
|  | 
 | ||||||
|  | const { handler: externalTooltipHandler } = useChartTooltip(); | ||||||
|  | 
 | ||||||
|  | async function renderChart() { | ||||||
|  | 	if (chartInstance) { | ||||||
|  | 		chartInstance.destroy(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const getDate = (ago: number) => { | ||||||
|  | 		const y = now.getFullYear(); | ||||||
|  | 		const m = now.getMonth(); | ||||||
|  | 		const d = now.getDate(); | ||||||
|  | 
 | ||||||
|  | 		return new Date(y, m, d - ago); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	const format = (arr) => { | ||||||
|  | 		return arr.map((v, i) => ({ | ||||||
|  | 			x: getDate(i).getTime(), | ||||||
|  | 			y: v, | ||||||
|  | 		})); | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
|  | 	const raw = await os.api('charts/user/notes', { userId: props.user.id, limit: chartLimit, span: 'day' }); | ||||||
|  | 
 | ||||||
|  | 	const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; | ||||||
|  | 
 | ||||||
|  | 	const colorNormal = '#008FFB'; | ||||||
|  | 	const colorReply = '#FEB019'; | ||||||
|  | 	const colorRenote = '#00E396'; | ||||||
|  | 	const colorFile = '#e300db'; | ||||||
|  | 
 | ||||||
|  | 	function makeDataset(label: string, data: ChartDataset['data'], extra: Partial<ChartDataset> = {}): ChartDataset { | ||||||
|  | 		return Object.assign({ | ||||||
|  | 			label: label, | ||||||
|  | 			data: data, | ||||||
|  | 			parsing: false, | ||||||
|  | 			pointRadius: 0, | ||||||
|  | 			borderWidth: 0, | ||||||
|  | 			borderJoinStyle: 'round', | ||||||
|  | 			borderRadius: 4, | ||||||
|  | 			barPercentage: 0.9, | ||||||
|  | 			fill: true, | ||||||
|  | 		} satisfies ChartDataset, extra); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	chartInstance = new Chart(chartEl, { | ||||||
|  | 		type: 'bar', | ||||||
|  | 		data: { | ||||||
|  | 			datasets: [ | ||||||
|  | 				makeDataset('Normal', format(raw.diffs.normal).slice().reverse(), { backgroundColor: colorNormal }), | ||||||
|  | 				makeDataset('Reply', format(raw.diffs.reply).slice().reverse(), { backgroundColor: colorReply }), | ||||||
|  | 				makeDataset('Renote', format(raw.diffs.renote).slice().reverse(), { backgroundColor: colorRenote }), | ||||||
|  | 				makeDataset('File', format(raw.diffs.withFile).slice().reverse(), { backgroundColor: colorFile }), | ||||||
|  | 			], | ||||||
|  | 		}, | ||||||
|  | 		options: { | ||||||
|  | 			aspectRatio: 3, | ||||||
|  | 			layout: { | ||||||
|  | 				padding: { | ||||||
|  | 					left: 0, | ||||||
|  | 					right: 8, | ||||||
|  | 					top: 0, | ||||||
|  | 					bottom: 0, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			scales: { | ||||||
|  | 				x: { | ||||||
|  | 					type: 'time', | ||||||
|  | 					offset: true, | ||||||
|  | 					stacked: true, | ||||||
|  | 					time: { | ||||||
|  | 						stepSize: 1, | ||||||
|  | 						unit: 'day', | ||||||
|  | 						displayFormats: { | ||||||
|  | 							day: 'M/d', | ||||||
|  | 							month: 'Y/M', | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 					grid: { | ||||||
|  | 						display: false, | ||||||
|  | 					}, | ||||||
|  | 					ticks: { | ||||||
|  | 						display: true, | ||||||
|  | 						maxRotation: 0, | ||||||
|  | 						autoSkipPadding: 8, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 				y: { | ||||||
|  | 					position: 'left', | ||||||
|  | 					stacked: true, | ||||||
|  | 					suggestedMax: 10, | ||||||
|  | 					grid: { | ||||||
|  | 						display: true, | ||||||
|  | 					}, | ||||||
|  | 					ticks: { | ||||||
|  | 						display: true, | ||||||
|  | 						//mirror: true, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			interaction: { | ||||||
|  | 				intersect: false, | ||||||
|  | 				mode: 'index', | ||||||
|  | 			}, | ||||||
|  | 			plugins: { | ||||||
|  | 				legend: { | ||||||
|  | 					display: false, | ||||||
|  | 				}, | ||||||
|  | 				tooltip: { | ||||||
|  | 					enabled: false, | ||||||
|  | 					mode: 'index', | ||||||
|  | 					animation: { | ||||||
|  | 						duration: 0, | ||||||
|  | 					}, | ||||||
|  | 					external: externalTooltipHandler, | ||||||
|  | 				}, | ||||||
|  | 				gradient, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		plugins: [chartVLine(vLineColor), chartLegend(legendEl)], | ||||||
|  | 	}); | ||||||
|  | 
 | ||||||
|  | 	fetching = false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | onMounted(async () => { | ||||||
|  | 	renderChart(); | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <style lang="scss" module> | ||||||
|  | .root { | ||||||
|  | 	padding: 20px; | ||||||
|  | } | ||||||
|  | </style> | ||||||
|  | @ -10,7 +10,7 @@ | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } from 'vue'; | import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } from 'vue'; | ||||||
| import { Chart } from 'chart.js'; | import { Chart, ChartDataset } from 'chart.js'; | ||||||
| import tinycolor from 'tinycolor2'; | import tinycolor from 'tinycolor2'; | ||||||
| import * as misskey from 'misskey-js'; | import * as misskey from 'misskey-js'; | ||||||
| import gradient from 'chartjs-plugin-gradient'; | import gradient from 'chartjs-plugin-gradient'; | ||||||
|  | @ -67,65 +67,33 @@ async function renderChart() { | ||||||
| 	const colorUser2 = '#3498db88'; | 	const colorUser2 = '#3498db88'; | ||||||
| 	const colorVisitor2 = '#2ecc7188'; | 	const colorVisitor2 = '#2ecc7188'; | ||||||
| 
 | 
 | ||||||
|  | 	function makeDataset(label: string, data: ChartDataset['data'], extra: Partial<ChartDataset> = {}): ChartDataset { | ||||||
|  | 		return Object.assign({ | ||||||
|  | 			label: label, | ||||||
|  | 			data: data, | ||||||
|  | 			parsing: false, | ||||||
|  | 			pointRadius: 0, | ||||||
|  | 			borderWidth: 0, | ||||||
|  | 			borderJoinStyle: 'round', | ||||||
|  | 			borderRadius: 4, | ||||||
|  | 			barPercentage: 0.7, | ||||||
|  | 			categoryPercentage: 0.7, | ||||||
|  | 			fill: true, | ||||||
|  | 		} satisfies ChartDataset, extra); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	chartInstance = new Chart(chartEl, { | 	chartInstance = new Chart(chartEl, { | ||||||
| 		type: 'bar', | 		type: 'bar', | ||||||
| 		data: { | 		data: { | ||||||
| 			datasets: [{ | 			datasets: [ | ||||||
| 				parsing: false, | 				makeDataset('UPV (user)', format(raw.upv.user).slice().reverse(), { backgroundColor: colorUser, stack: 'u' }), | ||||||
| 				label: 'UPV (user)', | 				makeDataset('UPV (visitor)', format(raw.upv.visitor).slice().reverse(), { backgroundColor: colorVisitor, stack: 'u' }), | ||||||
| 				data: format(raw.upv.user).slice().reverse(), | 				makeDataset('NPV (user)', format(raw.pv.user).slice().reverse(), { backgroundColor: colorUser2, stack: 'n' }), | ||||||
| 				pointRadius: 0, | 				makeDataset('UPV (visitor)', format(raw.pv.visitor).slice().reverse(), { backgroundColor: colorVisitor2, stack: 'n' }), | ||||||
| 				borderWidth: 0, | 			], | ||||||
| 				borderJoinStyle: 'round', |  | ||||||
| 				borderRadius: 4, |  | ||||||
| 				backgroundColor: colorUser, |  | ||||||
| 				barPercentage: 0.7, |  | ||||||
| 				categoryPercentage: 0.7, |  | ||||||
| 				fill: true, |  | ||||||
| 				stack: 'u', |  | ||||||
| 			}, { |  | ||||||
| 				parsing: false, |  | ||||||
| 				label: 'UPV (visitor)', |  | ||||||
| 				data: format(raw.upv.visitor).slice().reverse(), |  | ||||||
| 				pointRadius: 0, |  | ||||||
| 				borderWidth: 0, |  | ||||||
| 				borderJoinStyle: 'round', |  | ||||||
| 				borderRadius: 4, |  | ||||||
| 				backgroundColor: colorVisitor, |  | ||||||
| 				barPercentage: 0.7, |  | ||||||
| 				categoryPercentage: 0.7, |  | ||||||
| 				fill: true, |  | ||||||
| 				stack: 'u', |  | ||||||
| 			}, { |  | ||||||
| 				parsing: false, |  | ||||||
| 				label: 'NPV (user)', |  | ||||||
| 				data: format(raw.pv.user).slice().reverse(), |  | ||||||
| 				pointRadius: 0, |  | ||||||
| 				borderWidth: 0, |  | ||||||
| 				borderJoinStyle: 'round', |  | ||||||
| 				borderRadius: 4, |  | ||||||
| 				backgroundColor: colorUser2, |  | ||||||
| 				barPercentage: 0.7, |  | ||||||
| 				categoryPercentage: 0.7, |  | ||||||
| 				fill: true, |  | ||||||
| 				stack: 'n', |  | ||||||
| 			}, { |  | ||||||
| 				parsing: false, |  | ||||||
| 				label: 'NPV (visitor)', |  | ||||||
| 				data: format(raw.pv.visitor).slice().reverse(), |  | ||||||
| 				pointRadius: 0, |  | ||||||
| 				borderWidth: 0, |  | ||||||
| 				borderJoinStyle: 'round', |  | ||||||
| 				borderRadius: 4, |  | ||||||
| 				backgroundColor: colorVisitor2, |  | ||||||
| 				barPercentage: 0.7, |  | ||||||
| 				categoryPercentage: 0.7, |  | ||||||
| 				fill: true, |  | ||||||
| 				stack: 'n', |  | ||||||
| 			}], |  | ||||||
| 		}, | 		}, | ||||||
| 		options: { | 		options: { | ||||||
| 			aspectRatio: 2.5, | 			aspectRatio: 3, | ||||||
| 			layout: { | 			layout: { | ||||||
| 				padding: { | 				padding: { | ||||||
| 					left: 0, | 					left: 0, | ||||||
|  |  | ||||||
|  | @ -2,11 +2,19 @@ | ||||||
| <MkSpacer :content-max="700"> | <MkSpacer :content-max="700"> | ||||||
| 	<div class="_gaps"> | 	<div class="_gaps"> | ||||||
| 		<MkFolder class="item"> | 		<MkFolder class="item"> | ||||||
| 			<template #header>Heatmap</template> | 			<template #header><i class="ti ti-activity"></i> Heatmap</template> | ||||||
| 			<XHeatmap :user="user" :src="'notes'"/> | 			<XHeatmap :user="user" :src="'notes'"/> | ||||||
| 		</MkFolder> | 		</MkFolder> | ||||||
| 		<MkFolder class="item"> | 		<MkFolder class="item"> | ||||||
| 			<template #header>PV</template> | 			<template #header><i class="ti ti-pencil"></i> Notes</template> | ||||||
|  | 			<XNotes :user="user"/> | ||||||
|  | 		</MkFolder> | ||||||
|  | 		<MkFolder class="item"> | ||||||
|  | 			<template #header><i class="ti ti-users"></i> Following</template> | ||||||
|  | 			<XFollowing :user="user"/> | ||||||
|  | 		</MkFolder> | ||||||
|  | 		<MkFolder class="item"> | ||||||
|  | 			<template #header><i class="ti ti-eye"></i> PV</template> | ||||||
| 			<XPv :user="user"/> | 			<XPv :user="user"/> | ||||||
| 		</MkFolder> | 		</MkFolder> | ||||||
| 	</div> | 	</div> | ||||||
|  | @ -18,6 +26,8 @@ import { computed } from 'vue'; | ||||||
| import * as misskey from 'misskey-js'; | import * as misskey from 'misskey-js'; | ||||||
| import XHeatmap from './activity.heatmap.vue'; | import XHeatmap from './activity.heatmap.vue'; | ||||||
| import XPv from './activity.pv.vue'; | import XPv from './activity.pv.vue'; | ||||||
|  | import XNotes from './activity.notes.vue'; | ||||||
|  | import XFollowing from './activity.following.vue'; | ||||||
| import MkFolder from '@/components/MkFolder.vue'; | import MkFolder from '@/components/MkFolder.vue'; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ | const props = defineProps<{ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue