Preview & editor
This commit is contained in:
parent
2809dc6295
commit
0f9faa45f0
16
src/app.html
16
src/app.html
|
@ -3,8 +3,8 @@
|
|||
<head>
|
||||
<title>Paste</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
|
||||
<link rel="stylesheet" type="text/css" href="%sveltekit.assets%/fonts.css" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.svg" />
|
||||
<link rel="preload" as="font" type="text/css" href="%sveltekit.assets%/hack-subset.css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
|
@ -14,18 +14,10 @@ npm/codemirror@5.65.16/theme/nord.min.css"
|
|||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
%sveltekit.head%
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/combine/npm/lzma@2.3.2/src/lzma.min.js"></script>
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
<div class="dark:text-gray-300 dark:bg-gray-800 min-h-screen">%sveltekit.body%</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/combine/
|
||||
npm/lzma@2.3.2/src/lzma.min.js,
|
||||
npm/codemirror@5.65.16,
|
||||
npm/codemirror@5.65.16/addon/mode/loadmode.min.js,
|
||||
npm/codemirror@5.65.16/addon/mode/overlay.min.js,
|
||||
npm/codemirror@5.65.16/addon/mode/multiplex.min.js,
|
||||
npm/codemirror@5.65.16/addon/mode/simple.min.js,
|
||||
npm/codemirror@5.65.16/addon/scroll/simplescrollbars.js,
|
||||
npm/codemirror@5.65.16/mode/meta.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
122
src/components/EditForm.svelte
Normal file
122
src/components/EditForm.svelte
Normal file
|
@ -0,0 +1,122 @@
|
|||
<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'
|
||||
|
||||
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)!
|
||||
})
|
||||
|
||||
$: {
|
||||
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'
|
||||
|
||||
// Line wrapping
|
||||
editor.setOption('lineWrapping', textWrap)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
</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 -->
|
||||
<a class="button" href={$shareUrl}>
|
||||
<Icon class="text-xl" icon="fluent:eye-12-regular" />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.button {
|
||||
@apply text-sm border border-gray-300 p-1 hover:bg-gray-600/50;
|
||||
}
|
||||
</style>
|
|
@ -1,135 +1,17 @@
|
|||
<script lang="ts">
|
||||
import { onMount, tick } from 'svelte'
|
||||
import { shorten } from '$lib/utils'
|
||||
import type { Editor } from 'codemirror'
|
||||
import { shareUrl, selectedLang } from '../store'
|
||||
import ComboBox from './ComboBox.svelte'
|
||||
import Icon from '@iconify/svelte'
|
||||
|
||||
type Language = {
|
||||
text: string
|
||||
value: string
|
||||
data: { mime: string; mode: string }
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
$: {
|
||||
if (editor) {
|
||||
const language = selectedLanguage?.data ?? { mime: null, mode: null }
|
||||
// @ts-ignore
|
||||
editor.setOption('mode', language.mime)
|
||||
CodeMirror.autoLoadMode(editor, language.mode)
|
||||
$selectedLang = selectedLanguage?.value ?? null
|
||||
|
||||
// Line wrapping
|
||||
editor.setOption('lineWrapping', textWrap)
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
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
|
||||
console.log(languages)
|
||||
})
|
||||
|
||||
export function setLanguage(lang: string) {
|
||||
if (lang === 'mrwn' || lang === 'gflm') {
|
||||
// back compatiblity with old links
|
||||
lang = 'md'
|
||||
}
|
||||
const language = languages.find((e) => e.value === lang)!
|
||||
selectedLanguage = language
|
||||
// Automatic text wrap for plain text or markdown
|
||||
if (lang === 'plt' || lang === 'mrwn' || !lang) {
|
||||
textWrap = true
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
closeUrlInput()
|
||||
}
|
||||
|
||||
function closeUrlInput() {
|
||||
isUrlInputVisible = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex flex-wrap justify-between items-center px-3 py-1 text-sm relative z-10 shadow-md gap-2"
|
||||
class="flex flex-wrap justify-between items-center px-3 py-1 text-sm relative z-10 shadow-md gap-2 font-mono bg-gray-700"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<h1 class="text-xl">Paste</h1>
|
||||
<span class="ml-8 text-xs">
|
||||
<a
|
||||
href="https://paste.scambier.xyz/?l=mrwn#G14EICwPbMc0BJ69xNPoItLoErDRMwMj3+vxE5RxArxajeByk+b0b1Tm2h/5ugGgK6S83AqUCi09HeYmDs+vvzQc0QDZe7v7U2rHnFe6CTWSm2AArNua4tqtXVIEFVQuqG+is15etOm1OZOPPCH4xDX1iDNF2bQcN9ugum0Icnwj51n0nlvNacn/N3OOctSGrQbLoNzG8n5bSoJQXOx+PsxV+MeUl+rkKNPIAXT9c8LoOY/772FiFkLv/5w8rvtCBc38VEE5lzmGFcZ0QtqlzBhvWLV5WPhRkROqeoKoDCtH03/fQVI5Y8HfLkq2/Nuidd1GQTKgmPJQVWbZ4cAiqUdOJG6j6pvu48qWjqamYG3nFPHcdYLHYCRV877U2mBgSHTbLWv6eu/DEA88SE5XEIqiQFyDVS2HLN7jJSloLHQJ+jOE86zb9jrkQ9tXAwkAoovCcnlrW5T/EU4L7imRsDAkZdEySO/ri/NBuHPMpSFnqGItLlPd98/SZSmySbImOLfv4WGbdCxw9TYykGsk56aQaVSa/DB2t5HfD6x28lJVlMm3Hjnkwyx95PxNGH0teCAk6CqtbBYlC3LjhY0IEpJ0WWZWY6MlJB+jEW7lAN3DSJD0QFz2FZOOV/HwA9LbFBU="
|
||||
href="/?l=md#G14EICwPbMc0BJ69xNPoItLoErDRMwMj3+vxE5RxArxajeByk+b0b1Tm2h/5ugGgK6S83AqUCi09HeYmDs+vvzQc0QDZe7v7U2rHnFe6CTWSm2AArNua4tqtXVIEFVQuqG+is15etOm1OZOPPCH4xDX1iDNF2bQcN9ugum0Icnwj51n0nlvNacn/N3OOctSGrQbLoNzG8n5bSoJQXOx+PsxV+MeUl+rkKNPIAXT9c8LoOY/772FiFkLv/5w8rvtCBc38VEE5lzmGFcZ0QtqlzBhvWLV5WPhRkROqeoKoDCtH03/fQVI5Y8HfLkq2/Nuidd1GQTKgmPJQVWbZ4cAiqUdOJG6j6pvu48qWjqamYG3nFPHcdYLHYCRV877U2mBgSHTbLWv6eu/DEA88SE5XEIqiQFyDVS2HLN7jJSloLHQJ+jOE86zb9jrkQ9tXAwkAoovCcnlrW5T/EU4L7imRsDAkZdEySO/ri/NBuHPMpSFnqGItLlPd98/SZSmySbImOLfv4WGbdCxw9TYykGsk56aQaVSa/DB2t5HfD6x28lJVlMm3Hjnkwyx95PxNGH0teCAk6CqtbBYlC3LjhY0IEpJ0WWZWY6MlJB+jEW7lAN3DSJD0QFz2FZOOV/HwA9LbFBU="
|
||||
target="_blank"
|
||||
>
|
||||
About</a
|
||||
>
|
||||
About
|
||||
</a>
|
||||
<a class="ml-4" href="https://git.scambier.xyz/scambier/paste" target="_blank">Source</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{#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 on:click={copyUrl}>Copy</button>
|
||||
<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>
|
||||
<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>
|
||||
<div>
|
||||
<button on:click={showUrlInput}> Generate Link </button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
button {
|
||||
@apply text-sm border border-gray-300 p-1 hover:bg-gray-600/50;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -28,4 +28,8 @@ export const shorten = (name: string) => {
|
|||
return n.substr(0, 2) + n.substr(n.length - 2, 2)
|
||||
}
|
||||
|
||||
export function getLangFromUrl() {
|
||||
return new URLSearchParams(window.location.search).get('l') ?? 'plt'
|
||||
}
|
||||
|
||||
export const byId = (id: string) => document.getElementById(id)
|
||||
|
|
|
@ -10,13 +10,16 @@
|
|||
import rehypeStringify from 'rehype-stringify'
|
||||
import hljs from 'highlight.js'
|
||||
import 'highlight.js/styles/nord.min.css'
|
||||
import TopBar from '../components/TopBar.svelte'
|
||||
import Icon from '@iconify/svelte'
|
||||
import { getLangFromUrl } from '$lib/utils'
|
||||
|
||||
let decompressed: string
|
||||
let isMarkdown = false
|
||||
let isPlainText = false
|
||||
|
||||
onMount(async () => {
|
||||
let lang = new URLSearchParams(window.location.search).get('l')
|
||||
let lang = getLangFromUrl()
|
||||
lang = lang === 'mrwn' || lang === 'gflm' ? 'md' : lang // back compatiblity with old links
|
||||
|
||||
// extract the part in the url after the hash
|
||||
|
@ -30,7 +33,7 @@
|
|||
}
|
||||
|
||||
// Markdown
|
||||
if (lang === 'md' || lang === 'gflm') {
|
||||
if (lang === 'md') {
|
||||
const html = await unified()
|
||||
.use(remarkParse)
|
||||
.use(remarkGfm)
|
||||
|
@ -54,9 +57,18 @@
|
|||
window.location.href = '/editor'
|
||||
}
|
||||
})
|
||||
|
||||
function getUrlDataPart(): string {
|
||||
return window.location.search + window.location.hash
|
||||
}
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<TopBar>
|
||||
<a href={'/editor' + getUrlDataPart()} class="p-1 hover:bg-gray-600/50" title="Edit a copy of this note">
|
||||
<Icon class="text-xl" icon="fluent:document-edit-16-regular" />
|
||||
</a>
|
||||
</TopBar>
|
||||
<div class="prose dark:prose-invert lg:py-12 p-[0.5em] md:max-w-3xl md:mx-auto lg:max-w-4xl">
|
||||
{#if isMarkdown}
|
||||
{@html decompressed}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import type { Editor } from 'codemirror'
|
||||
import { onMount } from 'svelte'
|
||||
import { debounce } from 'lodash-es'
|
||||
import * as brotli from '$lib/brotli'
|
||||
import * as lzma from '$lib/lzma'
|
||||
import { byId } from '$lib/utils'
|
||||
import TopBar from '../../components/TopBar.svelte'
|
||||
import { selectedLang, shareUrl } from '../../store'
|
||||
import EditForm from '../../components/EditForm.svelte'
|
||||
|
||||
let editor: Editor | null = null
|
||||
const readOnly = false
|
||||
|
@ -15,33 +14,6 @@
|
|||
let charLen = 0
|
||||
let compressed: string = ''
|
||||
let waiting = false
|
||||
let setLanguage: (lang: string) => void
|
||||
|
||||
onMount(async () => {
|
||||
initCodeEditor()
|
||||
// extract the part in the url after the hash
|
||||
const hash = window.location.hash.slice(1)
|
||||
if (hash) {
|
||||
// decompress the data
|
||||
let decompressed: string
|
||||
if (hash.startsWith('XQAAA')) {
|
||||
decompressed = await lzma.decompress(hash)
|
||||
} else {
|
||||
decompressed = await brotli.decompress(hash)
|
||||
}
|
||||
// set the editor value
|
||||
if (editor) {
|
||||
editor.setValue(decompressed)
|
||||
}
|
||||
}
|
||||
|
||||
const lang = new URLSearchParams(window.location.search).get('l')
|
||||
if (lang) {
|
||||
setLanguage(lang)
|
||||
} else {
|
||||
setLanguage('plt')
|
||||
}
|
||||
})
|
||||
|
||||
async function updateShareUrl() {
|
||||
if (editor) {
|
||||
|
@ -60,7 +32,7 @@
|
|||
waiting = false
|
||||
}, 1000)
|
||||
|
||||
const initCodeEditor = () => {
|
||||
async function initCodeEditor() {
|
||||
CodeMirror.modeURL = 'https://cdn.jsdelivr.net/npm/codemirror@5.65.16/mode/%N/%N.js'
|
||||
editor = new CodeMirror(byId('editor'), {
|
||||
lineNumbers: true,
|
||||
|
@ -81,11 +53,45 @@
|
|||
updateShareUrlDebounced()
|
||||
}
|
||||
})
|
||||
|
||||
// extract the part in the url after the hash
|
||||
const hash = window.location.hash.slice(1)
|
||||
if (hash) {
|
||||
// decompress the data
|
||||
let decompressed: string
|
||||
if (hash.startsWith('XQAAA')) {
|
||||
decompressed = await lzma.decompress(hash)
|
||||
} else {
|
||||
decompressed = await brotli.decompress(hash)
|
||||
}
|
||||
// set the editor value
|
||||
if (editor) {
|
||||
editor.setValue(decompressed)
|
||||
}
|
||||
}
|
||||
|
||||
$selectedLang = new URLSearchParams(window.location.search).get('l') ?? ' plt'
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/combine/
|
||||
npm/codemirror@5.65.16,
|
||||
npm/codemirror@5.65.16/addon/mode/loadmode.min.js,
|
||||
npm/codemirror@5.65.16/addon/mode/overlay.min.js,
|
||||
npm/codemirror@5.65.16/addon/mode/multiplex.min.js,
|
||||
npm/codemirror@5.65.16/addon/mode/simple.min.js,
|
||||
npm/codemirror@5.65.16/addon/scroll/simplescrollbars.js,
|
||||
npm/codemirror@5.65.16/mode/meta.min.js"
|
||||
on:load={initCodeEditor}
|
||||
></script>
|
||||
</svelte:head>
|
||||
|
||||
<div class="flex flex-col font-mono h-screen bg-gray-700">
|
||||
<TopBar {editor} {updateShareUrl} bind:setLanguage />
|
||||
<TopBar>
|
||||
<EditForm {editor} {updateShareUrl} class="grow" />
|
||||
</TopBar>
|
||||
|
||||
<div id="editor" class="grow overflow-hidden" />
|
||||
|
||||
|
@ -98,13 +104,13 @@
|
|||
? '?'
|
||||
: Math.round(($shareUrl.length / charLen) * 100)}% of original)
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:global(div.CodeMirror) {
|
||||
height: 100%;
|
||||
font-size: 15px;
|
||||
font-family: 'Hack', monospace;
|
||||
}
|
||||
#footer {
|
||||
--tw-shadow: 0 -4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { writable } from 'svelte/store'
|
||||
|
||||
export const shareUrl = writable('')
|
||||
export const selectedLang = writable<string | null>(null)
|
||||
export const selectedLang = writable<string>('plt')
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 4.2 KiB |
1
static/favicon.svg
Normal file
1
static/favicon.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32"><g fill="none"><path fill="#E19747" d="M5 4.5A1.5 1.5 0 0 1 6.5 3h19A1.5 1.5 0 0 1 27 4.5v24a1.5 1.5 0 0 1-1.5 1.5h-19A1.5 1.5 0 0 1 5 28.5v-24Z"/><path fill="#F3EEF8" d="M25 6a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v21a1 1 0 0 0 1 1h10.586c.147 0 .29-.032.421-.093l.321-.783l.632-4.086l4.457-.783l.49-.247a1 1 0 0 0 .093-.422V6Z"/><path fill="#CDC4D6" d="M24.91 22H20a1 1 0 0 0-1 1v4.91a1 1 0 0 0 .293-.203l5.414-5.414A1 1 0 0 0 24.91 22Z"/><path fill="#9B9B9B" d="M18 4a2 2 0 1 0-4 0h-1a2 2 0 0 0-2 2v1.5a.5.5 0 0 0 .5.5h9a.5.5 0 0 0 .5-.5V6a2 2 0 0 0-2-2h-1Zm-1 0a1 1 0 1 1-2 0a1 1 0 0 1 2 0Zm-8 8.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5Zm0 3a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5Zm.5 2.5a.5.5 0 0 0 0 1h13a.5.5 0 0 0 0-1h-13ZM9 21.5a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Z"/></g></svg>
|
After Width: | Height: | Size: 915 B |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
static/fonts/hack-bold-subset.woff
Normal file
BIN
static/fonts/hack-bold-subset.woff
Normal file
Binary file not shown.
BIN
static/fonts/hack-bold-subset.woff2
Normal file
BIN
static/fonts/hack-bold-subset.woff2
Normal file
Binary file not shown.
BIN
static/fonts/hack-bolditalic-subset.woff
Normal file
BIN
static/fonts/hack-bolditalic-subset.woff
Normal file
Binary file not shown.
BIN
static/fonts/hack-bolditalic-subset.woff2
Normal file
BIN
static/fonts/hack-bolditalic-subset.woff2
Normal file
Binary file not shown.
BIN
static/fonts/hack-italic-subset.woff
Normal file
BIN
static/fonts/hack-italic-subset.woff
Normal file
Binary file not shown.
BIN
static/fonts/hack-italic-subset.woff2
Normal file
BIN
static/fonts/hack-italic-subset.woff2
Normal file
Binary file not shown.
BIN
static/fonts/hack-regular-subset.woff
Normal file
BIN
static/fonts/hack-regular-subset.woff
Normal file
Binary file not shown.
BIN
static/fonts/hack-regular-subset.woff2
Normal file
BIN
static/fonts/hack-regular-subset.woff2
Normal file
Binary file not shown.
34
static/hack-subset.css
Normal file
34
static/hack-subset.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*!
|
||||
* Hack typeface https://github.com/source-foundry/Hack
|
||||
* License: https://github.com/source-foundry/Hack/blob/master/LICENSE.md
|
||||
*/
|
||||
/* FONT PATHS
|
||||
* -------------------------- */
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-regular-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-regular-subset.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-bold-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-bold-subset.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-italic-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-italic-webfont.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-bolditalic-subset.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-bolditalic-subset.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
34
static/hack.css
Normal file
34
static/hack.css
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*!
|
||||
* Hack typeface https://github.com/source-foundry/Hack
|
||||
* License: https://github.com/source-foundry/Hack/blob/master/LICENSE.md
|
||||
*/
|
||||
/* FONT PATHS
|
||||
* -------------------------- */
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-regular.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-regular.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-bold.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-bold.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-italic.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-italic.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 400;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Hack';
|
||||
src: url('fonts/hack-bolditalic.woff2?sha=3114f1256') format('woff2'), url('fonts/hack-bolditalic.woff?sha=3114f1256') format('woff');
|
||||
font-weight: 700;
|
||||
font-style: italic;
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ export default {
|
|||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
mono: ['"JetBrainsMono"', ...defaultTheme.fontFamily.mono],
|
||||
mono: ['"Hack"', ...defaultTheme.fontFamily.mono],
|
||||
},
|
||||
typography: {
|
||||
DEFAULT: {
|
||||
|
|
Loading…
Reference in New Issue
Block a user