You've already forked AstralRinth
forked from didirus/AstralRinth
Merge branch 'master' into redesign/new-promo-style
This commit is contained in:
@@ -14,7 +14,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'report',
|
'id': 'report',
|
||||||
'action': () => {}
|
'link': 'https://example.com/report',
|
||||||
|
'external': true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'remain',
|
'id': 'remain',
|
||||||
@@ -65,7 +66,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'report',
|
'id': 'report',
|
||||||
'action': () => {}
|
'link': 'https://example.com/report',
|
||||||
|
'external': true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'remain',
|
'id': 'remain',
|
||||||
|
|||||||
@@ -447,11 +447,10 @@ a,
|
|||||||
height: 1.25rem;
|
height: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.external-icon) {
|
.external-icon {
|
||||||
width: 0.75rem;
|
width: 0.75rem;
|
||||||
height: 0.75rem;
|
height: 0.75rem;
|
||||||
margin-bottom: auto;
|
margin-bottom: auto;
|
||||||
margin-left: 0.25rem;
|
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ const accentedButton = computed(() =>
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="link"
|
v-if="link && link.startsWith('/')"
|
||||||
class="btn"
|
class="btn"
|
||||||
:class="{
|
:class="{
|
||||||
'icon-only': iconOnly,
|
'icon-only': iconOnly,
|
||||||
@@ -81,6 +81,35 @@ const accentedButton = computed(() =>
|
|||||||
<ExternalIcon v-if="external && !iconOnly" class="external-icon" />
|
<ExternalIcon v-if="external && !iconOnly" class="external-icon" />
|
||||||
<UnknownIcon v-if="!$slots.default" />
|
<UnknownIcon v-if="!$slots.default" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<a
|
||||||
|
v-else-if="link"
|
||||||
|
class="btn"
|
||||||
|
:class="{
|
||||||
|
'icon-only': iconOnly,
|
||||||
|
'btn-large': large,
|
||||||
|
'btn-danger': color === 'danger',
|
||||||
|
'btn-primary': color === 'primary',
|
||||||
|
'btn-secondary': color === 'secondary',
|
||||||
|
'btn-highlight': color === 'highlight',
|
||||||
|
'btn-red': color === 'red',
|
||||||
|
'btn-orange': color === 'orange',
|
||||||
|
'btn-green': color === 'green',
|
||||||
|
'btn-blue': color === 'blue',
|
||||||
|
'btn-purple': color === 'purple',
|
||||||
|
'btn-gray': color === 'gray',
|
||||||
|
'btn-transparent': transparent,
|
||||||
|
'btn-hover-filled': hoverFilled,
|
||||||
|
'btn-hover-filled-only': hoverFilledOnly,
|
||||||
|
'btn-outline': outline,
|
||||||
|
'color-accent-contrast': accentedButton,
|
||||||
|
}"
|
||||||
|
:href="link"
|
||||||
|
:target="external ? '_blank' : '_self'"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<ExternalIcon v-if="external && !iconOnly" class="external-icon" />
|
||||||
|
<UnknownIcon v-if="!$slots.default" />
|
||||||
|
</a>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn"
|
class="btn"
|
||||||
|
|||||||
@@ -135,7 +135,7 @@
|
|||||||
<Button :action="() => imageModal?.hide()"><XIcon /> Cancel</Button>
|
<Button :action="() => imageModal?.hide()"><XIcon /> Cancel</Button>
|
||||||
<Button
|
<Button
|
||||||
color="primary"
|
color="primary"
|
||||||
:disabled="linkValidationErrorMessage || !linkUrl"
|
:disabled="!canInsertImage"
|
||||||
:action="
|
:action="
|
||||||
() => {
|
() => {
|
||||||
if (editor) markdownCommands.replaceSelection(editor, imageMarkdown)
|
if (editor) markdownCommands.replaceSelection(editor, imageMarkdown)
|
||||||
@@ -607,6 +607,14 @@ const handleImageUpload = async (files: FileList) => {
|
|||||||
const imageUploadOption = ref<string>('upload')
|
const imageUploadOption = ref<string>('upload')
|
||||||
const imageMarkdown = computed(() => (linkMarkdown.value.length ? `!${linkMarkdown.value}` : ''))
|
const imageMarkdown = computed(() => (linkMarkdown.value.length ? `!${linkMarkdown.value}` : ''))
|
||||||
|
|
||||||
|
const canInsertImage = computed(() => {
|
||||||
|
// Make sure the image url is valid, there is an image url, and there is alt text
|
||||||
|
// They need to be valid, and not empty
|
||||||
|
return (
|
||||||
|
!linkValidationErrorMessage.value && linkUrl.value?.length > 0 && linkText.value?.length > 0
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
const youtubeRegex =
|
const youtubeRegex =
|
||||||
/^(?:https?:)?(?:\/\/)?(?:youtu\.be\/|(?:www\.|m\.)?youtube\.com\/(?:watch|v|embed)(?:\.php)?(?:\?.*v=|\/))([a-zA-Z0-9_-]{7,15})(?:[?&][a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+)*$/
|
/^(?:https?:)?(?:\/\/)?(?:youtu\.be\/|(?:www\.|m\.)?youtube\.com\/(?:watch|v|embed)(?:\.php)?(?:\?.*v=|\/))([a-zA-Z0-9_-]{7,15})(?:[?&][a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+)*$/
|
||||||
|
|
||||||
@@ -623,22 +631,25 @@ const linkModal = ref<InstanceType<typeof Modal> | null>(null)
|
|||||||
const imageModal = ref<InstanceType<typeof Modal> | null>(null)
|
const imageModal = ref<InstanceType<typeof Modal> | null>(null)
|
||||||
const videoModal = ref<InstanceType<typeof Modal> | null>(null)
|
const videoModal = ref<InstanceType<typeof Modal> | null>(null)
|
||||||
|
|
||||||
|
function resetModalStates() {
|
||||||
|
linkText.value = ''
|
||||||
|
linkUrl.value = ''
|
||||||
|
linkValidationErrorMessage.value = undefined
|
||||||
|
}
|
||||||
|
|
||||||
function openLinkModal() {
|
function openLinkModal() {
|
||||||
if (editor) linkText.value = markdownCommands.yankSelection(editor)
|
if (editor) linkText.value = markdownCommands.yankSelection(editor)
|
||||||
linkUrl.value = ''
|
resetModalStates()
|
||||||
linkModal.value?.show()
|
linkModal.value?.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openImageModal() {
|
function openImageModal() {
|
||||||
linkValidationErrorMessage.value = undefined
|
resetModalStates()
|
||||||
linkText.value = ''
|
|
||||||
linkUrl.value = ''
|
|
||||||
imageModal.value?.show()
|
imageModal.value?.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
function openVideoModal() {
|
function openVideoModal() {
|
||||||
linkText.value = ''
|
resetModalStates()
|
||||||
linkUrl.value = ''
|
|
||||||
videoModal.value?.show()
|
videoModal.value?.show()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -18,9 +18,20 @@
|
|||||||
:hover-filled-only="option.hoverFilledOnly"
|
:hover-filled-only="option.hoverFilledOnly"
|
||||||
transparent
|
transparent
|
||||||
:action="
|
:action="
|
||||||
|
option.action
|
||||||
|
? () => {
|
||||||
|
option.action()
|
||||||
|
if (!option.remainOnClick) {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null
|
||||||
|
"
|
||||||
|
:link="option.link ? option.link : null"
|
||||||
|
:external="option.external ? option.external : false"
|
||||||
|
@click="
|
||||||
() => {
|
() => {
|
||||||
option.action()
|
if (option.link && !option.remainOnClick) {
|
||||||
if (!option.remainOnClick) {
|
|
||||||
close()
|
close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ const toggleCodeBlock: Command = ({ state, dispatch }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toggleSpoiler: Command = ({ state, dispatch }) => {
|
const toggleSpoiler: Command = ({ state, dispatch }) => {
|
||||||
return toggleAround(state, dispatch, '||', '||')
|
// Insert details tag with a summary tag at the start
|
||||||
|
const detailsTags = ['\n<details>\n<summary>Spoiler</summary>\n\n', '\n\n</details>\n\n']
|
||||||
|
return toggleAround(state, dispatch, detailsTags[0], detailsTags[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleHeader: Command = ({ state, dispatch }) => {
|
const toggleHeader: Command = ({ state, dispatch }) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user