pref: remove unused file
This commit is contained in:
parent
14b55bd472
commit
4a7e1ed69e
|
@ -180,7 +180,7 @@ useEditor((root) =>
|
|||
|
||||
ul li,
|
||||
ol li {
|
||||
color: var(--kungalgame-blue-4);
|
||||
color: var(--kungalgame-blue-5);
|
||||
}
|
||||
|
||||
.tableWrapper {
|
||||
|
|
|
@ -1,141 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
// Global message component (top)
|
||||
import Message from '@/components/alert/Message'
|
||||
|
||||
// Import the router
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
// Import the icon font
|
||||
import { Icon } from '@iconify/vue'
|
||||
|
||||
// Import CSS animations
|
||||
import 'animate.css'
|
||||
|
||||
const router = useRouter()
|
||||
// Current route
|
||||
const route = useRoute()
|
||||
// Name of the current page route
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// Adjust the background color based on the mouse coordinates
|
||||
const x = ref(0)
|
||||
// Whether to display information prompts
|
||||
const isShowInfo = ref(false)
|
||||
|
||||
// When the mouse moves
|
||||
const onMousemove = (e: MouseEvent) => {
|
||||
x.value = e.clientX
|
||||
}
|
||||
|
||||
// Click the help button
|
||||
const handleClickHelp = () => {
|
||||
if (routeName.value === 'Edit') {
|
||||
isShowInfo.value = true
|
||||
} else {
|
||||
const helpHtmlEN = `<p>You can click on the left settings to adjust the editor's mode.</p>
|
||||
<p>We recommend finishing your text before formatting.</p>
|
||||
<p>The website's code is handwritten, and errors are inevitable.</p>
|
||||
<p>If you encounter any errors, please <a style="color: var(--kungalgame-blue-4); border-bottom: 2px solid var(--kungalgame-blue-4);" href="/contact">Contact Us</a>.</p>`
|
||||
const helpHtmlCN = `<p>您可以点击左侧的设置调整编辑器的模式</p>
|
||||
<p>我们建议您写完文本再进行格式化</p>
|
||||
<p>网站的代码是手写的,错误在所难免</p>
|
||||
<p>如果您遇到错误,请<a style="color: var(--kungalgame-blue-4); border-bottom: 2px solid var(--kungalgame-blue-4);" href="/contact">联系我们</a></p>`
|
||||
|
||||
Message(helpHtmlEN, helpHtmlCN, 'info', 5000)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="help">
|
||||
<div class="title" @click="handleClickHelp">
|
||||
<span><Icon icon="line-md:question-circle" /></span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isShowInfo"
|
||||
@mousemove="onMousemove"
|
||||
@mouseleave="isShowInfo = false"
|
||||
class="info"
|
||||
:style="{ backgroundColor: `hsl(${x}, 77%, 77%)` }"
|
||||
>
|
||||
<ul>
|
||||
<li>{{ $tm('edit.help1') }}</li>
|
||||
<li>{{ $tm('edit.help2') }}</li>
|
||||
<li>{{ $tm('edit.help3') }}</li>
|
||||
<li>{{ $tm('edit.help4') }}</li>
|
||||
<li>
|
||||
{{ $tm('edit.help5') }}
|
||||
<span @click="router.push('/contact')">
|
||||
{{ $tm('edit.contact') }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.help {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title {
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
color: var(--kungalgame-font-color-1);
|
||||
font-size: 23px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
padding: 3px;
|
||||
color: var(--kungalgame-font-color-2);
|
||||
position: absolute;
|
||||
left: 200px;
|
||||
transition: 0.3s background-color ease;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--kungalgame-white);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
li {
|
||||
&::before {
|
||||
content: '❆ ';
|
||||
color: var(--kungalgame-pink-3);
|
||||
}
|
||||
|
||||
cursor: default;
|
||||
font-size: 15px;
|
||||
line-height: 27px;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
color: var(--kungalgame-blue-4);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,11 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue'
|
||||
import { computed, defineAsyncComponent, ref } from 'vue'
|
||||
// Import the router
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
// Import icon font
|
||||
import { Icon } from '@iconify/vue'
|
||||
|
||||
// Asynchronously import the editor settings menu
|
||||
const EditorSettingsMenu = defineAsyncComponent(
|
||||
() => import('./EditorSettingsMenu.vue')
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, defineAsyncComponent, ref } from 'vue'
|
||||
// Import the router
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
// Import icon font
|
||||
import { Icon } from '@iconify/vue'
|
||||
|
||||
// Asynchronously import the editor settings menu
|
||||
const EditorSettingsMenu = defineAsyncComponent(
|
||||
() => import('./EditorSettingsMenu.vue')
|
||||
)
|
||||
// Import CSS animations
|
||||
import 'animate.css'
|
||||
|
||||
// Import the topic editing store
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// Topic editing page store
|
||||
const { textCount } = storeToRefs(useKUNGalgameEditStore())
|
||||
// Topic page store for replies and adjusting reply panel width
|
||||
const { replyDraft, replyPanelWidth } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
// Current route
|
||||
const route = useRoute()
|
||||
// Name of the current page route
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
const textCountNumber = computed(() =>
|
||||
routeName.value === 'Edit' ? textCount.value : replyDraft.value.textCount
|
||||
)
|
||||
|
||||
// Whether to display the editor settings panel
|
||||
const isShowSettingsMenu = ref(false)
|
||||
// Style when the settings panel is activated
|
||||
const settingsPanelActive = ref('')
|
||||
|
||||
// Click the settings button
|
||||
const handelClickSettings = () => {
|
||||
isShowSettingsMenu.value = !isShowSettingsMenu.value
|
||||
if (isShowSettingsMenu.value) {
|
||||
settingsPanelActive.value = 'settings-icon-active'
|
||||
} else {
|
||||
settingsPanelActive.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// Close the panel emits
|
||||
const handelCloseSettingsMenu = () => {
|
||||
isShowSettingsMenu.value = false
|
||||
settingsPanelActive.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="footer">
|
||||
<!-- Display the settings button -->
|
||||
<div class="settings">
|
||||
<span
|
||||
@click="handelClickSettings"
|
||||
class="settings-icon"
|
||||
:class="settingsPanelActive"
|
||||
>
|
||||
<Icon icon="uiw:setting-o" />
|
||||
</span>
|
||||
|
||||
<!-- Help slot -->
|
||||
<slot name="help" />
|
||||
<input
|
||||
v-if="routeName === 'Topic'"
|
||||
class="panel-width"
|
||||
type="range"
|
||||
min="50"
|
||||
max="100"
|
||||
step="1"
|
||||
v-model="replyPanelWidth"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Word count -->
|
||||
<span class="count">{{ textCountNumber + ` ${$tm('edit.word')}` }}</span>
|
||||
|
||||
<!-- Settings panel -->
|
||||
<EditorSettingsMenu
|
||||
@close="handelCloseSettingsMenu"
|
||||
:isShowSettingsMenu="isShowSettingsMenu"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.footer {
|
||||
padding: 10px 17px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.settings {
|
||||
color: var(--kungalgame-font-color-1);
|
||||
font-size: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.settings-icon {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.help {
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
color: var(--kungalgame-font-color-1);
|
||||
font-size: 23px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: 3px;
|
||||
color: var(--kungalgame-font-color-2);
|
||||
position: absolute;
|
||||
left: 200px;
|
||||
transition: 0.3s background-color ease;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--kungalgame-white);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
li {
|
||||
&::before {
|
||||
content: '❆ ';
|
||||
color: var(--kungalgame-pink-3);
|
||||
}
|
||||
|
||||
cursor: default;
|
||||
font-size: 15px;
|
||||
line-height: 27px;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
color: var(--kungalgame-blue-4);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.panel-width {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
color: var(--kungalgame-font-color-0);
|
||||
background-color: var(--kungalgame-trans-white-9);
|
||||
}
|
||||
|
||||
// Keep the settings button rotating when activated.
|
||||
.settings-icon-active {
|
||||
color: var(--kungalgame-blue-4);
|
||||
animation: settings 3s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes settings {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,249 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
// Import the icon font
|
||||
import { Icon } from '@iconify/vue'
|
||||
// Import CSS animations
|
||||
import 'animate.css'
|
||||
|
||||
// Import the topic editing store
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
// Import the reply store
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// Import the keyword display toggle button
|
||||
import SwitchButton from './SwitchButton.vue'
|
||||
|
||||
// Topic editing page store
|
||||
const { editorHeight, mode } = storeToRefs(useKUNGalgameEditStore())
|
||||
// Topic page store for replies
|
||||
const { replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
defineProps<{
|
||||
isShowSettingsMenu: boolean
|
||||
}>()
|
||||
|
||||
// Define emits to close the settings panel
|
||||
const emits = defineEmits<{
|
||||
close: [isShowSettingsMenu: boolean]
|
||||
}>()
|
||||
|
||||
// Current route
|
||||
const route = useRoute()
|
||||
// Name of the current page route
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// Whether to refresh the page when clicking advanced options
|
||||
const isRefreshPage = ref(false)
|
||||
|
||||
// Remind the user to refresh the page when clicking on advanced options
|
||||
watch(
|
||||
() => [replyDraft.value.mode, mode.value],
|
||||
() => {
|
||||
isRefreshPage.value = true
|
||||
}
|
||||
)
|
||||
|
||||
const handleRefreshPage = () => location.reload()
|
||||
|
||||
// Close the settings panel
|
||||
const handelCloseSettingsPanel = () => {
|
||||
emits('close', false)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__jackInTheBox animate__faster"
|
||||
leave-active-class="animate__animated animate__rollOut animate__faster"
|
||||
>
|
||||
<!-- Settings menu -->
|
||||
<div v-if="isShowSettingsMenu" class="settings-menu">
|
||||
<div class="content">
|
||||
<!-- Editor height settings -->
|
||||
<div class="editor-height-title">
|
||||
<span> {{ $tm('edit.editorHeight') }} </span>
|
||||
<span>{{ editorHeight }} px</span>
|
||||
</div>
|
||||
|
||||
<!-- Editor page -->
|
||||
<div v-if="routeName === 'Edit'" class="editor-height">
|
||||
<span>300 px</span>
|
||||
<input
|
||||
type="range"
|
||||
min="300"
|
||||
max="500"
|
||||
step="1"
|
||||
v-model="editorHeight"
|
||||
/>
|
||||
<span>500 px</span>
|
||||
</div>
|
||||
|
||||
<!-- Reply panel -->
|
||||
<div v-if="routeName === 'Topic'" class="editor-height">
|
||||
<span>100 px</span>
|
||||
<input
|
||||
type="range"
|
||||
min="100"
|
||||
max="500"
|
||||
step="1"
|
||||
v-model="replyDraft.editorHeight"
|
||||
/>
|
||||
<span>500 px</span>
|
||||
</div>
|
||||
|
||||
<!-- Whether to display editor advanced options -->
|
||||
<div class="editor-advance">
|
||||
<div class="editor-advance-title">
|
||||
<Transition mode="out-in" name="slide-up">
|
||||
<span v-if="!isRefreshPage"> {{ $tm('edit.editorMode') }} </span>
|
||||
<span
|
||||
@click="handleRefreshPage"
|
||||
class="refresh"
|
||||
v-else-if="isRefreshPage"
|
||||
>
|
||||
{{ $tm('edit.refresh') }}
|
||||
</span>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<!-- Editor page switch button -->
|
||||
<select class="select" v-if="routeName === 'Edit'" v-model="mode">
|
||||
<option value="minimal">{{ $tm('edit.minimal') }}</option>
|
||||
<option value="">{{ $tm('edit.default') }}</option>
|
||||
<option value="essential">{{ $tm('edit.essential') }}</option>
|
||||
<option value="full">{{ $tm('edit.full') }}</option>
|
||||
</select>
|
||||
|
||||
<!-- Reply panel switch button -->
|
||||
<select
|
||||
class="select"
|
||||
v-if="routeName === 'Topic'"
|
||||
v-model="replyDraft.mode"
|
||||
>
|
||||
<option value="minimal">{{ $tm('edit.minimal') }}</option>
|
||||
<option value="">{{ $tm('edit.default') }}</option>
|
||||
<option value="essential">{{ $tm('edit.essential') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Whether to display popular keywords -->
|
||||
<div class="keywords">
|
||||
<div class="keywords-title">{{ $tm('edit.tagsHint') }}</div>
|
||||
<SwitchButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Close button -->
|
||||
<div class="close">
|
||||
<Icon @click="handelCloseSettingsPanel" icon="line-md:close" />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.settings-menu {
|
||||
width: 323px;
|
||||
padding: 10px;
|
||||
z-index: 1009;
|
||||
position: absolute;
|
||||
margin-bottom: 190px;
|
||||
background-color: var(--kungalgame-white);
|
||||
border: 1px solid var(--kungalgame-blue-1);
|
||||
box-shadow: var(--shadow);
|
||||
border-radius: 5px;
|
||||
display: flex;
|
||||
|
||||
.content {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.editor-height-title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.editor-advance {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
font-size: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-height {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
justify-content: space between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.editor-advance-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.refresh {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 17px;
|
||||
cursor: pointer;
|
||||
color: var(--kungalgame-blue-4);
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Editor mode selection box
|
||||
.select {
|
||||
width: 100px;
|
||||
font-size: 16px;
|
||||
margin-left: 20px;
|
||||
color: var(--kungalgame-font-color-3);
|
||||
border: 1px solid var(--kungalgame-blue-4);
|
||||
background-color: var(--kungalgame-trans-white-9);
|
||||
|
||||
option {
|
||||
background-color: var(--kungalgame-white);
|
||||
}
|
||||
}
|
||||
|
||||
// Close settings
|
||||
.close {
|
||||
font-size: 25px;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Whether to display popular keywords
|
||||
.keywords {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.slide-up-enter-active,
|
||||
.slide-up-leave-active {
|
||||
transition: all 0.25s ease-out;
|
||||
}
|
||||
|
||||
.slide-up-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
}
|
||||
|
||||
.slide-up-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
</style>
|
|
@ -1,141 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
// Global message component (top)
|
||||
import Message from '@/components/alert/Message'
|
||||
|
||||
// Import the router
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
// Import the icon font
|
||||
import { Icon } from '@iconify/vue'
|
||||
|
||||
// Import CSS animations
|
||||
import 'animate.css'
|
||||
|
||||
const router = useRouter()
|
||||
// Current route
|
||||
const route = useRoute()
|
||||
// Name of the current page route
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// Adjust the background color based on the mouse coordinates
|
||||
const x = ref(0)
|
||||
// Whether to display information prompts
|
||||
const isShowInfo = ref(false)
|
||||
|
||||
// When the mouse moves
|
||||
const onMousemove = (e: MouseEvent) => {
|
||||
x.value = e.clientX
|
||||
}
|
||||
|
||||
// Click the help button
|
||||
const handleClickHelp = () => {
|
||||
if (routeName.value === 'Edit') {
|
||||
isShowInfo.value = true
|
||||
} else {
|
||||
const helpHtmlEN = `<p>You can click on the left settings to adjust the editor's mode.</p>
|
||||
<p>We recommend finishing your text before formatting.</p>
|
||||
<p>The website's code is handwritten, and errors are inevitable.</p>
|
||||
<p>If you encounter any errors, please <a style="color: var(--kungalgame-blue-4); border-bottom: 2px solid var(--kungalgame-blue-4);" href="/contact">Contact Us</a>.</p>`
|
||||
const helpHtmlCN = `<p>您可以点击左侧的设置调整编辑器的模式</p>
|
||||
<p>我们建议您写完文本再进行格式化</p>
|
||||
<p>网站的代码是手写的,错误在所难免</p>
|
||||
<p>如果您遇到错误,请<a style="color: var(--kungalgame-blue-4); border-bottom: 2px solid var(--kungalgame-blue-4);" href="/contact">联系我们</a></p>`
|
||||
|
||||
Message(helpHtmlEN, helpHtmlCN, 'info', 5000)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="help">
|
||||
<div class="title" @click="handleClickHelp">
|
||||
<span><Icon icon="line-md:question-circle" /></span>
|
||||
</div>
|
||||
<div
|
||||
v-if="isShowInfo"
|
||||
@mousemove="onMousemove"
|
||||
@mouseleave="isShowInfo = false"
|
||||
class="info"
|
||||
:style="{ backgroundColor: `hsl(${x}, 77%, 77%)` }"
|
||||
>
|
||||
<ul>
|
||||
<li>{{ $tm('edit.help1') }}</li>
|
||||
<li>{{ $tm('edit.help2') }}</li>
|
||||
<li>{{ $tm('edit.help3') }}</li>
|
||||
<li>{{ $tm('edit.help4') }}</li>
|
||||
<li>
|
||||
{{ $tm('edit.help5') }}
|
||||
<span @click="router.push('/contact')">
|
||||
{{ $tm('edit.contact') }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.help {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.title {
|
||||
cursor: pointer;
|
||||
margin-left: 20px;
|
||||
color: var(--kungalgame-font-color-1);
|
||||
font-size: 23px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
padding: 3px;
|
||||
color: var(--kungalgame-font-color-2);
|
||||
position: absolute;
|
||||
left: 200px;
|
||||
transition: 0.3s background-color ease;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 100px;
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--kungalgame-white);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
|
||||
li {
|
||||
&::before {
|
||||
content: '❆ ';
|
||||
color: var(--kungalgame-pink-3);
|
||||
}
|
||||
|
||||
cursor: default;
|
||||
font-size: 15px;
|
||||
line-height: 27px;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
color: var(--kungalgame-blue-4);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,289 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { defineAsyncComponent, computed, ref, onBeforeMount } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
// Import the editor
|
||||
import { QuillEditor } from '@vueup/vue-quill'
|
||||
// Import editor Modules
|
||||
import { modules } from './modules'
|
||||
|
||||
// Custom Quill themes, the second theme is not currently in use
|
||||
import '@/styles/editor/editor.snow.scss'
|
||||
// import '@vueup/vue-quill/dist/vue-quill.bubble.css'
|
||||
|
||||
// Import Title component
|
||||
const Title = defineAsyncComponent(
|
||||
() => import('@/components/quill-editor/Title.vue')
|
||||
)
|
||||
|
||||
// Import EditorFooter
|
||||
import EditorFooter from './EditorFooter.vue'
|
||||
// Footer slot
|
||||
import Help from './Help.vue'
|
||||
|
||||
// Import the store for editing topics
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// Import XSS filtering tool
|
||||
import DOMPurify from 'dompurify'
|
||||
// Import debounce function
|
||||
import { debounce } from '@/utils/debounce'
|
||||
|
||||
// Topic editing page store
|
||||
const { editorHeight, textCount, isSaveTopic, content, topicRewrite } =
|
||||
storeToRefs(useKUNGalgameEditStore())
|
||||
// Store for topic page used for replies
|
||||
const { replyDraft, replyRewrite } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
// Current route
|
||||
const route = useRoute()
|
||||
// Current page route name
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// Define props passed from the parent component
|
||||
/**
|
||||
* @param {boolean} isShowToolbar - Whether to display the toolbar
|
||||
* @param {boolean} isShowTitle - Whether to display the title
|
||||
*/
|
||||
|
||||
const props = defineProps<{
|
||||
isShowToolbar: boolean
|
||||
isShowTitle: boolean
|
||||
}>()
|
||||
|
||||
// Editor instance
|
||||
const editorRef = ref<typeof QuillEditor>()
|
||||
// Content inside the editor
|
||||
const valueHtml = ref('')
|
||||
// Editor-related configuration
|
||||
const editorOptions = {
|
||||
placeholder: 'Moe Moe Moe!',
|
||||
}
|
||||
|
||||
// Editor height, determined by the route name
|
||||
const editorHeightStyle = computed(
|
||||
() =>
|
||||
`height: ${
|
||||
routeName.value === 'Edit'
|
||||
? editorHeight.value
|
||||
: replyDraft.value.editorHeight
|
||||
}px`
|
||||
)
|
||||
|
||||
// Whether to show the editor toolbar
|
||||
const isShowEditorToolbar = computed(() =>
|
||||
props.isShowToolbar ? 'block' : 'none'
|
||||
)
|
||||
|
||||
onBeforeMount(() => {
|
||||
/**
|
||||
* Editor is in the edit mode
|
||||
*/
|
||||
// Load topic data before mounting if not saved (and must be on the Edit page)
|
||||
if (isSaveTopic.value && routeName.value === 'Edit') {
|
||||
valueHtml.value = content.value
|
||||
}
|
||||
/**
|
||||
* Editor is in the re-editing edit mode
|
||||
*/
|
||||
// Load data for re-editing a topic before mounting
|
||||
if (topicRewrite.value.isTopicRewriting && routeName.value === 'Edit') {
|
||||
valueHtml.value = topicRewrite.value.content
|
||||
}
|
||||
/**
|
||||
* Editor is in the reply mode
|
||||
*/
|
||||
// Load reply data before mounting if not saved (and must be on the Topic page)
|
||||
if (replyDraft.value.isSaveReply && routeName.value === 'Topic') {
|
||||
valueHtml.value = replyDraft.value.content
|
||||
}
|
||||
/**
|
||||
* Editor is in the re-editing reply mode
|
||||
*/
|
||||
if (replyRewrite.value.isReplyRewriting && routeName.value === 'Topic') {
|
||||
valueHtml.value = replyRewrite.value.content
|
||||
}
|
||||
})
|
||||
|
||||
// Automatically save data when the editor text changes
|
||||
const handleTextChange = async () => {
|
||||
// Filter out XSS
|
||||
const purifiedHtml = DOMPurify.sanitize(editorRef.value?.getHTML())
|
||||
// Create a debounce function
|
||||
const debouncedUpdateContent = debounce(() => {
|
||||
/**
|
||||
* Editor is in edit mode
|
||||
*/
|
||||
// Save to the edit store if not in topic re-edit mode
|
||||
if (!topicRewrite.value.isTopicRewriting && routeName.value === 'Edit') {
|
||||
content.value = purifiedHtml
|
||||
}
|
||||
/**
|
||||
* Editor is in re-editing edit mode
|
||||
*/
|
||||
// Load data for re-editing a topic before mounting
|
||||
if (topicRewrite.value.isTopicRewriting && routeName.value === 'Edit') {
|
||||
topicRewrite.value.content = purifiedHtml
|
||||
}
|
||||
/**
|
||||
* Editor is in reply mode
|
||||
*/
|
||||
// Save to the reply store if not in reply re-edit mode
|
||||
if (!replyRewrite.value.isReplyRewriting && routeName.value === 'Topic') {
|
||||
replyDraft.value.content = purifiedHtml
|
||||
}
|
||||
/**
|
||||
* Editor is in re-editing reply mode
|
||||
*/
|
||||
if (replyRewrite.value.isReplyRewriting && routeName.value === 'Topic') {
|
||||
replyRewrite.value.content = purifiedHtml
|
||||
}
|
||||
}, 1007)
|
||||
|
||||
// Call the debounce function, which will execute the update operation only once within the delay time
|
||||
debouncedUpdateContent()
|
||||
|
||||
// Calculate how many characters the user has entered
|
||||
const length = computed(() => editorRef.value?.getText().trim().length)
|
||||
|
||||
// Save the count based on the page's route name
|
||||
if (routeName.value === 'Edit') {
|
||||
textCount.value = length.value
|
||||
}
|
||||
if (routeName.value === 'Topic') {
|
||||
replyDraft.value.textCount = length.value
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="editor">
|
||||
<!-- Topic title -->
|
||||
<Title v-if="isShowTitle" />
|
||||
|
||||
<!-- Editor body -->
|
||||
<QuillEditor
|
||||
ref="editorRef"
|
||||
contentType="html"
|
||||
:content="valueHtml"
|
||||
:style="editorHeightStyle"
|
||||
:modules="modules"
|
||||
:options="editorOptions"
|
||||
@textChange="handleTextChange"
|
||||
@click.prevent
|
||||
/>
|
||||
|
||||
<!-- Editor footer -->
|
||||
<EditorFooter>
|
||||
<template #help>
|
||||
<Help />
|
||||
</template>
|
||||
</EditorFooter>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/*
|
||||
* Resolve style issues
|
||||
* These styles are written based on the compiled CSS, it's a bit weird, blame the author www
|
||||
*/
|
||||
|
||||
/* Style of the toolbar */
|
||||
:deep(.ql-toolbar) {
|
||||
border-top: 1px solid var(--kungalgame-blue-1);
|
||||
border-bottom: 1px solid var(--kungalgame-blue-1);
|
||||
background-color: var(--kungalgame-trans-blue-0);
|
||||
/* Shadow below the header */
|
||||
box-shadow: 0 2px 4px 0 var(--kungalgame-trans-blue-1);
|
||||
display: v-bind(isShowEditorToolbar);
|
||||
/* Do not display video insertion, this feature has too many bugs */
|
||||
|
||||
.ql-video {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Style of the editor body */
|
||||
:deep(.ql-container) {
|
||||
transition: all 0.2s;
|
||||
width: 80%;
|
||||
max-width: 1080px;
|
||||
border: none;
|
||||
margin: 0 auto;
|
||||
font-size: 17px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
|
||||
&::before {
|
||||
content: '∟';
|
||||
position: absolute;
|
||||
font-size: 40px;
|
||||
transform: translateX(-20px) translateY(-20px) rotate(90deg);
|
||||
color: var(--kungalgame-blue-2);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '∟';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
font-size: 40px;
|
||||
transform: translateX(20px) translateY(-20px) rotate(-90deg);
|
||||
color: var(--kungalgame-blue-2);
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
padding: 0;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: inline;
|
||||
width: 7px;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
cursor: default;
|
||||
background: var(--kungalgame-blue-4);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Compatible with Firefox */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--kungalgame-blue-4) var(--kungalgame-blue-1); /* Firefox 64+ */
|
||||
|
||||
&::before {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '♡ Yuki Yuki';
|
||||
font-size: 22px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
transform: translateX(-20px) translateY(27px);
|
||||
color: var(--kungalgame-trans-white-5);
|
||||
text-shadow: 1px 1px 1px var(--kungalgame-pink-3);
|
||||
font-style: oblique;
|
||||
}
|
||||
}
|
||||
|
||||
/* Style of BlotFormatter plugin, important here */
|
||||
.blot-formatter__toolbar-button {
|
||||
margin: 0 5px;
|
||||
border: none !important;
|
||||
background: var(--kungalgame-trans-white-9) !important;
|
||||
|
||||
svg {
|
||||
border: 1px solid var(--kungalgame-blue-4) !important;
|
||||
background: var(--kungalgame-trans-white-2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.is-selected {
|
||||
svg {
|
||||
background: var(--kungalgame-trans-blue-1) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,95 +0,0 @@
|
|||
<!-- Common Toggle Button for KUNGalgame -->
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
// Import the store for the editing page
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
// Import the store for replies
|
||||
import { useKUNGalgameTopicStore } from '@/store/modules/topic'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// Current page's route
|
||||
const route = useRoute()
|
||||
// Name of the current page's route
|
||||
const routeName = computed(() => route.name as string)
|
||||
|
||||
// Use the store for the editing page
|
||||
const { isShowHotKeywords } = storeToRefs(useKUNGalgameEditStore())
|
||||
// Store for the topic page, used for replies
|
||||
const { replyDraft } = storeToRefs(useKUNGalgameTopicStore())
|
||||
|
||||
// Watch for changes in store states to keep button states in sync with the store
|
||||
watch(
|
||||
() => [isShowHotKeywords.value, replyDraft.value.isShowHotKeywords],
|
||||
([newValue1, newValue2]) => {
|
||||
isShowHotKeywords.value = newValue1
|
||||
replyDraft.value.isShowHotKeywords = newValue2
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Bind different models based on the route name -->
|
||||
<input
|
||||
v-if="routeName === 'Edit'"
|
||||
type="checkbox"
|
||||
id="switch"
|
||||
v-model="isShowHotKeywords"
|
||||
/>
|
||||
<input
|
||||
v-if="routeName === 'Topic'"
|
||||
type="checkbox"
|
||||
id="switch"
|
||||
v-model="replyDraft.isShowHotKeywords"
|
||||
/>
|
||||
<label for="switch"></label>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
input {
|
||||
height: 0;
|
||||
width: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
text-indent: -9999px;
|
||||
width: 47px;
|
||||
height: 24px;
|
||||
background: var(--kungalgame-trans-blue-2);
|
||||
display: block;
|
||||
border-radius: 100px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
label:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: var(--kungalgame-white);
|
||||
border-radius: 15px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
input:checked + label {
|
||||
background: var(--kungalgame-blue-4);
|
||||
}
|
||||
|
||||
input:checked + label:after {
|
||||
left: calc(100% - 2px);
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
// Centering
|
||||
body {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
</style>
|
|
@ -1,104 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
import { onBeforeMount, ref } from 'vue'
|
||||
|
||||
// Import the store for editing topics
|
||||
import { useKUNGalgameEditStore } from '@/store/modules/edit'
|
||||
import { storeToRefs } from 'pinia'
|
||||
|
||||
// Import debounce function
|
||||
import { debounce } from '@/utils/debounce'
|
||||
|
||||
const { isSaveTopic, title, topicRewrite } = storeToRefs(
|
||||
useKUNGalgameEditStore()
|
||||
)
|
||||
|
||||
// Topic title text
|
||||
const topicTitle = ref('')
|
||||
// Maximum length for the title
|
||||
const maxInputLength = 40
|
||||
|
||||
onBeforeMount(() => {
|
||||
/**
|
||||
* Editor is in edit mode
|
||||
*/
|
||||
if (isSaveTopic.value) {
|
||||
topicTitle.value = title.value
|
||||
}
|
||||
/**
|
||||
* Editor is in re-editing edit mode
|
||||
*/
|
||||
// Load data for re-editing a topic before mounting
|
||||
if (topicRewrite.value.isTopicRewriting) {
|
||||
topicTitle.value = topicRewrite.value.title
|
||||
}
|
||||
})
|
||||
|
||||
// Handle user input
|
||||
const handleInput = () => {
|
||||
// Title cannot exceed 40 characters
|
||||
if (topicTitle.value.length > maxInputLength) {
|
||||
topicTitle.value = topicTitle.value.slice(0, maxInputLength)
|
||||
}
|
||||
|
||||
// User input is pure whitespace
|
||||
if (topicTitle.value.trim() === '') {
|
||||
title.value = ''
|
||||
topicRewrite.value.title = ''
|
||||
return
|
||||
}
|
||||
|
||||
// Create a debounce handling function
|
||||
const debouncedInput = debounce(() => {
|
||||
/**
|
||||
* Editor is in reply mode
|
||||
*/
|
||||
// Save to the edit store if not in topic re-edit mode
|
||||
if (!topicRewrite.value.isTopicRewriting) {
|
||||
title.value = topicTitle.value
|
||||
}
|
||||
/**
|
||||
* Editor is in re-editing edit mode
|
||||
*/
|
||||
// Save to the re-editing page's store if in re-edit mode
|
||||
if (topicRewrite.value.isTopicRewriting) {
|
||||
topicRewrite.value.title = topicTitle.value
|
||||
}
|
||||
}, 300)
|
||||
|
||||
// Call the debounce handling function, which will execute the update operation only once within the delay time
|
||||
debouncedInput()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Topic title -->
|
||||
<div class="title">
|
||||
<input
|
||||
type="text"
|
||||
:placeholder="`${$tm('edit.title')}`"
|
||||
v-model="topicTitle"
|
||||
@input="handleInput"
|
||||
:maxlength="maxInputLength"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* Title of the topic */
|
||||
.title {
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Input field for the topic title */
|
||||
.title input {
|
||||
background-color: var(--kungalgame-white-9);
|
||||
color: var(--kungalgame-font-color-2);
|
||||
/* Distance from the outline */
|
||||
padding: 7px;
|
||||
width: 100%;
|
||||
/* Font size for the title input */
|
||||
font-size: 40px;
|
||||
border: none;
|
||||
}
|
||||
</style>
|
|
@ -1,88 +0,0 @@
|
|||
/**
|
||||
* This file contains various modules for Quill. Large modules like markdown and emoji are not used here.
|
||||
*/
|
||||
|
||||
// Import the editor
|
||||
// import { QuillEditor } from '@vueup/vue-quill'
|
||||
// Import Quill module for resizing and realigning images and iframe video
|
||||
// It must be imported this way, otherwise it will throw errors after bundling
|
||||
// import BlotFormatter from 'quill-blot-formatter'
|
||||
// import BlotFormatter from 'quill-blot-formatter/dist/BlotFormatter'
|
||||
// Import module for automatic recognition of URLs and email addresses
|
||||
import MagicUrl from 'quill-magic-url'
|
||||
import '@/styles/editor/editor.snow.scss'
|
||||
// Import module for image compression and uploading (very useful)
|
||||
import ImageCompress from 'quill-image-compress'
|
||||
import Message from '../alert/Message'
|
||||
|
||||
// Editor modules
|
||||
export const modules = [
|
||||
// BlotFormatter
|
||||
// {
|
||||
// name: 'blotFormatter',
|
||||
// module: BlotFormatter,
|
||||
// // see: https://github.com/Fandom-OSS/quill-blot-formatter/blob/master/src/Options.js
|
||||
// options: {
|
||||
// overlay: {
|
||||
// style: {
|
||||
// border: '2px solid var(--kungalgame-blue-3)',
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// MagicUrl
|
||||
{
|
||||
name: 'magicUrl',
|
||||
module: MagicUrl,
|
||||
options: {
|
||||
// Regex used to check URLs during typing
|
||||
urlRegularExpression:
|
||||
/(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}(?:\/[^\s]*)?/,
|
||||
// Regex used to check URLs on paste
|
||||
globalRegularExpression: /(https?:\/\/|www\.|tel:)[\S]+/g,
|
||||
mailRegularExpression: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
||||
globalMailRegularExpression:
|
||||
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
||||
},
|
||||
},
|
||||
// ImageCompress
|
||||
{
|
||||
name: 'imageCompress',
|
||||
module: ImageCompress,
|
||||
options: {
|
||||
quality: 0.77,
|
||||
maxWidth: 1007,
|
||||
maxHeight: 1007,
|
||||
imageType: 'image/webp',
|
||||
insertIntoEditor: () => {
|
||||
Message(
|
||||
'The image upload API is under development',
|
||||
'图片上传接口正在开发中',
|
||||
'warn'
|
||||
)
|
||||
},
|
||||
// insertIntoEditor: (
|
||||
// imageBase64URL: string,
|
||||
// imageBlob: Blob,
|
||||
// editor: typeof QuillEditor
|
||||
// ) => {
|
||||
// const formData = new FormData()
|
||||
// formData.append('file', imageBlob)
|
||||
|
||||
// /* TODO: Change this to a backend API */
|
||||
|
||||
// fetch('127.0.0.1:10008/upload', { method: 'POST', body: formData })
|
||||
// .then((response) => response.text())
|
||||
// .then((result) => {
|
||||
// const range = editor.getSelection()
|
||||
// editor.insertEmbed(range.index, 'image', `${result}`, 'user')
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.error(error)
|
||||
// })
|
||||
// },
|
||||
// Temporarily enable console debugging
|
||||
debug: false,
|
||||
},
|
||||
},
|
||||
]
|
|
@ -20,8 +20,6 @@ const handlePublish = async () => {
|
|||
// Backend returns the created topic data
|
||||
const res = await useKUNGalgameEditStore().createNewTopic()
|
||||
|
||||
console.log(res)
|
||||
|
||||
if (res?.code === 200) {
|
||||
// Get the tid of the created topic
|
||||
const tid = res.data.tid
|
||||
|
|
|
@ -287,7 +287,9 @@ onBeforeMount(() => {
|
|||
{{ topicData?.title }}
|
||||
</div>
|
||||
</Transition>
|
||||
|
||||
<Master v-if="topicData" :topicData="topicData" />
|
||||
|
||||
<Reply
|
||||
v-if="topicData && repliesData"
|
||||
:repliesData="repliesData"
|
||||
|
|
Loading…
Reference in a new issue