トップページデザインを改修
This commit is contained in:
		
							parent
							
								
									fbbc7d005d
								
							
						
					
					
						commit
						feca9940bc
					
				
					 11 changed files with 125 additions and 183 deletions
				
			
		|  | @ -320,6 +320,8 @@ pinnedUsers: "ピン留めユーザー" | |||
| pinnedUsersDescription: "「みつける」ページなどにピン留めしたいユーザーを改行で区切って記述します。" | ||||
| pinnedPages: "ピン留めページ" | ||||
| pinnedPagesDescription: "インスタンスのトップページにピン留めしたいページのパスを改行で区切って記述します。" | ||||
| pinnedClipId: "ピン留めするクリップのID" | ||||
| pinnedNotes: "ピン留めされたノート" | ||||
| hcaptcha: "hCaptcha" | ||||
| enableHcaptcha: "hCaptchaを有効にする" | ||||
| hcaptchaSiteKey: "サイトキー" | ||||
|  |  | |||
							
								
								
									
										14
									
								
								migration/1607151207216-instance-pinned-clip.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								migration/1607151207216-instance-pinned-clip.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| import {MigrationInterface, QueryRunner} from "typeorm"; | ||||
| 
 | ||||
| export class instancePinnedClip1607151207216 implements MigrationInterface { | ||||
|     name = 'instancePinnedClip1607151207216' | ||||
| 
 | ||||
|     public async up(queryRunner: QueryRunner): Promise<void> { | ||||
|         await queryRunner.query(`ALTER TABLE "meta" ADD "pinnedClipId" character varying(32)`); | ||||
|     } | ||||
| 
 | ||||
|     public async down(queryRunner: QueryRunner): Promise<void> { | ||||
|         await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedClipId"`); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -18,6 +18,8 @@ | |||
| 		</div> | ||||
| 	</section> | ||||
| 
 | ||||
| 	<MkInput v-model:value="pinnedClipId">{{ $t('pinnedClipId') }}</MkInput> | ||||
| 
 | ||||
| 	<section class="_card _vMargin"> | ||||
| 		<div class="_content"> | ||||
| 			<MkInput v-model:value="maxNoteTextLength" type="number" :save="() => save()"><template #icon><Fa :icon="faPencilAlt"/></template>{{ $t('maxNoteTextLength') }}</MkInput> | ||||
|  | @ -285,6 +287,7 @@ export default defineComponent({ | |||
| 			blockedHosts: '', | ||||
| 			pinnedUsers: '', | ||||
| 			pinnedPages: '', | ||||
| 			pinnedClipId: null, | ||||
| 			maintainerName: null, | ||||
| 			maintainerEmail: null, | ||||
| 			name: null, | ||||
|  | @ -373,6 +376,7 @@ export default defineComponent({ | |||
| 		this.blockedHosts = this.meta.blockedHosts.join('\n'); | ||||
| 		this.pinnedUsers = this.meta.pinnedUsers.join('\n'); | ||||
| 		this.pinnedPages = this.meta.pinnedPages.join('\n'); | ||||
| 		this.pinnedClipId = this.meta.pinnedClipId; | ||||
| 		this.enableServiceWorker = this.meta.enableServiceWorker; | ||||
| 		this.swPublicKey = this.meta.swPublickey; | ||||
| 		this.swPrivateKey = this.meta.swPrivateKey; | ||||
|  | @ -526,6 +530,7 @@ export default defineComponent({ | |||
| 				blockedHosts: this.blockedHosts.split('\n') || [], | ||||
| 				pinnedUsers: this.pinnedUsers ? this.pinnedUsers.split('\n') : [], | ||||
| 				pinnedPages: this.pinnedPages ? this.pinnedPages.split('\n') : [], | ||||
| 				pinnedClipId: (this.pinnedClipId && this.pinnedClipId) != '' ? this.pinnedClipId : null, | ||||
| 				enableServiceWorker: this.enableServiceWorker, | ||||
| 				swPublicKey: this.swPublicKey, | ||||
| 				swPrivateKey: this.swPrivateKey, | ||||
|  |  | |||
|  | @ -1,142 +0,0 @@ | |||
| <template> | ||||
| <div class="xyeqzsjl _panel"> | ||||
| 	<header> | ||||
| 		<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button> | ||||
| 		<XHeader class="title" :info="pageInfo" :with-back="false"/> | ||||
| 	</header> | ||||
| 	<div> | ||||
| 		<component :is="component" v-bind="props" :ref="changePage"/> | ||||
| 	</div> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
| import { defineComponent } from 'vue'; | ||||
| import { faChevronLeft } from '@fortawesome/free-solid-svg-icons'; | ||||
| import XWindow from '@/components/ui/window.vue'; | ||||
| import XHeader from '@/ui/_common_/header.vue'; | ||||
| import { popout } from '@/scripts/popout'; | ||||
| import { resolve } from '@/router'; | ||||
| import { url } from '@/config'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	components: { | ||||
| 		XWindow, | ||||
| 		XHeader, | ||||
| 	}, | ||||
| 
 | ||||
| 	provide() { | ||||
| 		return { | ||||
| 			navHook: (path) => { | ||||
| 				this.navigate(path); | ||||
| 			} | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
| 	props: { | ||||
| 		initialPath: { | ||||
| 			type: String, | ||||
| 			required: true, | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
| 		return { | ||||
| 			pageInfo: null, | ||||
| 			path: this.initialPath, | ||||
| 			component: null, | ||||
| 			props: null, | ||||
| 			history: [], | ||||
| 			faChevronLeft, | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
| 	computed: { | ||||
| 		url(): string { | ||||
| 			return url + this.path; | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		const { component, props } = resolve(this.initialPath); | ||||
| 		this.component = component; | ||||
| 		this.props = props; | ||||
| 	}, | ||||
| 
 | ||||
| 	methods: { | ||||
| 		changePage(page) { | ||||
| 			if (page == null) return; | ||||
| 			if (page.INFO) { | ||||
| 				this.pageInfo = page.INFO; | ||||
| 			} | ||||
| 		}, | ||||
| 
 | ||||
| 		navigate(path, record = true) { | ||||
| 			if (record) this.history.push(this.path); | ||||
| 			this.path = path; | ||||
| 			const { component, props } = resolve(path); | ||||
| 			this.component = component; | ||||
| 			this.props = props; | ||||
| 		}, | ||||
| 
 | ||||
| 		back() { | ||||
| 			this.navigate(this.history.pop(), false); | ||||
| 		}, | ||||
| 
 | ||||
| 		expand() { | ||||
| 			this.$router.push(this.path); | ||||
| 			this.$refs.window.close(); | ||||
| 		}, | ||||
| 
 | ||||
| 		popout() { | ||||
| 			popout(this.path, this.$el); | ||||
| 			this.$refs.window.close(); | ||||
| 		}, | ||||
| 	}, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .xyeqzsjl { | ||||
| 	--section-padding: 16px; | ||||
| 
 | ||||
| 	display: flex; | ||||
| 	flex-direction: column; | ||||
| 	contain: content; | ||||
| 
 | ||||
| 	> header { | ||||
| 		$height: 50px; | ||||
| 		display: flex; | ||||
| 		position: relative; | ||||
| 		z-index: 1; | ||||
| 		height: $height; | ||||
| 		line-height: $height; | ||||
| 		box-shadow: 0px 1px var(--divider); | ||||
| 
 | ||||
| 		> button { | ||||
| 			height: $height; | ||||
| 			width: $height; | ||||
| 
 | ||||
| 			&:hover { | ||||
| 				color: var(--fgHighlighted); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		> .title { | ||||
| 			flex: 1; | ||||
| 			position: relative; | ||||
| 			line-height: $height; | ||||
| 			white-space: nowrap; | ||||
| 			overflow: hidden; | ||||
| 			text-overflow: ellipsis; | ||||
| 			text-align: center; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> div { | ||||
| 		flex: 1; | ||||
| 		overflow: auto; | ||||
| 		background: var(--bg); | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -1,8 +1,9 @@ | |||
| <template> | ||||
| <div class="rsqzvsbo _section" v-if="meta"> | ||||
| 	<div class="blocks"> | ||||
| 		<XBlock class="block" v-for="path in meta.pinnedPages" :initial-path="path" :key="path"/> | ||||
| 	</div> | ||||
| 	<h2># {{ $t('pinnedNotes') }}</h2> | ||||
| 	<MkPagination :pagination="pagination" #default="{items}"> | ||||
| 		<XNote class="kmkqjgkl" v-for="note in items" :note="note" :key="note.id"/> | ||||
| 	</MkPagination> | ||||
| </div> | ||||
| </template> | ||||
| 
 | ||||
|  | @ -12,16 +13,16 @@ import { toUnicode } from 'punycode'; | |||
| import XSigninDialog from '@/components/signin-dialog.vue'; | ||||
| import XSignupDialog from '@/components/signup-dialog.vue'; | ||||
| import MkButton from '@/components/ui/button.vue'; | ||||
| import XNotes from '@/components/notes.vue'; | ||||
| import XBlock from './welcome.entrance.block.vue'; | ||||
| import XNote from '@/components/note.vue'; | ||||
| import MkPagination from '@/components/ui/pagination.vue'; | ||||
| import { host, instanceName } from '@/config'; | ||||
| import * as os from '@/os'; | ||||
| 
 | ||||
| export default defineComponent({ | ||||
| 	components: { | ||||
| 		MkButton, | ||||
| 		XNotes, | ||||
| 		XBlock, | ||||
| 		XNote, | ||||
| 		MkPagination, | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
|  | @ -29,6 +30,13 @@ export default defineComponent({ | |||
| 			host: toUnicode(host), | ||||
| 			instanceName, | ||||
| 			meta: null, | ||||
| 			pagination: { | ||||
| 				endpoint: 'clips/notes', | ||||
| 				limit: 10, | ||||
| 				params: () => ({ | ||||
| 					clipId: this.meta.pinnedClipId, | ||||
| 				}) | ||||
| 			}, | ||||
| 		}; | ||||
| 	}, | ||||
| 
 | ||||
|  | @ -62,19 +70,28 @@ export default defineComponent({ | |||
| .rsqzvsbo { | ||||
| 	text-align: center; | ||||
| 
 | ||||
| 	> .blocks { | ||||
| 		display: grid; | ||||
| 		grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); | ||||
| 		grid-gap: var(--margin); | ||||
| 		text-align: left; | ||||
| 
 | ||||
| 		> .block { | ||||
| 			height: 600px; | ||||
| 	> h2 { | ||||
| 		display: inline-block; | ||||
| 		color: #fff; | ||||
| 		margin: 16px; | ||||
| 		padding: 8px 12px; | ||||
| 		background: rgba(0, 0, 0, 0.5); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .kmkqjgkl { | ||||
| 	display: inline-block; | ||||
| 	vertical-align: middle; | ||||
| 	width: 600px; | ||||
| 	margin: 16px; | ||||
| 	text-align: left; | ||||
| 	box-shadow: 0 6px 46px rgb(0 0 0 / 30%); | ||||
| 	border-radius: 12px; | ||||
| 
 | ||||
| 	@media (max-width: 800px) { | ||||
| 			grid-template-columns: 1fr; | ||||
| 		} | ||||
| 		display: block; | ||||
| 		width: 100%; | ||||
| 		margin: 12px 0; | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| :root { | ||||
| 	--baseContentWidth: 760px; | ||||
| 	--radius: 8px; | ||||
| 	--radius: 12px; | ||||
| 	--marginFull: 16px; | ||||
| 	--marginHalf: 10px; | ||||
| 
 | ||||
|  | @ -320,6 +320,7 @@ hr { | |||
| ._popup { | ||||
| 	background: var(--panel); | ||||
| 	border-radius: var(--radius); | ||||
| 	contain: content; | ||||
| } | ||||
| 
 | ||||
| ._section { | ||||
|  |  | |||
|  | @ -1,14 +1,14 @@ | |||
| <template> | ||||
| <div class="mk-app"> | ||||
| 	<div class="side" v-if="!narrow && $route.path !== '/'"> | ||||
| 		<XKanban class="kanban" full/> | ||||
| <div class="mk-app" :style="{ backgroundImage: root ? `url(${ $store.state.instance.meta.backgroundImageUrl })` : 'none' }"> | ||||
| 	<div class="side" v-if="!narrow"> | ||||
| 		<XKanban class="kanban" full :transparent="root" :powered-by="root"/> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div class="main"> | ||||
| 		<XKanban class="banner" :full="$route.path === '/'" v-if="narrow || $route.path === '/'"/> | ||||
| 		<XKanban class="banner" :full="root" :transparent="root" :powered-by="root" v-if="narrow"/> | ||||
| 
 | ||||
| 		<div class="contents"> | ||||
| 			<XHeader class="header" :info="pageInfo" v-if="$route.path !== '/'"/> | ||||
| 			<XHeader class="header" :info="pageInfo" v-if="!root"/> | ||||
| 			<main> | ||||
| 				<router-view v-slot="{ Component }"> | ||||
| 					<transition :name="$store.state.device.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> | ||||
|  | @ -16,7 +16,7 @@ | |||
| 					</transition> | ||||
| 				</router-view> | ||||
| 			</main> | ||||
| 			<div class="powered-by"> | ||||
| 			<div class="powered-by" v-if="!root"> | ||||
| 				<b><MkA to="/">{{ host }}</MkA></b> | ||||
| 				<small>Powered by <a href="https://github.com/syuilo/misskey" target="_blank">Misskey</a></small> | ||||
| 			</div> | ||||
|  | @ -97,6 +97,10 @@ export default defineComponent({ | |||
| 				'h|/': this.help | ||||
| 			}; | ||||
| 		}, | ||||
| 
 | ||||
| 		root(): boolean { | ||||
| 			return this.$route.path === '/'; | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	watch: { | ||||
|  | @ -182,6 +186,9 @@ export default defineComponent({ | |||
| .mk-app { | ||||
| 	display: flex; | ||||
| 	min-height: 100vh; | ||||
| 	background-position: center; | ||||
| 	background-size: cover; | ||||
| 	background-attachment: fixed; | ||||
| 
 | ||||
| 	> .side { | ||||
| 		width: 500px; | ||||
|  | @ -199,6 +206,7 @@ export default defineComponent({ | |||
| 
 | ||||
| 	> .main { | ||||
| 		flex: 1; | ||||
| 		min-width: 0; | ||||
| 
 | ||||
| 		> .banner { | ||||
| 		} | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| <template> | ||||
| <div class="rwqkcmrc" :style="{ backgroundImage: `url(${ $store.state.instance.meta.backgroundImageUrl })` }"> | ||||
| 	<div class="back"></div> | ||||
| 	<div class="fade" v-if="full"></div> | ||||
| <div class="rwqkcmrc" :style="{ backgroundImage: transparent ? 'none' : `url(${ $store.state.instance.meta.backgroundImageUrl })` }"> | ||||
| 	<div class="back" :class="{ transparent }"></div> | ||||
| 	<div class="contents"> | ||||
| 		<div class="wrapper"> | ||||
| 			<h1 v-if="meta" :class="{ full }"> | ||||
|  | @ -27,6 +26,10 @@ | |||
| 						</section> | ||||
| 					</MkPagination> | ||||
| 				</div> | ||||
| 				<div class="powered-by" v-if="poweredBy"> | ||||
| 					<b><MkA to="/">{{ host }}</MkA></b> | ||||
| 					<small>Powered by <a href="https://github.com/syuilo/misskey" target="_blank">Misskey</a></small> | ||||
| 				</div> | ||||
| 			</template> | ||||
| 		</div> | ||||
| 	</div> | ||||
|  | @ -54,7 +57,17 @@ export default defineComponent({ | |||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false, | ||||
| 		} | ||||
| 		}, | ||||
| 		transparent: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false, | ||||
| 		}, | ||||
| 		poweredBy: { | ||||
| 			type: Boolean, | ||||
| 			required: false, | ||||
| 			default: false, | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	data() { | ||||
|  | @ -107,17 +120,12 @@ export default defineComponent({ | |||
| 		left: 0; | ||||
| 		width: 100%; | ||||
| 		height: 100%; | ||||
| 		background: var(--bg); | ||||
| 		opacity: 0.5; | ||||
| 	} | ||||
| 		background: rgba(0, 0, 0, 0.3); | ||||
| 
 | ||||
| 	> .fade { | ||||
| 		position: absolute; | ||||
| 		top: 0; | ||||
| 		left: 0; | ||||
| 		width: 100%; | ||||
| 		height: 300px; | ||||
| 		background: linear-gradient(rgba(#000, 0.5), transparent); | ||||
| 		&.transparent { | ||||
| 			-webkit-backdrop-filter: blur(12px); | ||||
| 			backdrop-filter: blur(12px); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> .contents { | ||||
|  | @ -223,6 +231,20 @@ export default defineComponent({ | |||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			> .powered-by { | ||||
| 				padding: 28px; | ||||
| 				font-size: 14px; | ||||
| 				text-align: center; | ||||
| 				border-top: 1px solid rgba(255, 255, 255, 0.5); | ||||
| 				color: #fff; | ||||
| 
 | ||||
| 				> small { | ||||
| 					display: block; | ||||
| 					margin-top: 8px; | ||||
| 					opacity: 0.5; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm'; | ||||
| import { User } from './user'; | ||||
| import { id } from '../id'; | ||||
| import { Clip } from './clip'; | ||||
| 
 | ||||
| @Entity() | ||||
| export class Meta { | ||||
|  | @ -81,6 +82,12 @@ export class Meta { | |||
| 	}) | ||||
| 	public pinnedPages: string[]; | ||||
| 
 | ||||
| 	@Column({ | ||||
| 		...id(), | ||||
| 		nullable: true, | ||||
| 	}) | ||||
| 	public pinnedClipId: Clip['id'] | null; | ||||
| 
 | ||||
| 	@Column('varchar', { | ||||
| 		length: 512, | ||||
| 		nullable: true, | ||||
|  |  | |||
|  | @ -220,6 +220,10 @@ export const meta = { | |||
| 			validator: $.optional.arr($.str), | ||||
| 		}, | ||||
| 
 | ||||
| 		pinnedClipId: { | ||||
| 			validator: $.optional.nullable.type(ID), | ||||
| 		}, | ||||
| 
 | ||||
| 		langs: { | ||||
| 			validator: $.optional.arr($.str), | ||||
| 			desc: { | ||||
|  | @ -561,6 +565,10 @@ export default define(meta, async (ps, me) => { | |||
| 		set.pinnedPages = ps.pinnedPages.filter(Boolean); | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps.pinnedClipId !== undefined) { | ||||
| 		set.pinnedClipId = ps.pinnedClipId; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps.summalyProxy !== undefined) { | ||||
| 		set.summalyProxy = ps.summalyProxy; | ||||
| 	} | ||||
|  |  | |||
|  | @ -142,7 +142,7 @@ export default define(meta, async (ps, me) => { | |||
| 		enableServiceWorker: instance.enableServiceWorker, | ||||
| 
 | ||||
| 		...(ps.detail ? { | ||||
| 			pinnedPages: instance.pinnedPages, | ||||
| 			pinnedClipId: instance.pinnedClipId, | ||||
| 			cacheRemoteFiles: instance.cacheRemoteFiles, | ||||
| 			proxyRemoteFiles: instance.proxyRemoteFiles, | ||||
| 			requireSetup: (await Users.count({ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue