137 lines
3.6 KiB
Svelte
137 lines
3.6 KiB
Svelte
<script lang="ts">
|
|
import { onMount, tick } from 'svelte'
|
|
import { shorten, getLangFromUrl } from '$lib/utils'
|
|
import type { Editor } from 'codemirror'
|
|
import { shareUrl, selectedLang } from '../store'
|
|
import ComboBox from './ComboBox.svelte'
|
|
import Icon from '@iconify/svelte'
|
|
import { goto } from '$app/navigation'
|
|
|
|
type Language = {
|
|
text: string
|
|
value: string
|
|
data: { mime: string; mode: string }
|
|
}
|
|
|
|
let cssClass = ''
|
|
export { cssClass as class }
|
|
export let editor: Editor | null = null
|
|
export let updateShareUrl: () => Promise<void>
|
|
|
|
let languages: Language[] = []
|
|
let selectedLanguage: Language | null = null
|
|
let textWrap = false
|
|
|
|
let urlInput: HTMLInputElement
|
|
let isUrlInputVisible = false
|
|
|
|
onMount(() => {
|
|
$selectedLang = getLangFromUrl()
|
|
selectedLanguage = languages.find((e) => e.value === $selectedLang)!
|
|
})
|
|
|
|
selectedLang.subscribe((lang) => {
|
|
textWrap = lang === 'plt' || lang === 'md'
|
|
})
|
|
|
|
$: {
|
|
if (editor) {
|
|
// Line wrapping
|
|
editor.setOption('lineWrapping', textWrap)
|
|
}
|
|
}
|
|
|
|
$: {
|
|
if (editor) {
|
|
languages = CodeMirror.modeInfo
|
|
.map((e: any) => ({
|
|
text: e.name,
|
|
value: shorten(e.name),
|
|
data: { mime: e.mime, mode: e.mode },
|
|
}))
|
|
.filter((l: any) => l.value !== 'gflm') // Remove github flavored markdown, redundant with markdown
|
|
|
|
selectedLanguage =
|
|
selectedLanguage ??
|
|
languages.find((e) => e.value === $selectedLang) ??
|
|
languages.find((e) => e.value === 'plt')!
|
|
|
|
const langData = selectedLanguage?.data ?? { mime: null, mode: null }
|
|
// @ts-ignore
|
|
editor.setOption('mode', langData.mime)
|
|
CodeMirror.autoLoadMode(editor, langData.mode)
|
|
$selectedLang = selectedLanguage?.value ?? 'plt'
|
|
}
|
|
}
|
|
|
|
async function showUrlInput() {
|
|
// Make sure the url is up to date
|
|
await updateShareUrl()
|
|
isUrlInputVisible = true
|
|
await tick()
|
|
urlInput.select()
|
|
}
|
|
|
|
async function copyUrl() {
|
|
urlInput.select()
|
|
await navigator.clipboard.writeText(urlInput.value)
|
|
setTimeout(closeUrlInput, 500)
|
|
}
|
|
|
|
function closeUrlInput() {
|
|
isUrlInputVisible = false
|
|
}
|
|
|
|
async function goToPreview() {
|
|
await updateShareUrl()
|
|
goto($shareUrl)
|
|
}
|
|
</script>
|
|
|
|
<div class={cssClass}>
|
|
{#if isUrlInputVisible}
|
|
<div class="flex gap-2 grow">
|
|
<input
|
|
bind:this={urlInput}
|
|
type="text"
|
|
class="border border-gray-300 bg-transparent p-1 grow"
|
|
value={$shareUrl}
|
|
/>
|
|
<button class="button" on:click={copyUrl}>Copy</button>
|
|
<button class="button" on:click={closeUrlInput}>Close</button>
|
|
</div>
|
|
{:else}
|
|
<div class="flex justify-end gap-2">
|
|
<div>
|
|
<ComboBox
|
|
items={languages}
|
|
bind:value={selectedLanguage}
|
|
class="bg-gray-700 border border-gray-300 p-1"
|
|
/>
|
|
</div>
|
|
<!-- Show link input-->
|
|
<button class="button" on:click={showUrlInput}>Get Link</button>
|
|
|
|
<!-- Toggle text wrap -->
|
|
<button class="button" title="Toggle text wrap" on:click={() => (textWrap = !textWrap)}>
|
|
{#if textWrap}
|
|
<Icon class="text-xl" icon="fluent:text-wrap-24-filled" />
|
|
{:else}
|
|
<Icon class="text-xl" icon="fluent:text-wrap-off-24-filled" />
|
|
{/if}
|
|
</button>
|
|
|
|
<!-- Switch to readonly view -->
|
|
<button class="button" on:click={goToPreview} title="Switch to read-only view">
|
|
<Icon class="text-xl" icon="fluent:eye-12-regular" />
|
|
</button>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
.button {
|
|
@apply text-sm border border-gray-300 p-1 hover:bg-gray-600/50;
|
|
}
|
|
</style>
|