mirror of
https://codeberg.org/Freedium-cfd/web.git
synced 2026-03-11 09:04:37 +00:00
feat(new-web): ui design fixes && more md tests
This commit is contained in:
parent
cf9327477e
commit
a21e6a493c
11 changed files with 195 additions and 114 deletions
|
|
@ -1,38 +1,5 @@
|
|||
# create-svelte
|
||||
# New Freedium Frontend
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
|
||||
## TODO:
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
||||
- Migrate to https://github.com/unplugin/unplugin-icons
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -12,6 +12,7 @@
|
|||
"format": "prettier --write ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/heroicons-outline": "^1.2.0",
|
||||
"@sveltejs/adapter-auto": "^3.3.1",
|
||||
"@sveltejs/kit": "^2.7.4",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||
|
|
@ -39,9 +40,11 @@
|
|||
"@iconify/tailwind": "^1.1.3",
|
||||
"bits-ui": "^0.21.16",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"es-toolkit": "^1.26.1",
|
||||
"es-toolkit": "^1.27.0",
|
||||
"hast-util-to-html": "^9.0.3",
|
||||
"mdsvex": "^0.12.3",
|
||||
"medium-zoom": "^1.1.0",
|
||||
"rehype-external-links": "^3.0.0",
|
||||
"shiki": "^1.23.1",
|
||||
"shiki-transformer-copy-button": "^0.0.3",
|
||||
"svelte-bricks": "^0.2.1",
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ html {
|
|||
z-index: 999;
|
||||
}
|
||||
|
||||
.medium-zoom-overlay {
|
||||
@apply !bg-white dark:!bg-zinc-900;
|
||||
}
|
||||
|
||||
@layer base {
|
||||
/**
|
||||
* Shiki
|
||||
|
|
@ -140,44 +144,3 @@ html {
|
|||
background-color: hsla(0 62.8% 30.6% / 0.7);
|
||||
}
|
||||
}
|
||||
|
||||
pre:has(code) {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre button.copy {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
|
||||
& span {
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
& .ready {
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 24 24'><path fill='none' stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192q.56-.045 1.124-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48 48 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.25 2.25 0 0 0 15 2.25h-1.5a2.25 2.25 0 0 0-2.15 1.586m5.8 0q.099.316.1.664v.75h-6V4.5q.001-.348.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9'/></svg>");
|
||||
}
|
||||
|
||||
& .success {
|
||||
display: none;
|
||||
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 16 16'><g fill='white' fill-rule='evenodd' clip-rule='evenodd'><path d='M11.986 3H12a2 2 0 0 1 2 2v6a2 2 0 0 1-1.5 1.937V7A2.5 2.5 0 0 0 10 4.5H4.063A2 2 0 0 1 6 3h.014A2.25 2.25 0 0 1 8.25 1h1.5a2.25 2.25 0 0 1 2.236 2M10.5 4v-.75a.75.75 0 0 0-.75-.75h-1.5a.75.75 0 0 0-.75.75V4z'/><path d='M2 7a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1zm6.585 1.08a.75.75 0 0 1 .336 1.005l-1.75 3.5a.75.75 0 0 1-1.16.234l-1.75-1.5a.75.75 0 0 1 .977-1.139l1.02.875l1.321-2.64a.75.75 0 0 1 1.006-.336'/></g></svg>");
|
||||
}
|
||||
|
||||
&.copied {
|
||||
& .success {
|
||||
display: block;
|
||||
}
|
||||
|
||||
& .ready {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
if (browser) {
|
||||
window.addEventListener('toast', (event) => {
|
||||
console.log(`toast: ${event.detail.message}`);
|
||||
toast.success(event.detail.message);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@
|
|||
|
||||
/* Blockquotes */
|
||||
:global(.prose blockquote) {
|
||||
@apply border-l-4 border-gray-200 dark:border-gray-700 pl-4 italic my-6;
|
||||
@apply border-l-4 border-gray-300 dark:border-gray-700 pl-4 italic my-6;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
|
|
@ -212,8 +212,8 @@
|
|||
@apply rounded-lg p-4 my-6 overflow-x-auto;
|
||||
}
|
||||
|
||||
:global(.prose code) {
|
||||
@apply px-1.5 py-0.5 rounded text-sm font-mono;
|
||||
:global(.prose code:not(.shiki code)) {
|
||||
@apply px-1.5 py-0.5 rounded text-sm font-mono bg-gray-200 dark:bg-zinc-700;
|
||||
}
|
||||
|
||||
:global(.prose pre code) {
|
||||
|
|
@ -238,6 +238,11 @@
|
|||
@apply text-primary hover:text-primary/90 underline decoration-primary/30 hover:decoration-primary/50;
|
||||
}
|
||||
|
||||
:global(.prose a::after) {
|
||||
content: "";
|
||||
@apply icon-[heroicons-outline--external-link] inline-block ml-1 w-3.5 h-3.5 align-text-bottom;
|
||||
}
|
||||
|
||||
/* Horizontal rule */
|
||||
:global(.prose hr) {
|
||||
@apply border-gray-200 dark:border-gray-700 my-8;
|
||||
|
|
@ -297,4 +302,23 @@
|
|||
:global(.prose details[open] summary) {
|
||||
@apply mb-3;
|
||||
}
|
||||
|
||||
/* Aside blocks */
|
||||
:global(.prose aside) {
|
||||
@apply my-6 p-4 rounded-lg border-l-4 border-primary bg-primary/5;
|
||||
}
|
||||
|
||||
:global(.prose aside p) {
|
||||
@apply m-0;
|
||||
}
|
||||
|
||||
/* Mark blocks */
|
||||
:global(.prose mark) {
|
||||
@apply bg-primary/20 text-primary px-1.5 py-0.5 rounded;
|
||||
}
|
||||
|
||||
/* Keyboard blocks */
|
||||
:global(.prose kbd) {
|
||||
@apply px-2 py-1.5 text-xs font-semibold text-gray-800 bg-gray-100 border border-gray-200 rounded-lg dark:bg-gray-600 dark:text-gray-100 dark:border-gray-500;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
aria-label="Open search"
|
||||
>
|
||||
<Icon icon="heroicons:magnifying-glass" />
|
||||
<span>Search articles, topics, and more...</span>
|
||||
<span>Search articles...</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -58,6 +58,70 @@ UploadThing now leverages cutting-edge machine learning algorithms to optimize y
|
|||
|
||||
</details>
|
||||
|
||||
## More Formatting Examples
|
||||
|
||||
### Advanced Markdown
|
||||
|
||||
#### Lists and Sublists
|
||||
|
||||
- Main Feature
|
||||
- Sub-feature 1
|
||||
- Sub-feature 2
|
||||
- Detailed point
|
||||
- Another detail
|
||||
- Another Feature
|
||||
1. First step
|
||||
2. Second step
|
||||
3. Third step
|
||||
|
||||
#### Text Formatting
|
||||
|
||||
_Italic text_ and _another italic_
|
||||
**Bold text** and **another bold**
|
||||
**_Bold and italic_** **_together_**
|
||||
~~Strikethrough text~~
|
||||
`inline code`
|
||||
|
||||
### HTML Elements
|
||||
|
||||
<div align="center">
|
||||
<h3>Centered Content</h3>
|
||||
<p>This content is centered using `HTML`</p>
|
||||
</div>
|
||||
|
||||
<kbd>Ctrl</kbd> + <kbd>C</kbd> to copy
|
||||
|
||||
<mark>Highlighted text</mark>
|
||||
|
||||
<blockquote>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</blockquote>
|
||||
|
||||
<details>
|
||||
<summary>Click to expand</summary>
|
||||
This is hidden content that can be expanded!
|
||||
|
||||
<ul>
|
||||
<li>Point 1</li>
|
||||
<li>Point 2</li>
|
||||
<li>Point 3</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<aside>
|
||||
💡 Pro tip: You can combine <code>HTML</code> and <code>Markdown</code> for powerful formatting
|
||||
</aside>
|
||||
|
||||
### Custom Styling
|
||||
|
||||
<div style="background-color: #f0f0f0; padding: 1rem; border-radius: 4px;">
|
||||
<p style="color: #333;">Custom styled content box</p>
|
||||
<ul>
|
||||
<li>Feature highlight</li>
|
||||
<li>Important note</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
_For more information, visit our [documentation](https://docs.uploadthing.com)._
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
import { Toaster } from '$lib/components/ui/sonner';
|
||||
</script>
|
||||
|
||||
<Toaster />
|
||||
<Toaster position="top-right" expand={true} />
|
||||
<slot />
|
||||
|
|
|
|||
|
|
@ -1,39 +1,97 @@
|
|||
import { mdsvex, escapeSvelte } from 'mdsvex';
|
||||
import rehypeExternalLinks from 'rehype-external-links';
|
||||
import { createHighlighter } from 'shiki';
|
||||
import adapter from '@sveltejs/adapter-auto';
|
||||
import { toHtml } from 'hast-util-to-html';
|
||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||
|
||||
import { h } from 'hastscript';
|
||||
|
||||
export function addCopyButton(options = {}) {
|
||||
const readySvg =
|
||||
"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 24 24'><path fill='none' stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M8.25 7.5V6.108c0-1.135.845-2.098 1.976-2.192q.56-.045 1.124-.08M15.75 18H18a2.25 2.25 0 0 0 2.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48 48 0 0 0-1.123-.08M15.75 18.75v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5A3.375 3.375 0 0 0 6.375 7.5H5.25m11.9-3.664A2.25 2.25 0 0 0 15 2.25h-1.5a2.25 2.25 0 0 0-2.15 1.586m5.8 0q.099.316.1.664v.75h-6V4.5q.001-.348.1-.664M6.75 7.5H4.875c-.621 0-1.125.504-1.125 1.125v12c0 .621.504 1.125 1.125 1.125h9.75c.621 0 1.125-.504 1.125-1.125V16.5a9 9 0 0 0-9-9'/></svg>";
|
||||
|
||||
const successSvg =
|
||||
"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' viewBox='0 0 16 16'><g fill='white' fill-rule='evenodd' clip-rule='evenodd'><path d='M11.986 3H12a2 2 0 0 1 2 2v6a2 2 0 0 1-1.5 1.937V7A2.5 2.5 0 0 0 10 4.5H4.063A2 2 0 0 1 6 3h.014A2.25 2.25 0 0 1 8.25 1h1.5a2.25 2.25 0 0 1 2.236 2M10.5 4v-.75a.75.75 0 0 0-.75-.75h-1.5a.75.75 0 0 0-.75.75V4z'/><path d='M2 7a1 1 0 0 1 1-1h7a1 1 0 0 1 1 1v7a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1zm6.585 1.08a.75.75 0 0 1 .336 1.005l-1.75 3.5a.75.75 0 0 1-1.16.234l-1.75-1.5a.75.75 0 0 1 .977-1.139l1.02.875l1.321-2.64a.75.75 0 0 1 1.006-.336'/></g></svg>";
|
||||
|
||||
export function renderCodeCopyButton(code, options = {}) {
|
||||
const toggleMs = options.toggle || 3000;
|
||||
const button = h(
|
||||
'button',
|
||||
{
|
||||
'data-code': code,
|
||||
style: `
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
top: 0.8rem;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
padding: 0.4rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.2s ease;
|
||||
cursor: pointer;
|
||||
`,
|
||||
onmouseover: `
|
||||
this.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
|
||||
`,
|
||||
onmouseout: `
|
||||
this.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
|
||||
`,
|
||||
onclick: `
|
||||
if (this.classList.contains('copied')) return;
|
||||
navigator.clipboard.writeText(this.dataset.code);
|
||||
this.classList.add('copied');
|
||||
const ready = this.querySelector('.ready');
|
||||
const success = this.querySelector('.success');
|
||||
ready.style.display = 'none';
|
||||
success.style.display = 'block';
|
||||
setTimeout(() => {
|
||||
this.classList.remove('copied');
|
||||
ready.style.display = 'block';
|
||||
success.style.display = 'none';
|
||||
}, ${toggleMs});
|
||||
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Copied to clipboard' } }));
|
||||
`
|
||||
},
|
||||
[
|
||||
h('span', {
|
||||
class: 'ready',
|
||||
style: `
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-image: url("${readySvg}");
|
||||
z-index: 99;
|
||||
display: block;
|
||||
`
|
||||
}),
|
||||
h('span', {
|
||||
class: 'success',
|
||||
style: `
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-image: url("${successSvg}");
|
||||
z-index: 99;
|
||||
display: none;
|
||||
`
|
||||
})
|
||||
]
|
||||
);
|
||||
|
||||
return {
|
||||
name: 'shiki-transformer-copy-button',
|
||||
pre(node) {
|
||||
const button = h(
|
||||
'button',
|
||||
{
|
||||
class: 'copy',
|
||||
'data-code': this.source,
|
||||
onclick: `
|
||||
navigator.clipboard.writeText(this.dataset.code);
|
||||
this.classList.add('copied');
|
||||
setTimeout(() => this.classList.remove('copied'), ${toggleMs});
|
||||
window.dispatchEvent(new CustomEvent('toast', { detail: { message: 'Copied to clipboard' } }));
|
||||
`
|
||||
},
|
||||
[h('span', { class: 'ready' }), h('span', { class: 'success' })]
|
||||
);
|
||||
|
||||
node.children.push(button);
|
||||
}
|
||||
};
|
||||
return toHtml(button);
|
||||
}
|
||||
|
||||
/** @type {import('mdsvex').MdsvexOptions} */
|
||||
const mdsvexOptions = {
|
||||
extensions: ['.md'],
|
||||
rehypePlugins: [[rehypeExternalLinks, { target: '_blank', rel: ['nofollow'] }]],
|
||||
highlight: {
|
||||
highlighter: async (code, lang = 'text') => {
|
||||
const highlighter = await createHighlighter({
|
||||
|
|
@ -41,13 +99,12 @@ const mdsvexOptions = {
|
|||
langs: ['javascript', 'typescript']
|
||||
});
|
||||
await highlighter.loadLanguage('javascript', 'typescript');
|
||||
const html = escapeSvelte(
|
||||
highlighter.codeToHtml(code, {
|
||||
lang,
|
||||
theme: 'poimandres',
|
||||
transformers: [addCopyButton({ toggle: 1200 })]
|
||||
})
|
||||
);
|
||||
const result = highlighter.codeToHtml(code, {
|
||||
lang,
|
||||
theme: 'poimandres'
|
||||
});
|
||||
const buttonHtml = renderCodeCopyButton(code, { toggle: 1200 });
|
||||
const html = escapeSvelte(`<div class="relative">${buttonHtml}${result}</div>`);
|
||||
return `{@html \`${html}\` }`;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { fontFamily } from 'tailwindcss/defaultTheme';
|
||||
import { addDynamicIconSelectors } from '@iconify/tailwind';
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
const config = {
|
||||
|
|
@ -58,7 +59,8 @@ const config = {
|
|||
sans: [...fontFamily.sans]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: [addDynamicIconSelectors()]
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
Loading…
Reference in a new issue