feat(new-web): ui design fixes && more md tests

This commit is contained in:
ZhymabekRoman 2024-11-21 19:58:40 +05:00
parent cf9327477e
commit a21e6a493c
11 changed files with 195 additions and 114 deletions

View file

@ -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.

View file

@ -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",

View file

@ -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;
}
}
}

View file

@ -8,6 +8,7 @@
if (browser) {
window.addEventListener('toast', (event) => {
console.log(`toast: ${event.detail.message}`);
toast.success(event.detail.message);
});
}

View file

@ -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>

View file

@ -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>

View file

@ -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)._

View file

@ -3,5 +3,5 @@
import { Toaster } from '$lib/components/ui/sonner';
</script>
<Toaster />
<Toaster position="top-right" expand={true} />
<slot />

View file

@ -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}\` }`;
}
}

View file

@ -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;