widgets: v0.1

This commit is contained in:
Tobias Merkle 2024-05-03 14:28:16 -04:00
parent 8ee3778878
commit 6e1ede9155
25 changed files with 378 additions and 145 deletions

View File

@ -108,10 +108,32 @@ fn get_widget() -> String {
return r#"<html>
<head>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.app {
max-width: 32%;
width: 100%;
}
.app-image {
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
.app-info {
max-width: 67%
}
</style>
</head>
<body class="h-screen w-screen">
<div id="latest-apps" class="flex flex-col items-center bg-white/25 rounded-lg shadow-lg w-full h-full overflow-y-auto">
<h1 class="font-bold text-white">Latest Apps</h1>
<body class="text-white overflow-hidden">
<div
id="latest-apps"
class="flex flex-wrap p-2 gap-2 items-center backdrop-brightness-125 rounded-xl shadow-lg h-screen w-screen overflow-y-auto"
style="
scrollbar-color: transparent transparent;
scrollbar-width: none;
"
>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
@ -121,15 +143,12 @@ fn get_widget() -> String {
const container = document.getElementById('latest-apps');
data.forEach(app => {
const div = document.createElement('div');
div.className = 'm-2 grow self-stretch flex items-stretch m-2 p-2 rounded-lg shadow bg-white/25 font-sans';
div.className = 'app p-2 grow self-stretch flex items-stretch rounded-lg shadow bg-white/10 font-sans';
div.innerHTML = `${app.metadata.image ? `<div
class="rounded mr-2"
style="background-image: url('${app.metadata.image}');
background-cover: cover;
background-position: center;
width: 33%"
class="app-image rounded mr-2 grow"
style="background-image: url('${app.metadata.image}');"
></div>` : ''}
<div class="flex flex-col grow">
<div class="app-info flex flex-col grow">
<h2 class="font-bold">${app.metadata.name}</h2>
<p>${app.metadata.description}</p>
</div>`;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -14,8 +14,8 @@
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
<script type="module" crossorigin src="/main:app_store:sys/assets/index-rQKf2jeD.js"></script>
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-McZbj3o1.css">
<script type="module" crossorigin src="/main:app_store:sys/assets/index-C8ofW7WS.js"></script>
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-_Aqzph9X.css">
</head>
<body>

View File

@ -5,6 +5,7 @@ import Modal from "./Modal";
import { getAppName } from "../utils/app";
import Loader from "./Loader";
import classNames from "classnames";
import { useNavigate } from "react-router-dom";
interface ActionButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
app: AppInfo;
@ -17,6 +18,7 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
const [mirror, setMirror] = useState(app.metadata?.properties?.mirrors?.[0] || "Other");
const [customMirror, setCustomMirror] = useState("");
const [caps, setCaps] = useState<string[]>([]);
const [launchPath, setLaunchPath] = useState('');
const [loading, setLoading] = useState("");
const { clean, installed, downloaded, updatable } = useMemo(() => {
@ -42,9 +44,27 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
setMirror(app.metadata?.properties?.mirrors?.[0] || "Other");
}, [app.metadata?.properties?.mirrors]);
useEffect(() => {
if (installed) {
fetch('/apps').then(data => data.json())
.then((data: Array<{ package_name: string, path: string }>) => {
// console.log(data)
if (Array.isArray(data)) {
// console.log('is array')
const homepageAppData = data.find(otherApp => app.package === otherApp.package_name)
if (homepageAppData) {
// console.log('found the good appness', homepageAppData.package_name, homepageAppData.path);
setLaunchPath(homepageAppData.path)
}
}
})
}
}, [installed])
const onClick = useCallback(async () => {
if (installed && !updatable) {
window.alert("App is installed");
if (installed && !updatable && launchPath) {
window.location.href = `/${launchPath.replace('/', '')}`
return;
} else {
if (downloaded) {
getCaps(app).then((manifest) => {
@ -53,7 +73,7 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
}
setShowModal(true);
}
}, [app, installed, downloaded, updatable, setShowModal, getCaps]);
}, [app, installed, downloaded, updatable, setShowModal, getCaps, launchPath]);
const download = useCallback(async (e: FormEvent) => {
e.preventDefault();
@ -137,11 +157,16 @@ export default function ActionButton({ app, ...props }: ActionButtonProps) {
<button
{...props}
type="button"
className={classNames("text-sm min-w-[100px] px-2 py-1 self-start", props.className)}
className={classNames("text-sm min-w-[100px] px-2 py-1 self-start", props.className, {
'bg-orange': installed,
'hidden': installed && !updatable && !launchPath
})}
onClick={onClick}
>
{installed && updatable
? "Update"
: installed && launchPath
? "Launch"
: installed
? "Installed"
: downloaded

View File

@ -15,7 +15,7 @@ export default function AppEntry({ app, ...props }: AppEntryProps) {
<div {...props} key={appId(app)} className="flex justify-between w-full rounded hover:bg-white/10 card">
<AppHeader app={app} size="small" />
<div className="flex mr-1 items-start">
{!app.state?.caps_approved && <ActionButton app={app} className="mr-2" />}
<ActionButton app={app} className="mr-2" />
<MoreActions app={app} />
</div>
</div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -9,8 +9,8 @@
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
<script type="module" crossorigin src="/assets/index-CrxBodxP.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CUrqWKH8.css">
<script type="module" crossorigin src="/assets/index-DweJf-tr.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B_MpocZ4.css">
</head>
<body>

View File

@ -9,8 +9,8 @@
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
<script type="module" crossorigin src="/assets/index-CrxBodxP.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CUrqWKH8.css">
<script type="module" crossorigin src="/assets/index-DweJf-tr.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B_MpocZ4.css">
</head>
<body>

View File

@ -10,7 +10,7 @@ const AppsDock: React.FC = () => {
setFavoriteApps(apps.filter(a => a.is_favorite))
}, [apps])
return <div className='flex-center flex-wrap obox border border-orange gap-8'>
return <div className='flex-center flex-wrap obox border border-orange gap-8 !rounded-xl'>
{favoriteApps.length === 0 ? <div>Favorite an app to pin it to your dock.</div> : favoriteApps.map(app => <AppDisplay app={app} />)}
</div>
}

View File

@ -0,0 +1,31 @@
import { FaX } from "react-icons/fa6"
import { isMobileCheck } from "../utilities/dimensions"
import classNames from "classnames"
interface Props extends React.HTMLAttributes<HTMLDivElement> {
title: string
onClose: () => void
}
export const Modal: React.FC<Props> = ({ title, onClose, children }) => {
const isMobile = isMobileCheck()
return (
<div className="flex fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 place-items-center place-content-center backdrop-blur-md">
<div className={classNames("flex flex-col rounded-lg bg-black py-4 shadow-lg", {
'min-w-[500px] px-8 w-1/2': !isMobile,
'px-4 w-full': isMobile
})}>
<div className="flex">
<h1 className="grow">{title}</h1>
<button
className="icon self-start"
onClick={onClose}
>
<FaX />
</button>
</div>
{children}
</div>
</div>
)
}

View File

@ -0,0 +1,36 @@
import classNames from "classnames"
import useHomepageStore from "../store/homepageStore"
import { FaEye, FaEyeSlash } from "react-icons/fa6"
import { useState } from "react"
interface WidgetProps {
package_name: string,
widget: string
}
const Widget: React.FC<WidgetProps> = ({ package_name, widget }) => {
const { widgetSettings, toggleWidgetVisibility } = useHomepageStore()
const [isHovered, setIsHovered] = useState(false)
return <div
className={classNames("self-stretch flex flex-wrap shadow-lg rounded-lg relative", {
"min-w-full": widgetSettings[package_name]?.size === "large",
"min-w-1/2": !widgetSettings[package_name]?.size || widgetSettings[package_name]?.size === "small"
})}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<iframe
srcDoc={widget || ""}
className="grow self-stretch"
data-widget-code={widget}
/>
{isHovered && <button
className="absolute -top-2 -right-2 icon"
onClick={() => toggleWidgetVisibility(package_name)}
>
{widgetSettings[package_name]?.hide ? <FaEye /> : <FaEyeSlash />}
</button>}
</div>
}
export default Widget

View File

@ -1,14 +1,32 @@
import { FaGear } from "react-icons/fa6"
import useHomepageStore from "../store/homepageStore"
import Widget from "./Widget"
import WidgetsSettingsModal from "./WidgetsSettingsModal"
const Widgets = () => {
const { apps } = useHomepageStore()
return <div className="flex flex-wrap my-4 gap-4 flex-grow">
{apps.filter(app => app.widget).map(({ widget }) => <iframe
srcDoc={widget || ""}
className="min-w-1/4 shadow-lg"
data-widget-code={widget}
const { apps, showWidgetsSettings, setShowWidgetsSettings, widgetSettings } = useHomepageStore()
return <div className="flex-col-center m-4 gap-4 flex-grow self-stretch">
<h3 className="flex-center">
<span>
Widgets
</span>
<button
className="icon ml-4"
onClick={() => setShowWidgetsSettings(true)}
>
<FaGear />
</button>
</h3>
<div className="flex-center flex-wrap gap-4 flex-grow self-stretch">
{apps
.filter(app => app.widget)
.map(({ widget, package_name }) => !widgetSettings[package_name]?.hide && <Widget
package_name={package_name}
widget={widget!}
/>)}
</div>
{showWidgetsSettings && <WidgetsSettingsModal />}
</div>
}
export default Widgets

View File

@ -0,0 +1,53 @@
import { FaCheck, FaX } from "react-icons/fa6"
import useHomepageStore from "../store/homepageStore"
import { Modal } from "./Modal"
import classNames from "classnames"
const WidgetsSettingsModal = () => {
const { apps, setShowWidgetsSettings, toggleWidgetVisibility, widgetSettings, setWidgetSize } = useHomepageStore()
return <Modal
title='Widget Settings'
onClose={() => setShowWidgetsSettings(false)}
>
<div className="flex-col-center">
{apps.filter(app => app.widget).map(({ label, package_name }) => <div className="flex items-start">
<h4 className="mr-4">{label}</h4>
<div className="flex-col-center gap-6">
<div className="flex-center gap-4">
<button
className="icon"
onClick={() => toggleWidgetVisibility(package_name)}
>
{!widgetSettings[package_name]?.hide ? <FaCheck /> : <FaX />}
</button>
<label>Show widget</label>
</div>
<div className="flex-col-center gap-4">
<span>Widget size</span>
<div className="flex-center items-stretch gap-4">
<button
className={classNames({
'clear': widgetSettings[package_name]?.size === 'large'
})}
onClick={() => setWidgetSize(package_name, 'small')}
>
Small
</button>
<button
className={classNames({
'clear': widgetSettings[package_name]?.size !== 'large'
})}
onClick={() => setWidgetSize(package_name, 'large')}
>
Large
</button>
</div>
</div>
</div>
</div>)}
</div>
</Modal>
}
export default WidgetsSettingsModal

View File

@ -79,8 +79,8 @@ function Homepage() {
<KinodeBird />
</div>
<AppsDock />
<Widgets />
<AllApps />
<Widgets />
</div>
)
}

View File

@ -24,6 +24,17 @@ export interface HomepageStore {
apps: HomepageApp[]
setApps: (apps: HomepageApp[]) => void
widgetSettings: {
[key: string]: {
hide: boolean,
size: 'small' | 'large'
}
}
setWidgetSettings: (widgetSettings: HomepageStore['widgetSettings']) => void
toggleWidgetVisibility: (package_name: string) => void
setWidgetSize: (package_name: string, size: 'small' | 'large') => void
showWidgetsSettings: boolean
setShowWidgetsSettings: (showWidgetsSettings: boolean) => void
}
const useHomepageStore = create<HomepageStore>()(
@ -34,6 +45,28 @@ const useHomepageStore = create<HomepageStore>()(
apps: [],
setApps: (apps: HomepageApp[]) => set({ apps }),
widgetSettings: {},
setWidgetSettings: (widgetSettings: HomepageStore['widgetSettings']) => set({ widgetSettings }),
showWidgetsSettings: false,
setShowWidgetsSettings: (showWidgetsSettings: boolean) => set({ showWidgetsSettings }),
toggleWidgetVisibility: (package_name: string) => set({
widgetSettings: {
...get().widgetSettings,
[package_name]: {
...get().widgetSettings[package_name],
hide: !get().widgetSettings[package_name]?.hide
}
}
}),
setWidgetSize: (package_name: string, size: 'small' | 'large') => set({
widgetSettings: {
...get().widgetSettings,
[package_name]: {
...get().widgetSettings[package_name],
size
}
}
}),
isHosted: false,
setIsHosted: (isHosted: boolean) => set({ isHosted }),
fetchHostedStatus: async (our: string) => {

View File

@ -0,0 +1 @@
export const isMobileCheck = () => window.innerWidth <= 600

View File

@ -1 +1 @@
data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIiA/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHZlcnNpb249IjEuMSIgd2lkdGg9IjEwODAiIGhlaWdodD0iMTA4MCIgdmlld0JveD0iMCAwIDEwODAgMTA4MCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxkZXNjPkNyZWF0ZWQgd2l0aCBGYWJyaWMuanMgNS4yLjQ8L2Rlc2M+CjxkZWZzPgo8L2RlZnM+CjxnIHRyYW5zZm9ybT0ibWF0cml4KDEgMCAwIDEgNTQwIDU0MCkiIGlkPSI0MDhjZjk5Ni0xN2M1LTQxOTctYmVhMy1jNTQwZGJhYTlhZGUiICA+CjxyZWN0IHN0eWxlPSJzdHJva2U6IG5vbmU7IHN0cm9rZS13aWR0aDogMTsgc3Ryb2tlLWRhc2hhcnJheTogbm9uZTsgc3Ryb2tlLWxpbmVjYXA6IGJ1dHQ7IHN0cm9rZS1kYXNob2Zmc2V0OiAwOyBzdHJva2UtbGluZWpvaW46IG1pdGVyOyBzdHJva2UtbWl0ZXJsaW1pdDogNDsgZmlsbDogcmdiKDI1NSwyNTUsMjU1KTsgZmlsbC1ydWxlOiBub256ZXJvOyBvcGFjaXR5OiAxOyB2aXNpYmlsaXR5OiBoaWRkZW47IiB2ZWN0b3ItZWZmZWN0PSJub24tc2NhbGluZy1zdHJva2UiICB4PSItNTQwIiB5PSItNTQwIiByeD0iMCIgcnk9IjAiIHdpZHRoPSIxMDgwIiBoZWlnaHQ9IjEwODAiIC8+CjwvZz4KPGcgdHJhbnNmb3JtPSJtYXRyaXgoMSAwIDAgMSA1NDAgNTQwKSIgaWQ9ImM1MzhkOTdkLWFhNjAtNGRmNi05NzM1LTE4N2FlOGU3ODQwYyIgID4KPC9nPgo8ZyB0cmFuc2Zvcm09Im1hdHJpeChOYU4gTmFOIE5hTiBOYU4gMCAwKSIgID4KPGcgc3R5bGU9IiIgICA+CjwvZz4KPC9nPgo8ZyB0cmFuc2Zvcm09Im1hdHJpeCgyLjExIDAgMCAyLjExIDU0MCA1NDApIiAgPgo8cGF0aCBzdHlsZT0ic3Ryb2tlOiByZ2IoMCwwLDApOyBzdHJva2Utd2lkdGg6IDA7IHN0cm9rZS1kYXNoYXJyYXk6IG5vbmU7IHN0cm9rZS1saW5lY2FwOiBidXR0OyBzdHJva2UtZGFzaG9mZnNldDogMDsgc3Ryb2tlLWxpbmVqb2luOiBtaXRlcjsgc3Ryb2tlLW1pdGVybGltaXQ6IDQ7IGZpbGw6IHJnYigwLDAsMCk7IGZpbGwtcnVsZTogbm9uemVybzsgb3BhY2l0eTogMTsiICB0cmFuc2Zvcm09IiB0cmFuc2xhdGUoLTI1NiwgLTI1NikiIGQ9Ik0gNDEzLjk2NyAyNzYuOCBDIDQxNS4wMjcgMjcwLjU2NSA0MTUuMDI3IDI2My4yODIwMDAwMDAwMDAwNCA0MTUuMDI3IDI1NiBDIDQxNS4wMjcgMjQ4LjcxNzk5OTk5OTk5OTk2IDQxMy45NjcgMjQyLjQ4MiA0MTMuOTY3IDIzNS4yIEwgNDU4LjYzNCAyMDAuODgyIEMgNDYyLjg5NCAxOTcuNzY0IDQ2My45NTMwMDAwMDAwMDAwMyAxOTIuNTY1IDQ2MC43NjQgMTg3LjM2NCBMIDQxOC4yMTUgMTE1LjYgQyA0MTYuMDg1OTk5OTk5OTk5OTYgMTExLjQzNTk5OTk5OTk5OTk5IDQwOS43MDc5OTk5OTk5OTk5NyAxMDkuMzY1IDQwNS40NDggMTExLjQzNTk5OTk5OTk5OTk5IEwgMzUyLjI2MiAxMzIuMjM3IEMgMzQxLjYyNCAxMjMuOTE5IDMyOC44NjggMTE2LjYzNiAzMTYuMTAyIDExMS40MzU5OTk5OTk5OTk5OSBMIDMwOC42NTQgNTYuMzE4OTk5OTk5OTk5OTk2IEMgMzA3LjU5NCA1Mi4xNjQ5OTk5OTk5OTk5OSAzMDMuMzM1IDQ4LjAwMSAyOTguMDE2IDQ4LjAwMSBMIDIxMi45MTggNDguMDAxIEMgMjA3LjYgNDguMDAxIDIwMy4zNDEgNTIuMTY1IDIwMi4yODEgNTYuMzE4OTk5OTk5OTk5OTk2IEwgMTkzLjc3MyAxMTEuNDM1OTk5OTk5OTk5OTkgQyAxODEuMDA2IDExNi42MzYgMTY5LjMwOSAxMjMuOTE3OTk5OTk5OTk5OTkgMTU3LjYwMiAxMzIuMjM3IEwgMTA0LjQxNiAxMTEuNDM1OTk5OTk5OTk5OTkgQyA5OS4wOTcgMTA5LjM2NSA5My43Nzc5OTk5OTk5OTk5OSAxMTEuNDM1OTk5OTk5OTk5OTkgOTEuNjQ5IDExNS42IEwgNDkuMSAxODcuMzY1IEMgNDYuOTgxIDE5MS41MTggNDguMDM5IDE5Ny43NjQgNTEuMjI5IDIwMC44ODMgTCA5Ni45NyAyMzUuMiBDIDk2Ljk3IDI0Mi40ODIgOTUuOTEgMjQ4LjcxOCA5NS45MSAyNTYgQyA5NS45MSAyNjMuMjgyMDAwMDAwMDAwMDQgOTYuOTcgMjY5LjUxODAwMDAwMDAwMDAzIDk2Ljk3IDI3Ni44IEwgNTIuMzAyIDMxMS4xMTggQyA0OC4wNDIgMzE0LjIzNiA0Ni45ODQgMzE5LjQzNSA1MC4xNzIgMzI0LjYzNTk5OTk5OTk5OTk3IEwgOTIuNzIxIDM5Ni40IEMgOTQuODUxIDQwMC41NjM5OTk5OTk5OTk5NiAxMDEuMjI5IDQwMi42MzUgMTA1LjQ4OCA0MDAuNTYzOTk5OTk5OTk5OTYgTCAxNTguNjc1IDM3OS43NjMgQyAxNjkuMzEyIDM4OC4wODA5OTk5OTk5OTk5NiAxODIuMDY5MDAwMDAwMDAwMDIgMzk1LjM2NCAxOTQuODM1IDQwMC41NjM5OTk5OTk5OTk5NiBMIDIwMy4zNDMwMDAwMDAwMDAwMiA0NTUuNjgxIEMgMjA0LjQxMiA0NjAuODgxIDIwOC42NjEwMDAwMDAwMDAwMyA0NjMuOTk4OTk5OTk5OTk5OTcgMjEzLjk4MDAwMDAwMDAwMDAyIDQ2My45OTg5OTk5OTk5OTk5NyBMIDI5OS4wNzgwMDAwMDAwMDAwMyA0NjMuOTk4OTk5OTk5OTk5OTcgQyAzMDQuMzk3MDAwMDAwMDAwMDUgNDYzLjk5ODk5OTk5OTk5OTk3IDMwOC42NTYgNDU5LjgzNSAzMDkuNzE2IDQ1NS42ODEgTCAzMTguMjM0MDAwMDAwMDAwMDQgNDAwLjU2Mzk5OTk5OTk5OTk2IEMgMzMwLjk5MTAwMDAwMDAwMDA0IDM5NS4zNjQgMzQyLjY5ODAwMDAwMDAwMDA0IDM4OC4wODIgMzU0LjM5NCAzNzkuNzYzIEwgNDA3LjU4MSA0MDAuNTYzOTk5OTk5OTk5OTYgQyA0MTIuODk5IDQwMi42MzUgNDE4LjIxOCA0MDAuNTYzOTk5OTk5OTk5OTYgNDIwLjM0OCAzOTYuNCBMIDQ2Mi44OTcgMzI0LjYzNSBDIDQ2NS4wMjYgMzIwLjQ4MTk5OTk5OTk5OTk3IDQ2My45NTcgMzE0LjIzNiA0NjAuNzY3IDMxMS4xMTY5OTk5OTk5OTk5NiBMIDQxMy45NjcgMjc2Ljc5OTk5OTk5OTk5OTk1IHogTSAyNTUuNDY4IDMyOC44IEMgMjEzLjk3ODk5OTk5OTk5OTk4IDMyOC44IDE4MS4wMDc5OTk5OTk5OTk5OCAyOTYuNTY1IDE4MS4wMDc5OTk5OTk5OTk5OCAyNTYgQyAxODEuMDA3OTk5OTk5OTk5OTggMjE1LjQzNSAyMTMuOTc4OTk5OTk5OTk5OTggMTgzLjIgMjU1LjQ2Nzk5OTk5OTk5OTk2IDE4My4yIEMgMjk2Ljk1Njk5OTk5OTk5OTk0IDE4My4yIDMyOS45MjkgMjE1LjQzNSAzMjkuOTI5IDI1NiBDIDMyOS45MjkgMjk2LjU2NSAyOTYuOTU3IDMyOC44IDI1NS40Njc5OTk5OTk5OTk5NiAzMjguOCB6IiBzdHJva2UtbGluZWNhcD0icm91bmQiIC8+CjwvZz4KPC9zdmc+
data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTM2IiBoZWlnaHQ9IjEzNiIgdmlld0JveD0iMCAwIDEzNiAxMzYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMzYiIGhlaWdodD0iMTM2IiByeD0iNjgiIGZpbGw9IiNGRkY1RDkiIGZpbGwtb3BhY2l0eT0iMC40Ii8+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xODIxXzkwOTMpIj4KPHBhdGggZD0iTTY3LjQ4NTUgOTQuOTg4MUM2NS44MTYxIDk0Ljk4ODEgNjQuMTQ2NyA5NC45NjQzIDYyLjQ3NzIgOTQuOTg4MUM2MS41NjAyIDk1LjAxMTkgNjEuMDQyOSA5NC40MTc0IDYwLjkzNzEgOTMuNjQ0N0M2MC42NjY3IDkxLjU1MjMgNjAuMzQ5MyA4OS40NTk4IDYwLjA2NzEgODcuMzY3NEM2MC4wMjAxIDg3LjAxMDggNTkuODc5IDg2Ljc5NjggNTkuNTM4MSA4Ni42NTQxQzU4LjIzMzEgODYuMDgzNCA1Ny4wMjIyIDg1LjM1ODIgNTUuODgxOCA4NC40OTA0QzU1LjYyMzEgODQuMjg4MiA1NS4zOTk4IDg0LjI2NDUgNTUuMDk0MSA4NC4zOTUyQzUzLjE1NDMgODUuMjAzNyA1MS4yMTQ0IDg1Ljk4ODMgNDkuMjc0NiA4Ni43NzNDNDguMjc1MyA4Ny4xNzcyIDQ3Ljc5MzMgODcuMDIyNyA0Ny4yNTI1IDg2LjA5NTNDNDUuNTcxMyA4My4xNTg4IDQzLjg5MDEgODAuMjEwNCA0Mi4yMDg5IDc3LjI2MkM0MS44MDkyIDc2LjU3MjUgNDEuOTI2NyA3NS45NDIzIDQyLjU0OTggNzUuNDQzQzQ0LjIzMSA3NC4wOTk2IDQ1LjkxMjIgNzIuNzU2MiA0Ny42MDUyIDcxLjQzNjVDNDcuODk5MSA3MS4yMTA2IDQ4LjAwNDkgNzAuOTYxIDQ3Ljk1NzkgNzAuNTkyNEM0Ny43ODE1IDY5LjIwMTQgNDcuNzkzMyA2Ny43OTg2IDQ3Ljk1NzkgNjYuNDA3NkM0OC4wMDQ5IDY2LjA1MDkgNDcuOTEwOCA2NS44MTMxIDQ3LjYyODcgNjUuNTg3M0M0NS45OTQ1IDY0LjMwMzMgNDQuMzYwNCA2My4wMDc0IDQyLjczNzkgNjEuNzExNUM0MS44Nzk3IDYxLjAzMzkgNDEuNzczOSA2MC41MTA4IDQyLjMxNDcgNTkuNTcxNkM0NC4wMDc3IDU2LjYxMTMgNDUuNjg4OCA1My42MzkxIDQ3LjM5MzYgNTAuNjc4OEM0Ny43NDYyIDUwLjA3MjUgNDguMzgxMSA0OS44NTg1IDQ5LjA3NDcgNTAuMTQzOEM1MC40MjY3IDUwLjY5MDcgNTEuNzc4OCA1MS4yMzc1IDUzLjEzMDggNTEuNzk2M0M1My44MjQ0IDUyLjA4MTcgNTQuNTE4IDUyLjM1NTEgNTUuMjExNyA1Mi42NTIzQzU1LjQyMzMgNTIuNzQ3NCA1NS41ODc5IDUyLjczNTUgNTUuNzc2IDUyLjU5MjlDNTYuOTg2OSA1MS42NjU1IDU4LjMwMzYgNTAuODkyOCA1OS43MDI3IDUwLjI4NjVDNTkuOTQ5NiA1MC4xNzk1IDYwLjAyMDEgNDkuOTg5MiA2MC4wNDM2IDQ5Ljc1MTVDNjAuMzE0IDQ3LjgxMzYgNjAuNTg0NCA0NS44NzU3IDYwLjg1NDggNDMuOTM3OUM2MC44OTAxIDQzLjcxMiA2MC45MTM2IDQzLjQ4NjEgNjAuOTQ4OSA0My4yNjAyQzYxLjA5IDQyLjQxNjEgNjEuNTYwMiA0MiA2Mi4zNzE0IDQyQzY0LjQ0MDYgNDIgNjYuNTA5NyA0MiA2OC41Nzg5IDQyQzY5LjkwNzQgNDIgNzEuMjQ3NiA0MiA3Mi41NzYxIDQyQzczLjQ0NjEgNDIgNzMuOTI4MSA0Mi40NTE4IDc0LjA1NzUgNDMuMzMxNUM3NC4zNTE0IDQ1LjQzNTggNzQuNjQ1MyA0Ny41NDAyIDc0LjkyNzQgNDkuNjQ0NUM3NC45NzQ1IDQ5Ljk4OTIgNzUuMTE1NSA1MC4xNzk1IDc1LjQzMyA1MC4zMzRDNzYuNzM4IDUwLjkxNjYgNzcuOTcyNCA1MS42Mjk5IDc5LjExMjggNTIuNTA5NkM3OS4zNTk3IDUyLjY5OTkgNzkuNTU5NSA1Mi43MjM2IDc5Ljg0MTcgNTIuNjA0OEM4MS44MDUgNTEuNzk2MyA4My43Njg0IDUwLjk4NzkgODUuNzQzNSA1MC4xOTEzQzg2LjY3MjMgNDkuODEwOSA4Ny4yMTMxIDUwLjAxMyA4Ny43MTg2IDUwLjg5MjhDODkuMzc2MyA1My44MDU1IDkxLjAzMzkgNTYuNzE4MyA5Mi42OTE2IDU5LjYxOTFDOTMuMTczNiA2MC40NTEzIDkzLjA2NzggNjEuMDIyIDkyLjMxNTQgNjEuNjI4M0M5MC42NDYgNjIuOTU5OCA4OC45NzY1IDY0LjI3OTUgODcuMjk1NCA2NS41ODczQzg3LjAyNDkgNjUuODAxMyA4Ni45NDI3IDY2LjAyNzEgODYuOTc3OSA2Ni4zNkM4Ny4xNTQzIDY3Ljc4NjcgODcuMTU0MyA2OS4yMTMzIDg2Ljk3NzkgNzAuNjRDODYuOTQyNyA3MC45NjEgODcuMDI1IDcxLjE4NjkgODcuMjgzNiA3MS4zODlDODguOTI5NSA3Mi42ODQ4IDkwLjU3NTQgNzMuOTkyNiA5Mi4yMjE0IDc1LjMwMDRDOTMuMDU2MSA3NS45NjYxIDkzLjE2MTkgNzYuNDg5MiA5Mi42MzI4IDc3LjQxNjZDOTAuOTc1MiA4MC4zNDEyIDg5LjMwNTcgODMuMjUzOSA4Ny42MzYzIDg2LjE2NjdDODcuMTg5NSA4Ni45NTEzIDg2LjYwMTcgODcuMTUzNCA4NS43NjcgODYuODA4N0M4My44MDM3IDg2LjAxMjEgODEuODUyMSA4NS4yMTU2IDc5LjkwMDUgODQuNDA3MUM3OS41NzEzIDg0LjI2NDUgNzkuMzI0NCA4NC4yODgyIDc5LjAzMDUgODQuNTE0MUM3Ny45MDE5IDg1LjM5MzkgNzYuNjc5MiA4Ni4wOTUzIDc1LjM3NDIgODYuNjY2Qzc1LjA2ODUgODYuNzk2OCA3NC45MzkyIDg2Ljk4NyA3NC44OTIyIDg3LjMwOEM3NC42MSA4OS40MDA0IDc0LjMxNjEgOTEuNDkyOCA3NC4wMTA0IDkzLjU4NTJDNzMuOTYzNCA5My45MDYyIDczLjgzNDEgOTQuMjI3MiA3My42Njk1IDk0LjUwMDdDNzMuNDM0NCA5NC44NTczIDczLjA1ODEgOTQuOTg4MSA3Mi42MjMxIDk0Ljk4ODFDNzAuOTA2NyA5NC45ODgxIDY5LjE3ODUgOTQuOTg4MSA2Ny40NjIgOTQuOTg4MUg2Ny40ODU1Wk02Ny40NzM4IDU5LjE1NTVDNjIuNDMwMiA1OS4xNTU1IDU4LjI2ODQgNjMuMzUyMiA1OC4yNTY2IDY4LjQ2NDNDNTguMjQ0OSA3My42MDAzIDYyLjQwNjcgNzcuODIwOCA2Ny40ODU1IDc3LjgyMDhDNzIuNTUyNiA3Ny44MjA4IDc2LjcxNDQgNzMuNjEyMiA3Ni43MTQ0IDY4LjQ4ODFDNzYuNzE0NCA2My4zNDAzIDcyLjU2NDQgNTkuMTU1NSA2Ny40NjIgNTkuMTQzNkw2Ny40NzM4IDU5LjE1NTVaIiBmaWxsPSIjRkZGNUQ5Ii8+CjwvZz4KPGRlZnM+CjxjbGlwUGF0aCBpZD0iY2xpcDBfMTgyMV85MDkzIj4KPHJlY3Qgd2lkdGg9IjUxIiBoZWlnaHQ9IjUzIiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDIgNDIpIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==

View File

@ -11,7 +11,7 @@
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover" />
<script type="module" crossorigin src="/assets/index-CHbSl3FU.js"></script>
<script type="module" crossorigin src="/assets/index-zSMkg4LY.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-UCAeMvu5.css">
</head>

View File

@ -1,4 +1,21 @@
<svg width="779" height="514" viewBox="0 0 779 514" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M753.092 5.91932C756.557 5.09976 755.962 -0.00012207 752.401 -0.00012207H426.001C424.755 -0.00012207 423.639 0.77027 423.197 1.93535L236.968 492.6C235.729 495.865 240.123 498.255 242.191 495.441L569.357 50.1132C569.778 49.5392 570.391 49.1339 571.084 48.97L753.092 5.91932Z" fill="#FFF5D9"/>
<path d="M11.9665 40.2288C9.10949 38.777 10.2135 34.4583 13.4167 34.5557L404.273 46.4367C406.334 46.4993 407.719 48.5749 406.986 50.5023L347.438 206.981C346.804 208.647 344.865 209.396 343.275 208.588L11.9665 40.2288Z" fill="#FFF5D9"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="779"
height="514"
viewBox="0 0 779 514"
fill="none"
version="1.1"
id="svg2"
xmlns="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<path
d="M753.092 5.91932C756.557 5.09976 755.962 -0.00012207 752.401 -0.00012207H426.001C424.755 -0.00012207 423.639 0.77027 423.197 1.93535L236.968 492.6C235.729 495.865 240.123 498.255 242.191 495.441L569.357 50.1132C569.778 49.5392 570.391 49.1339 571.084 48.97L753.092 5.91932Z"
fill="#FFF5D9"
id="path1" />
<path
d="M 12.054907,40.2288 C 9.0444768,38.777 10.207772,34.4583 13.582982,34.5557 l 411.845088,11.881 c 2.17167,0.0626 3.63105,2.1382 2.85869,4.0656 l -62.7457,156.4787 c -0.66805,1.666 -2.71117,2.415 -4.38655,1.607 z"
fill="#fff5d9"
id="path2"
style="stroke-width:1.0265" />
</svg>

Before

Width:  |  Height:  |  Size: 644 B

After

Width:  |  Height:  |  Size: 864 B