diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 7d8ba1753f..ecba573bae 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1104,6 +1104,7 @@ _pages: created: "ページを作成しました" updated: "ページを更新しました" deleted: "ページを削除しました" + pageSetting: "ページ設定" nameAlreadyExists: "指定されたページURLは既に存在しています" invalidNameTitle: "不正なページURLです" invalidNameText: "空白でないか確認してください" @@ -1115,6 +1116,7 @@ _pages: my: "自分のページ" liked: "いいねしたページ" inspector: "インスペクター" + contents: "コンテンツ" content: "ページブロック" variables: "変数" title: "タイトル" @@ -1175,6 +1177,11 @@ _pages: width: "幅" height: "高さ" + note: "ノート埋め込み" + _note: + id: "ノートID" + idDescription: "ノートURLをペーストして設定することもできます。" + switch: "スイッチ" _switch: name: "変数名" diff --git a/src/client/components/page-preview.vue b/src/client/components/page-preview.vue index 95ed8d0e38..d59813e00d 100644 --- a/src/client/components/page-preview.vue +++ b/src/client/components/page-preview.vue @@ -1,5 +1,5 @@ <template> -<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1"> +<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj _panel" tabindex="-1"> <div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div> <article> <header> @@ -35,16 +35,11 @@ export default defineComponent({ <style lang="scss" scoped> .vhpxefrj { display: block; - overflow: hidden; width: 100%; - border: solid var(--lineWidth) var(--urlPreviewBorder); - border-radius: 4px; - overflow: hidden; - border: 1px solid var(--divider); &:hover { text-decoration: none; - border-color: var(--urlPreviewBorderHover); + color: var(--accent); } > .thumbnail { diff --git a/src/client/components/page/page.block.vue b/src/client/components/page/page.block.vue index 412c91ee0d..be933c8623 100644 --- a/src/client/components/page/page.block.vue +++ b/src/client/components/page/page.block.vue @@ -18,10 +18,11 @@ import XPost from './page.post.vue'; import XCounter from './page.counter.vue'; import XRadioButton from './page.radio-button.vue'; import XCanvas from './page.canvas.vue'; +import XNote from './page.note.vue'; export default defineComponent({ components: { - XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas + XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton, XCanvas, XNote }, props: { value: { diff --git a/src/client/components/page/page.note.vue b/src/client/components/page/page.note.vue new file mode 100644 index 0000000000..4f1df77675 --- /dev/null +++ b/src/client/components/page/page.note.vue @@ -0,0 +1,39 @@ +<template> +<div class="voxdxuby"> + <XNote v-if="note" v-model:note="note" :key="note.id"/> +</div> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import XNote from '@/components/note.vue'; +import * as os from '@/os'; + +export default defineComponent({ + components: { + XNote + }, + props: { + value: { + required: true + }, + hpml: { + required: true + } + }, + data() { + return { + note: null, + }; + }, + async mounted() { + this.note = await os.api('notes/show', { noteId: this.value.note }); + } +}); +</script> + +<style lang="scss" scoped> +.voxdxuby { + margin: 1em 0; +} +</style> diff --git a/src/client/pages/page-editor/els/page-editor.el.note.vue b/src/client/pages/page-editor/els/page-editor.el.note.vue new file mode 100644 index 0000000000..d80623a63e --- /dev/null +++ b/src/client/pages/page-editor/els/page-editor.el.note.vue @@ -0,0 +1,62 @@ +<template> +<XContainer @remove="() => $emit('remove')" :draggable="true"> + <template #header><Fa :icon="faStickyNote"/> {{ $t('_pages.blocks.note') }}</template> + + <section style="padding: 0 16px 0 16px;"> + <MkInput v-model:value="id"> + <span>{{ $t('_pages.blocks._note.id') }}</span> + <template #desc>{{ $t('_pages.blocks._note.idDescription') }}</template> + </MkInput> + + <XNote v-if="note" v-model:note="note" :key="note.id" style="margin-bottom: 16px;"/> + </section> +</XContainer> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import { faStickyNote } from '@fortawesome/free-solid-svg-icons'; +import XContainer from '../page-editor.container.vue'; +import MkInput from '@/components/ui/input.vue'; +import XNote from '@/components/note.vue'; +import * as os from '@/os'; + +export default defineComponent({ + components: { + XContainer, MkInput, XNote + }, + + props: { + value: { + required: true + }, + }, + + data() { + return { + id: this.value.note, + note: null, + faStickyNote + }; + }, + + watch: { + id: { + async handler() { + if (this.id && (this.id.startsWith('http://') || this.id.startsWith('https://'))) { + this.value.note = this.id.endsWith('/') ? this.id.substr(0, this.id.length - 1).split('/').pop() : this.id.split('/').pop(); + } else { + this.value.note = this.id; + } + + this.note = await os.api('notes/show', { noteId: this.value.note }); + }, + immediate: true + }, + }, + + created() { + if (this.value.note == null) this.value.note = null; + }, +}); +</script> diff --git a/src/client/pages/page-editor/page-editor.blocks.vue b/src/client/pages/page-editor/page-editor.blocks.vue index 48e7fde404..5cf9eb42f7 100644 --- a/src/client/pages/page-editor/page-editor.blocks.vue +++ b/src/client/pages/page-editor/page-editor.blocks.vue @@ -20,12 +20,13 @@ import XPost from './els/page-editor.el.post.vue'; import XCounter from './els/page-editor.el.counter.vue'; import XRadioButton from './els/page-editor.el.radio-button.vue'; import XCanvas from './els/page-editor.el.canvas.vue'; +import XNote from './els/page-editor.el.note.vue'; import * as os from '@/os'; export default defineComponent({ components: { XDraggable: defineAsyncComponent(() => import('vue-draggable-next').then(x => x.VueDraggableNext)), - XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas + XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton, XCanvas, XNote }, props: { diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue index cd033219f0..30146b56ed 100644 --- a/src/client/pages/page-editor/page-editor.vue +++ b/src/client/pages/page-editor/page-editor.vue @@ -1,57 +1,54 @@ <template> <div class="_section"> <div class="_content"> - <div class="gwbmwxkm _panel _vMargin"> - <header> - <div class="title"><Fa :icon="faStickyNote"/> {{ readonly ? $t('_pages.readPage') : pageId ? $t('_pages.editPage') : $t('_pages.newPage') }}</div> - <div class="buttons"> - <button class="_button" @click="del()" v-if="!readonly"><Fa :icon="faTrashAlt"/></button> - <button class="_button" @click="() => showOptions = !showOptions"><Fa :icon="faCog"/></button> - <button class="_button" @click="save()" v-if="!readonly"><Fa :icon="faSave"/></button> - </div> - </header> + <MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $t('_pages.viewPage') }}</MkA> - <section> - <MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $t('_pages.viewPage') }}</MkA> + <MkButton @click="save" primary class="save" style="margin: 16px auto 16px auto;"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton> + <MkContainer :body-togglable="true" :expanded="true" class="_vMargin"> + <template #header><Fa :icon="faCog"/> {{ $t('_pages.pageSetting') }}</template> + <div class="_section"> <MkInput v-model:value="title"> <span>{{ $t('_pages.title') }}</span> </MkInput> - <template v-if="showOptions"> - <MkInput v-model:value="summary"> - <span>{{ $t('_pages.summary') }}</span> - </MkInput> + <MkInput v-model:value="summary"> + <span>{{ $t('_pages.summary') }}</span> + </MkInput> - <MkInput v-model:value="name"> - <template #prefix>{{ url }}/@{{ author.username }}/pages/</template> - <span>{{ $t('_pages.url') }}</span> - </MkInput> + <MkInput v-model:value="name"> + <template #prefix>{{ url }}/@{{ author.username }}/pages/</template> + <span>{{ $t('_pages.url') }}</span> + </MkInput> - <MkSwitch v-model:value="alignCenter">{{ $t('_pages.alignCenter') }}</MkSwitch> + <MkSwitch v-model:value="alignCenter">{{ $t('_pages.alignCenter') }}</MkSwitch> - <MkSelect v-model:value="font"> - <template #label>{{ $t('_pages.font') }}</template> - <option value="serif">{{ $t('_pages.fontSerif') }}</option> - <option value="sans-serif">{{ $t('_pages.fontSansSerif') }}</option> - </MkSelect> + <MkSelect v-model:value="font"> + <template #label>{{ $t('_pages.font') }}</template> + <option value="serif">{{ $t('_pages.fontSerif') }}</option> + <option value="sans-serif">{{ $t('_pages.fontSansSerif') }}</option> + </MkSelect> - <MkSwitch v-model:value="hideTitleWhenPinned">{{ $t('_pages.hideTitleWhenPinned') }}</MkSwitch> + <MkSwitch v-model:value="hideTitleWhenPinned">{{ $t('_pages.hideTitleWhenPinned') }}</MkSwitch> - <div class="eyeCatch"> - <MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage()"><Fa :icon="faPlus"/> {{ $t('_pages.eyeCatchingImageSet') }}</MkButton> - <div v-else-if="eyeCatchingImage"> - <img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name"/> - <MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><Fa :icon="faTrashAlt"/> {{ $t('_pages.eyeCatchingImageRemove') }}</MkButton> - </div> + <div class="eyeCatch"> + <MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><Fa :icon="faPlus"/> {{ $t('_pages.eyeCatchingImageSet') }}</MkButton> + <div v-else-if="eyeCatchingImage"> + <img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/> + <MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><Fa :icon="faTrashAlt"/> {{ $t('_pages.eyeCatchingImageRemove') }}</MkButton> </div> - </template> + </div> + </div> + </MkContainer> + <MkContainer :body-togglable="true" :expanded="true" class="_vMargin"> + <template #header><Fa :icon="faStickyNote"/> {{ $t('_pages.contents') }}</template> + <div class="_section"> <XBlocks class="content" v-model:value="content" :hpml="hpml"/> <MkButton @click="add()" v-if="!readonly"><Fa :icon="faPlus"/></MkButton> - </section> - </div> + </div> + </MkContainer> <MkContainer :body-togglable="true" class="_vMargin"> <template #header><Fa :icon="faMagic"/> {{ $t('_pages.variables') }}</template> @@ -85,14 +82,14 @@ </template> <script lang="ts"> -import { defineComponent, defineAsyncComponent } from 'vue'; +import { defineComponent, defineAsyncComponent, computed } from 'vue'; import 'prismjs'; import { highlight, languages } from 'prismjs/components/prism-core'; import 'prismjs/components/prism-clike'; import 'prismjs/components/prism-javascript'; import 'prismjs/themes/prism-okaidia.css'; import 'vue-prism-editor/dist/prismeditor.min.css'; -import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons'; +import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt, faPencilAlt } from '@fortawesome/free-solid-svg-icons'; import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons'; import { v4 as uuid } from 'uuid'; import XVariable from './page-editor.script-block.vue'; @@ -108,6 +105,7 @@ import { HpmlTypeChecker } from '@/scripts/hpml/type-checker'; import { url } from '@/config'; import { collectPageVars } from '@/scripts/collect-page-vars'; import * as os from '@/os'; +import { selectFile } from '@/scripts/select-file'; export default defineComponent({ components: { @@ -132,6 +130,13 @@ export default defineComponent({ data() { return { + INFO: computed(() => this.initPageId ? { + title: this.$t('_pages.editPage'), + icon: faPencilAlt, + } : { + title: this.$t('_pages.newPage'), + icon: faPencilAlt, + }), author: this.$store.state.i, readonly: false, page: null, @@ -149,7 +154,6 @@ export default defineComponent({ variables: [], hpml: null, script: '', - showOptions: false, url, faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode }; @@ -353,6 +357,7 @@ export default defineComponent({ { value: 'text', text: this.$t('_pages.blocks.text') }, { value: 'image', text: this.$t('_pages.blocks.image') }, { value: 'textarea', text: this.$t('_pages.blocks.textarea') }, + { value: 'note', text: this.$t('_pages.blocks.note') }, { value: 'canvas', text: this.$t('_pages.blocks.canvas') }, ] }, { @@ -413,8 +418,8 @@ export default defineComponent({ return list; }, - setEyeCatchingImage() { - os.selectDriveFile(false).then(file => { + setEyeCatchingImage(e) { + selectFile(e.currentTarget || e.target, null, false).then(file => { this.eyeCatchingImageId = file.id; }); },