moved files from material repo to mono repo

This commit is contained in:
FloVanGH 2025-03-28 14:35:46 +01:00
parent 8faa22292e
commit 615f400fa8
182 changed files with 14080 additions and 1 deletions

View file

@ -46,7 +46,7 @@ jobs:
- name: Remaining wasm demos
if: ${{ inputs.build_artifacts }}
run: |
for demo in demos/printerdemo/rust demos/usecases/rust examples/todo/rust examples/todo-mvc/rust examples/carousel/rust examples/slide_puzzle examples/memory examples/imagefilter/rust examples/plotter examples/opengl_underlay demos/home-automation/rust; do
for demo in demos/printerdemo/rust demos/usecases/rust examples/todo/rust examples/todo-mvc/rust examples/carousel/rust examples/slide_puzzle examples/memory examples/imagefilter/rust examples/plotter examples/opengl_underlay demos/home-automation/rust component-sets/material/examples/gallery; do
pushd $demo
sed -i "s/#wasm# //" Cargo.toml
wasm-pack build --release --target web
@ -83,6 +83,7 @@ jobs:
demos/home-automation/rust
demos/weather-demo/
demos/usecases/rust
component-sets/material/examples/gallery/
!/**/.gitignore
- name: Clean cache # Otherwise the cache is much too big
run: |

View file

@ -69,6 +69,8 @@ members = [
'tools/viewer',
'tools/tr-extractor',
'xtask',
'component-sets/material',
'component-sets/material/examples/gallery',
]
default-members = [

View file

@ -185,6 +185,8 @@ SPDX-License-Identifier = "MIT"
[[annotations]]
path = [
"internal/compiler/widgets/material/_**.svg",
"component-sets/material/ui/icons/**.svg",
"component-sets/material/examples/gallery/ui/icons/**.svg",
"examples/carousel/icons/**.svg",
"internal/compiler/widgets/cupertino/_**.svg",
"internal/compiler/widgets/qt/_**.svg",

View file

@ -0,0 +1,14 @@
# Copyright © SixtyFPS GmbH <info@slint.dev>
# SPDX-License-Identifier: MIT
[package]
name = "slint-material"
authors.workspace = true
edition.workspace = true
repository.workspace = true
license = "MIT"
description = "Material Design 3 component set for Slint"
version.workspace = true
homepage = "https://slint.rs"
rust-version.workspace = true

View file

29
component-sets/material/docs/.gitignore vendored Normal file
View file

@ -0,0 +1,29 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
# More to ignore
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/src/assets/generated/

View file

@ -0,0 +1,93 @@
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
<!-- cSpell: ignore docsnapper -->
# Slint Material Component Documentation
## Prerequisites
- Rust
- Node.js
- pnpm
## 🚀 Project Structure
The documentation site is built with [Astro Starlight](https://starlight.astro.build/) and reuses it's
project structure.
```
docs/
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ │ └── config.ts
│ └── env.d.ts
├── tests/
├── astro.config.mjs
├── package.json
├── tsconfig.json
└──
```
Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.
Images can be added to `src/assets/` and embedded in Markdown with a relative link. They will be optimized
for download size and also their width and height will be extracted so the framework can render them without
ugly content shifts.
Static assets, like favicons, can be placed in the `public/` directory. Note that images in this folder will
not be processed and optimized by Starlight.
## Building the docs
The docs use a lot of autogenerated content. First create all the screenshots which will be placed at `src/assets/generated/`.
```bash
cargo run -p slint-docsnapper -- docs/astro/src/content --overwrite
```
Then generate the slint auto generated content.
```bash
cargo xtask slintdocs
```
This xtask also installs the npm dependencies and builds the docs. The equivalent of:
```bash
pnpm i
pnpm run build
```
This will build the site and place it in `dist/`.
## Live edit the docs
To run the live hot reloading dev server run in the astro directory:
```bash
cd docs/astro/
pnpm start
```
This will start the dev server at [`localhost:4321/docs/`](http://localhost:4321/docs/).
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `pnpm i` | Installs dependencies |
| `pnpm start` | Starts local dev server at `localhost:4321` |
| `pnpm build` | Build your production site to `./dist/` |
| `pnpm preview` | Preview your build locally, before deploying |
| `pnpm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more about Astro and Starlight?
Check out [Starlights docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).

View file

@ -0,0 +1,65 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
// @ts-check
import { defineConfig } from "astro/config";
import starlight from "@astrojs/starlight";
import starlightLinksValidator from "starlight-links-validator";
import rehypeExternalLinks from "rehype-external-links";
// https://astro.build/config
export default defineConfig({
trailingSlash: "always",
markdown: {
rehypePlugins: [
[
rehypeExternalLinks,
{
content: {
type: "text",
value: " ↗",
},
properties: {
target: "_blank",
},
rel: ["noopener"],
},
],
],
},
integrations: [
starlight({
title: "Slint Docs",
logo: {
src: "./src/assets/slint-logo-small-light.svg",
},
customCss: ["./src/styles/custom.css", "./src/styles/theme.css"],
components: {
Footer: "./src/components/Footer.astro",
Header: "./src/components/Header.astro",
Banner: "./src/components/Banner.astro",
},
sidebar: [
{ label: "Overview", link: "index" },
{ label: "Style", link: "style" },
{
label: "Basic Widgets",
autogenerate: { directory: "basic-widgets" },
},
],
plugins: [
starlightLinksValidator({
errorOnLocalLinks: false,
}),
],
social: {
github: "https://github.com/slint-ui/slint",
"x.com": "https://x.com/slint_ui",
linkedin: "https://www.linkedin.com/company/slint-ui/",
mastodon: "https://fosstodon.org/@slint",
},
favicon: "favicon.svg",
}),
],
});

View file

@ -0,0 +1,57 @@
{
"formatter": {
"ignore": ["archive/**", ".astro", "dist", "codemirror.js"],
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 4,
"lineEnding": "lf",
"attributePosition": "auto"
},
"linter": {
"ignore": ["archive/**", ".astro", "dist", "codemirror.js"],
"rules": {
"recommended": false,
"complexity": {
"noBannedTypes": "warn",
"noUselessConstructor": "error"
},
"style": {
"useBlockStatements": "warn",
"noUselessElse": "off",
"useConst": "error",
"useImportType": "error",
"useNodejsImportProtocol": "error"
},
"suspicious": {
"noDoubleEquals": "error",
"noRedundantUseStrict": "warn",
"noImplicitAnyLet": "error"
}
}
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"semicolons": "always",
"bracketSpacing": true,
"bracketSameLine": false,
"quoteStyle": "double",
"attributePosition": "auto"
}
},
"overrides": [
{
"include": ["*.astro"],
"linter": {
"rules": {
"style": {
"useConst": "off",
"useImportType": "off"
}
}
}
}
]
}

View file

@ -0,0 +1,199 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
/** @type {import('@astrojs/starlight/expressive-code').StarlightExpressiveCodeOptions} */
import { definePlugin } from "@expressive-code/core";
import { h } from "@expressive-code/core/hast";
import fs from "node:fs";
import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers";
function sideBorder() {
return definePlugin({
name: "Adds side border to slint code blocks",
baseStyles: `
.sideBar {
position: absolute;
top: calc(var(--button-spacing) - 6px);
bottom: 0;
left: 0;
width: 100px;
border-left-width: 2px;
border-left-style: solid;
border-color: #2479f4;
border-top-left-radius: 0.4rem;
border-bottom-left-radius: 0.4rem;
pointer-events: none;
}
`,
hooks: {
postprocessRenderedBlock: async (context) => {
if (
context.renderData.blockAst.children[1].properties
.dataLanguage !== "slint"
) {
return;
}
const side = h("div.sideBar");
const ast = context.renderData.blockAst;
ast.children.push(side);
context.renderData.blockAst = ast;
},
},
});
}
function remapLanguageIdentifiers(lang) {
switch (lang) {
case "cpp": {
return "C++";
}
case "sh": {
return "bash";
}
default: {
return lang;
}
}
}
function languageLabel() {
return definePlugin({
name: "Adds language label to code blocks",
baseStyles: `
.language-label {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset-block-start: calc(var(--ec-brdWd) + var(--button-spacing));
inset-inline-end: calc(var(--ec-brdWd) + var(--ec-uiPadInl) );
direction: ltr;
font-size: 0.8rem;
color:rgb(169, 169, 169);
opacity: 1;
transition: opacity 0.3s;
}
div.expressive-code:hover .language-label,
.expressive-code:hover .language-label {
opacity: 0;
}
`,
hooks: {
postprocessRenderedBlock: async (context) => {
const language =
context.renderData.blockAst.children[1].properties
.dataLanguage;
const label = h("div.language-label", {}, [
remapLanguageIdentifiers(language),
]);
const ast = context.renderData.blockAst;
ast.children.push(label);
context.renderData.blockAst = ast;
},
},
});
}
function workersPlaygroundButton() {
return definePlugin({
name: "Adds 'Run in SlintPad' button to slint codeblocks",
baseStyles: `
.run {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset-block-start: calc(var(--ec-brdWd) + var(--button-spacing));
inset-inline-end: calc(var(--ec-brdWd) + var(--ec-uiPadInl) * 3);
direction: ltr;
unicode-bidi: isolate;
background-color: color-mix(in srgb, var(--sl-color-accent) 50%, transparent);
color: var(--sl-color-white);
text-decoration: none;
width: 2rem;
height: 2rem;
border-radius: 50%;
opacity: 0;
font-size: 0;
transition: opacity 0.3s, background-color 0.3s;
&:hover {
background-color: color-mix(in srgb, var(--sl-color-accent) 90%, transparent);
}
&::before {
content: '';
display: inline-block;
margin-left: 0.25rem;
border-style: solid;
border-width: 0.5rem 0 0.5rem 0.75rem;
border-color: transparent transparent transparent white;
}
}
div.expressive-code:hover .run,
.expressive-code:hover .run {
opacity: 1;
}
`,
hooks: {
postprocessRenderedBlock: async (context) => {
if (!context.codeBlock.meta.includes("playground")) {
return;
}
const content = context.codeBlock.code;
const url = `https://slintpad.com?snippet=${encodeURIComponent(content)}`;
const runButton = h(
"a.run",
{
href: url,
target: "__blank",
title: "Open in SlintPad",
},
[],
);
const ast = context.renderData.blockAst;
ast.children.push(runButton);
context.renderData.blockAst = ast;
},
},
});
}
export default {
plugins: [
workersPlaygroundButton(),
sideBorder(),
languageLabel(),
pluginLineNumbers(),
],
defaultProps: {
showLineNumbers: false,
},
themes: ["dark-plus", "light-plus"],
styleOverrides: {
borderRadius: "0.4rem",
borderColor: "var(--slint-code-background)",
frames: { shadowColor: "transparent" },
codeBackground: "var(--slint-code-background)",
},
shiki: {
langs: [
JSON.parse(
fs.readFileSync("src/misc/Slint-tmLanguage.json", "utf-8"),
),
],
},
frames: {
extractFileNameFromCode: false,
},
};

View file

@ -0,0 +1,43 @@
{
"name": "slint-docs",
"type": "module",
"version": "1.11.0",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro",
"format": "biome format",
"format:fix": "biome format --write",
"lint": "biome lint",
"lint:fix": "biome lint --fix",
"spellcheck": "cspell --no-progress --gitignore --exclude 'archive/**' \"./**/*.{md,mdx}\"",
"type-check": "astro check",
"test": "playwright test",
"test:ui": "playwright test --ui"
},
"dependencies": {
"@astrojs/check": "0.9.4",
"@astrojs/starlight": "0.32.4",
"@expressive-code/plugin-line-numbers": "0.40.2",
"@types/node": "20.16.10",
"astro": "5.5.5",
"astro-embed": "0.9.0",
"playwright": "1.51.1",
"playwright-ctrf-json-reporter": "0.0.19",
"rehype-external-links": "3.0.0",
"sharp": "0.33.5",
"starlight-links-validator": "0.14.3",
"typescript": "5.8.2"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
"@expressive-code/core": "^0.40.2",
"@playwright/test": "1.51.1",
"cspell": "8.17.5"
},
"pnpm": {
"onlyBuiltDependencies": ["@biomejs/biome", "esbuild", "sharp"]
}
}

View file

@ -0,0 +1,91 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { defineConfig, devices } from "@playwright/test";
import { BASE_PATH } from "./src/utils/site-config";
/**
* Read environment variables from file.
* https://github.com/motdotla/dotenv
*/
// import dotenv from 'dotenv';
// import path from 'path';
// dotenv.config({ path: path.resolve(__dirname, '.env') });
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [
["html"], // You can combine multiple reporters
[
"playwright-ctrf-json-reporter",
{
outputFile: "ctrf-report.json",
outputDir: "playwright-report",
},
],
],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: `http://localhost:4321${BASE_PATH}`,
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
{
name: "firefox",
use: { ...devices["Desktop Firefox"] },
},
{
name: "webkit",
use: { ...devices["Desktop Safari"] },
},
/* Test against mobile viewports. */
// {
// name: 'Mobile Chrome',
// use: { ...devices['Pixel 5'] },
// },
// {
// name: 'Mobile Safari',
// use: { ...devices['iPhone 12'] },
// },
/* Test against branded browsers. */
// {
// name: 'Microsoft Edge',
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
// },
// {
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
],
/* Run your local dev server before starting the tests */
webServer: {
command: "pnpm run preview",
url: `http://localhost:4321${BASE_PATH}`,
reuseExistingServer: !process.env.CI,
timeout: 120 * 1000,
},
});

5957
component-sets/material/docs/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(2.6609,0,0,2.6609,-21.0422,-21.1618)">
<path d="M20.663,55.828L48.733,37.031C48.733,37.031 50,36.328 50,35.218C50,33.741 48.398,33.26 48.398,33.26L32.956,27.355C32.405,27.146 31.646,27.731 32.356,28.473L37.469,33.417C37.469,33.417 38.889,34.765 38.889,35.649C38.889,36.534 38.017,37.322 38.017,37.322L19.414,54.691C18.752,55.309 19.646,56.429 20.663,55.828Z" style="fill:rgb(35,121,244);fill-rule:nonzero;"/>
</g>
<g transform="matrix(2.6609,0,0,2.6609,-21.0422,-21.1618)">
<path d="M43.337,8.173L15.267,26.968C15.267,26.968 14,27.671 14,28.78C14,30.258 15.602,30.739 15.602,30.739L31.044,36.646C31.595,36.852 32.356,36.267 31.644,35.529L26.531,30.568C26.531,30.568 25.111,29.223 25.111,28.336C25.111,27.448 25.983,26.663 25.983,26.663L44.575,9.308C45.248,8.69 44.356,7.569 43.337,8.173Z" style="fill:rgb(35,121,244);fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -0,0 +1,4 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.6632 55.828L48.7333 37.0309C48.7333 37.0309 50 36.3278 50 35.2182C50 33.7406 48.3981 33.2599 48.3981 33.2599L32.9557 27.355C32.4047 27.1462 31.6464 27.7312 32.3564 28.4728L37.4689 33.4165C37.4689 33.4165 38.889 34.765 38.889 35.6494C38.889 36.5338 38.017 37.322 38.017 37.322L19.4135 54.6909C18.7517 55.3089 19.6464 56.4294 20.6632 55.828Z" fill="white"/>
<path d="M43.3368 8.17339L15.2667 26.9677C15.2667 26.9677 14 27.6708 14 28.7804C14 30.258 15.6019 30.7387 15.6019 30.7387L31.0443 36.6464C31.5953 36.8524 32.3565 36.2674 31.6436 35.5286L26.5311 30.5684C26.5311 30.5684 25.111 29.2226 25.111 28.3355C25.111 27.4483 25.983 26.6628 25.983 26.6628L44.5752 9.30769C45.2483 8.68973 44.3565 7.56916 43.3368 8.17339Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 846 B

View file

@ -0,0 +1,4 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.6632 55.828L48.7333 37.0309C48.7333 37.0309 50 36.3278 50 35.2182C50 33.7406 48.3981 33.2599 48.3981 33.2599L32.9557 27.355C32.4047 27.1462 31.6464 27.7312 32.3564 28.4728L37.4689 33.4165C37.4689 33.4165 38.889 34.765 38.889 35.6494C38.889 36.5338 38.017 37.322 38.017 37.322L19.4135 54.6909C18.7517 55.3089 19.6464 56.4294 20.6632 55.828Z" fill="#2379F4"/>
<path d="M43.3368 8.17339L15.2667 26.9677C15.2667 26.9677 14 27.6708 14 28.7804C14 30.258 15.6019 30.7387 15.6019 30.7387L31.0443 36.6464C31.5953 36.8524 32.3565 36.2674 31.6436 35.5286L26.5311 30.5684C26.5311 30.5684 25.111 29.2226 25.111 28.3355C25.111 27.4483 25.983 26.6628 25.983 26.6628L44.5752 9.30769C45.2483 8.68973 44.3565 7.56916 43.3368 8.17339Z" fill="#2379F4"/>
</svg>

After

Width:  |  Height:  |  Size: 850 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,10 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import Default from "@astrojs/starlight/components/Banner.astro";
import VersionBanner from "./VersionBanner.astro";
---
<VersionBanner {...Astro.locals.starlightRoute} />
<Default ><slot /></Default>

View file

@ -0,0 +1,38 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import "@astrojs/starlight/style/markdown.css";
import type { ImageMetadata } from "astro";
import { Image } from "astro:assets";
interface Props {
imagePath: string;
imageAlt: string;
imageWidth: number;
imageHeight: number;
needsBackground?: boolean;
skip?: boolean;
scale?: number;
}
const { imagePath, imageAlt, skip, needsBackground } = Astro.props as Props;
const images = import.meta.glob<{ default: ImageMetadata }>(
"/src/assets/generated/*.{jpeg,jpg,png,gif}",
);
if (!images[imagePath]) {
throw new Error(
`"${imagePath}" does not exist in glob: "src/assets/generated/*.{jpeg,jpg,png,gif}"`,
);
}
const imageSrc = images[imagePath]();
const imageCSS = `image-block ${needsBackground ? "screenshot-container" : ""}`;
---
{!skip && <div class="code-image-container">
<div class="code-block">
<slot/>
</div>
<div class={imageCSS}>
<Image src={imageSrc} alt={imageAlt} />
</div>
</div>}

View file

@ -0,0 +1,24 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import Default from "@astrojs/starlight/components/Footer.astro";
const year = new Date().getFullYear();
---
<Default ><slot /></Default>
<hr />
<p>&copy; {year} SixtyFPS GmbH</p>
<style>
p {
text-align: center;
color: var(--sl-color-gray-2);
font-size: var(--sl-text-sm);
}
hr {
border: 0;
border-bottom: 1px solid var(--sl-color-hairline);
}
</style>

View file

@ -0,0 +1,38 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
interface Props {
stagger?: boolean;
}
const { stagger = false } = Astro.props;
---
<div class:list={["card-grid", { stagger }]}><slot /></div>
<style>
.card-grid {
display: grid;
gap: 1rem;
}
.card-grid > :global(*) {
margin-top: 0 !important;
}
@media (min-width: 50rem) {
.card-grid {
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 1.5rem;
}
.stagger {
--stagger-height: 5rem;
padding-bottom: var(--stagger-height);
}
.stagger > :global(*):nth-child(2n) {
transform: translateY(var(--stagger-height));
}
}
</style>

View file

@ -0,0 +1,86 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import LanguageSelect from "@astrojs/starlight/components/LanguageSelect.astro";
import Search from "@astrojs/starlight/components/Search.astro";
import SiteTitle from "@astrojs/starlight/components/SiteTitle.astro";
import SocialIcons from "@astrojs/starlight/components/SocialIcons.astro";
import ThemeSelect from "./ThemeSelect.astro";
import VersionSelector from "./VersionSelector.astro";
---
<div class="header sl-flex">
<div class="title-wrapper sl-flex">
<SiteTitle />
</div>
<div class="sl-flex">
<Search />
</div>
<div class="sl-hidden md:sl-flex right-group">
<div class="sl-flex social-icons">
<VersionSelector {...Astro.locals.starlightRoute} />
</div>
<div class="sl-flex social-icons">
<SocialIcons />
</div>
<ThemeSelect {...Astro.locals.starlightRoute} />
<LanguageSelect />
</div>
</div>
<style>
.header {
gap: var(--sl-nav-gap);
justify-content: space-between;
align-items: center;
height: 100%;
}
.title-wrapper {
/* Prevent long titles overflowing and covering the search and menu buttons on narrow viewports. */
overflow: hidden;
}
.right-group,
.social-icons {
gap: 1rem;
align-items: center;
}
.social-icons::after {
content: '';
height: 2rem;
border-inline-end: 1px solid var(--sl-color-gray-5);
}
@media (min-width: 50rem) {
:global(:root[data-has-sidebar]) {
--__sidebar-pad: calc(2 * var(--sl-nav-pad-x));
}
:global(:root:not([data-has-toc])) {
--__toc-width: 0rem;
}
.header {
--__sidebar-width: max(0rem, var(--sl-content-inline-start, 0rem) - var(--sl-nav-pad-x));
--__main-column-fr: calc(
(
100% + var(--__sidebar-pad, 0rem) - var(--__toc-width, var(--sl-sidebar-width)) -
(2 * var(--__toc-width, var(--sl-nav-pad-x))) - var(--sl-content-inline-start, 0rem) -
var(--sl-content-width)
) / 2
);
display: grid;
grid-template-columns:
/* 1 (site title): runs up until the main content columns left edge or the width of the title, whichever is the largest */
minmax(
calc(var(--__sidebar-width) + max(0rem, var(--__main-column-fr) - var(--sl-nav-gap))),
auto
)
/* 2 (search box): all free space that is available. */
1fr
/* 3 (right items): use the space that these need. */
auto;
align-content: center;
}
}
</style>

View file

@ -0,0 +1,89 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
// biome-ignore lint/style/useImportType: <explanation>
import { Icon } from "@astrojs/starlight/components";
import type { HTMLAttributes } from "astro/types";
interface Props extends Omit<HTMLAttributes<"a">, "title"> {
icon?: keyof typeof Icon;
title: string;
}
const { icon, title, ...attributes } = Astro.props as Props;
---
<article class="icon-link-card sl-flex">
<a {...attributes}>
<p class="title sl-flex">
{icon && <Icon name={icon} class="icon" size="1.5em" />}
<span class="title" set:html={title} />
{icon && <Icon name="right-arrow" size="1.5em" class="rtl:flip" />}
</p>
</a>
<div class="body"><slot /></div>
</article>
<style>
.icon-link-card {
--sl-card-border: var(--sl-color-purple);
--sl-card-bg: var(--sl-color-purple-low);
border: 1px solid var(--sl-color-gray-5);
background-color: var(--sl-color-black);
padding: clamp(1rem, calc(0.125rem + 3vw), 2.5rem);
flex-direction: column;
gap: clamp(0.5rem, calc(0.125rem + 1vw), 1rem);
}
.icon-link-card:nth-child(4n + 1) {
--sl-card-border: var(--sl-color-orange);
--sl-card-bg: var(--sl-color-orange-low);
}
.icon-link-card:nth-child(4n + 3) {
--sl-card-border: var(--sl-color-green);
--sl-card-bg: var(--sl-color-green-low);
}
.icon-link-card:nth-child(4n + 4) {
--sl-card-border: var(--sl-color-red);
--sl-card-bg: var(--sl-color-red-low);
}
.icon-link-card:nth-child(4n + 5) {
--sl-card-border: var(--sl-color-blue);
--sl-card-bg: var(--sl-color-blue-low);
}
a {
text-decoration: none;
line-height: var(--sl-line-height-headings);
}
.title {
font-weight: 600;
font-size: var(--sl-text-h4);
color: var(--sl-color-white);
line-height: var(--sl-line-height-headings);
gap: 1rem;
align-items: center;
}
.icon-link-card .icon {
border: 1px solid var(--sl-card-border);
background-color: var(--sl-card-bg);
padding: 0.2em;
border-radius: 0.25rem;
}
.icon-link-card .body {
margin: 0;
font-size: clamp(var(--sl-text-sm), calc(0.5rem + 1vw), var(--sl-text-body));
}
/* Hover state */
.icon-link-card:hover {
background: var(--sl-color-gray-7, var(--sl-color-gray-6));
border-color: var(--sl-color-gray-2);
}
.icon-link-card:hover .icon {
color: var(--sl-color-white);
}
</style>

View file

@ -0,0 +1,41 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import {
CPP_BASE_URL,
RUST_SLINT_CRATE_URL,
RUST_SLINT_INTERPRETER_CRATE_URL,
RUST_SLINT_BUILD_CRATE_URL,
NODEJS_BASE_URL,
PYTHON_BASE_URL,
} from "../utils/site-config.ts";
const BASE_URL_MAP = {
cpp: `${CPP_BASE_URL}`,
"rust-slint": `${RUST_SLINT_CRATE_URL}`,
"rust-slint-build": `${RUST_SLINT_BUILD_CRATE_URL}`,
"rust-slint-interpreter": `${RUST_SLINT_INTERPRETER_CRATE_URL}`,
nodejs: `${NODEJS_BASE_URL}`,
python: `${PYTHON_BASE_URL}`,
} as const;
type LangID = keyof typeof BASE_URL_MAP;
interface Props {
lang: LangID;
title: string;
relpath: string;
}
const props = Astro.props;
if (!Object.keys(BASE_URL_MAP).includes(props.lang)) {
throw new Error(`Invalid language ID: ${props.lang}`);
}
const { lang, relpath } = props;
const link = `${BASE_URL_MAP[lang]}${relpath}`;
---
<a href={link}><slot/></a>

View file

@ -0,0 +1,29 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { linkMap } from "../utils/utils";
type LinkType = keyof typeof linkMap;
interface Props {
label?: string;
type: LinkType;
}
const { label, type } = Astro.props as Props;
const displayLabel = label || type;
if (!(type in linkMap)) {
throw new Error(
`Invalid link type: ${type}. Maybe you forgot to add it to the linkMap?`,
);
}
// The base is set in astro.config.mjs
const base = import.meta.env.BASE_URL;
const fullHref = `${base}${linkMap[type].href}`;
---
<a href={fullHref}><span>{displayLabel}</span></a>

View file

@ -0,0 +1,27 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { SLINT_DOWNLOAD_VERSION } from "../utils/site-config.ts";
const LINK_MAP = {
"slint-cpp-template-stm32h735g-dk.zip": `https://github.com/slint-ui/slint/releases/download/${SLINT_DOWNLOAD_VERSION}/slint-cpp-template-stm32h735g-dk.zip`,
"slint-cpp-template-stm32h747i-disco.zip": `https://github.com/slint-ui/slint/releases/download/${SLINT_DOWNLOAD_VERSION}/slint-cpp-template-stm32h747i-disco.zip`,
} as const;
type LinkID = keyof typeof LINK_MAP;
interface Props {
id: LinkID;
}
const props = Astro.props;
if (!Object.keys(LINK_MAP).includes(props.id)) {
throw new Error(`Invalid link ID: ${props.id}`);
}
const { id } = props;
const link = LINK_MAP[id];
---
<a href={link}><span>{id}</span></a>

View file

@ -0,0 +1,87 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import "@astrojs/starlight/style/markdown.css";
import {
type KnownType,
type PropertyVisibility,
getEnumContent,
getStructContent,
getTypeInfo,
} from "../utils/utils.ts";
import Type from "./Type.astro";
interface Props {
propName: string;
typeName: KnownType;
defaultValue?: string;
enumName?: string;
structName?: string;
propertyVisibility?: PropertyVisibility;
}
const {
propName,
typeName,
defaultValue,
enumName,
structName,
propertyVisibility,
} = Astro.props as Props;
if (propName === "") {
console.error("No propName!!");
}
let fullTypeName = typeName;
if (typeName === "enum") {
if (enumName === undefined || enumName === "") {
console.error("enum type without an enumName:", propName);
} else {
fullTypeName = typeName.toString() + " " + enumName!.toString();
}
} else if (typeName === "struct") {
if (structName === undefined || structName === "") {
console.error("struct type without a structName:", propName);
} else {
fullTypeName = typeName.toString() + " " + structName!.toString();
}
} else {
if (enumName && enumName !== "") {
console.error("Non-enum type with an enumName set:", propName);
}
}
const typeInfo = getTypeInfo(typeName);
if (typeInfo.href !== "") {
const base = import.meta.env.BASE_URL;
typeInfo.href = `${base}${typeInfo.href}`;
}
const enumContent = await getEnumContent(enumName);
const structContent = await getStructContent(structName);
const defaultValue_ = defaultValue ? defaultValue : typeInfo.defaultValue;
if (!defaultValue_) {
console.error("No defaultValue for:", propName);
}
---
<div class="sl-markdown-content slint-property">
<p>
{typeInfo.href === "" ? (
<Type text={fullTypeName} />
) : (
<a href={typeInfo.href} dir="auto" class="no-underline">
<Type text={fullTypeName} />
</a>
)}
{propertyVisibility && <code>{`(${propertyVisibility})`}</code>}
<span class="default-value">default: <code class="plain-code" dir="auto">{defaultValue_}</code></span><br>
{enumName && <Fragment set:html={enumContent}/>}
{structContent && <Fragment set:html={structContent}/>}
</p>
<slot/>
</div>

View file

@ -0,0 +1,37 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { Icon } from "@astrojs/starlight/components";
---
<script>
class ThemeSwitcher extends HTMLElement {
constructor() {
super();
const storedTheme =
typeof localStorage !== 'undefined' && localStorage.getItem('starlight-theme');
const theme =
storedTheme ||
(window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
document.documentElement.dataset.theme = theme === 'light' ? 'light' : 'dark';
this.handleMouseDown = this.handleMouseDown.bind(this);
}
connectedCallback() {
this.addEventListener('click', this.handleMouseDown);
}
disconnectedCallback() {
this.removeEventListener('click', this.handleMouseDown);
}
private handleMouseDown() {
const theme = document.documentElement.dataset.theme === 'light' ? 'dark' : 'light';
document.documentElement.dataset.theme = theme;
localStorage.setItem('starlight-theme', theme);
}
}
customElements.define('theme-switcher', ThemeSwitcher);
</script>
<theme-switcher class="sl-flex">
<Icon name="sun" class="theme-selector-light" />
<Icon name="moon" class="theme-selector-dark" />
</theme-switcher>

View file

@ -0,0 +1,37 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
interface Props {
stagger?: boolean;
}
const { stagger = false } = Astro.props;
---
<div class:list={["card-grid", { stagger }]}><slot /></div>
<style>
.card-grid {
display: grid;
gap: 1rem;
}
.card-grid > :global(*) {
margin-top: 0 !important;
}
@media (min-width: 50rem) {
.card-grid {
grid-template-columns: 1fr 1fr 1fr;
gap: 1.5rem;
}
.stagger {
--stagger-height: 5rem;
padding-bottom: var(--stagger-height);
}
.stagger > :global(*):nth-child(2n) {
transform: translateY(var(--stagger-height));
}
}
</style>

View file

@ -0,0 +1,28 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { z } from "astro:schema";
import { Badge } from "@astrojs/starlight/components";
type Props = z.infer<typeof props>;
const props = z
.object({
text: z.string(),
})
.strict();
const { text } = props.parse(Astro.props);
---
<Badge
text={text}
size="large"
style={{
color: "var(--sl-text-white)",
backgroundColor: "transparent",
borderColor: "var(--badge-border-color)",
fontSize: "0.7rem",
fontWeight: "bold",
}}
/>

View file

@ -0,0 +1,79 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
---
<script>
// Define types
interface Version {
version: string;
name?: string;
url: string;
preferred?: boolean;
}
// Compare two versions
function compareVersions(v1: string, v2: string): number {
const [major1, minor1, patch1] = v1.split('.').map(Number);
const [major2, minor2, patch2] = v2.split('.').map(Number);
if (major1 !== major2) return major1 - major2;
if (minor1 !== minor2) return minor1 - minor2;
return patch1 - patch2;
}
// Extract version from URL
function extractVersion(url: string): string | null {
const match = url.match(/(\d+\.\d+\.\d+|\d+\.\d+)(?=\/|$)/);
return match ? match[0] : null;
}
function showBanner(latestVersion: string, currentVersion: string | null) {
// Logic for showing banners based on version comparison
if (currentVersion) {
const compareToPreferred = latestVersion && compareVersions(latestVersion, currentVersion);
const olderVersionElem = document.getElementById('older-version');
const devVersionElem = document.getElementById('development-snapshot');
if (olderVersionElem && compareToPreferred && compareToPreferred > 0) {
olderVersionElem.hidden = false;
} else if (olderVersionElem) {
olderVersionElem.hidden = true;
}
if (devVersionElem && compareToPreferred && compareToPreferred < 0) {
devVersionElem.hidden = false;
} else if (devVersionElem) {
devVersionElem.hidden = true;
}
} else if (window.location.href.includes('master')) {
const devVersionElem = document.getElementById('development-snapshot');
if (devVersionElem) devVersionElem.hidden = false;
}
}
// Fetch version data and set up logic
async function fetchVersions() {
const storedVersion: string | null = sessionStorage.getItem('version');
const currentUrl = window.location.href;
const currentVersion = extractVersion(currentUrl);
if (storedVersion) {
showBanner(storedVersion, currentVersion);
} else {
try {
const response = await fetch('https://releases.slint.dev/versions.json');
const versions: Version[] = await response.json();
const preferredVersion = versions.find((version: Version) => version.preferred) || null;
if (preferredVersion) {
const latestVersion = preferredVersion.version;
showBanner(latestVersion, currentVersion);
sessionStorage.setItem('version', latestVersion)
}
} catch (error) {
console.error('Failed to load versions.json:', error);
}
}
}
// Fetch versions when the page loads
fetchVersions();
</script>
<div class="version-banner" id="development-snapshot" hidden>
This is the unreleased documentation for the <strong>next</strong> version of Slint. Switch to <a href="https://docs.slint.dev">the latest released version</a>.
</div>
<div class="version-banner" id="older-version" hidden>
You are viewing contents of an older version. Switch to <a href="https://docs.slint.dev">the latest released version</a>.
</div>

View file

@ -0,0 +1,142 @@
---
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { Icon } from "@astrojs/starlight/components";
---
<script>
interface Version {
version: string;
name?: string;
url: string;
preferred?: boolean;
}
function populateVersions(versions: Version[]) {
// Populate the select dropdown
const select = document.getElementById('version-selector') as HTMLSelectElement;
const currentUrl = window.location.href;
versions.forEach((version) => {
const option = document.createElement('option');
option.value = version.url;
// Set the text content
option.textContent = version.preferred
? version.version
: version.name
? "next"
: version.version;
// Select the correct version based on the URL
const isCurrentVersion = currentUrl.includes(version.version) || (currentUrl.includes('latest') && version.preferred);
const isDevelopmentSnapshot = currentUrl.includes('master') && version.name?.includes('development snapshot');
if (isCurrentVersion || isDevelopmentSnapshot) option.selected = true;
select.appendChild(option);
});
}
async function fetchVersions() {
const storedVersions = sessionStorage.getItem('versions');
const versions: Version[] | null = storedVersions ? JSON.parse(storedVersions) : null;;
if (versions && versions.length) {
populateVersions(versions);
} else {
try {
const response = await fetch('https://releases.slint.dev/versions.json');
const fetchedVersions: Version[] = await response.json();
const preferredVersion = fetchedVersions.find((version: Version) => version.preferred) || null;
if (fetchedVersions.length) {
populateVersions(fetchedVersions);
sessionStorage.setItem('versions', JSON.stringify(fetchedVersions));
}
if (preferredVersion) {
const latestVersion = preferredVersion.version;
sessionStorage.setItem('version', latestVersion);
}
} catch (error) {
console.error('Failed to load versions.json:', error);
}
}
}
// Fetch versions when the page loads
fetchVersions();
class VersionSelect extends HTMLElement {
constructor() {
super();
const select = this.querySelector('select') as HTMLSelectElement;
select?.addEventListener('change', (e) => {
if (e.currentTarget instanceof HTMLSelectElement) {
window.location.href = e.currentTarget.value;
}
});
}
}
customElements.define('version-select', VersionSelect);
</script>
<div>
<version-select>
<label style={`--sl-select-width: ${Astro.props.width}`}>
<span class="sr-only">Version</span>
<select id="version-selector"
aria-label="Select Documentation Version">
</select>
<Icon name="down-caret" class="icon caret" />
</label>
</version-select>
</div>
<style>
label {
--sl-label-icon-size: 0.875rem;
--sl-caret-size: 1.25rem;
--sl-inline-padding: 0.5rem;
position: relative;
display: flex;
align-items: center;
gap: 0.25rem;
color: var(--sl-color-gray-1);
}
label:hover {
color: var(--sl-color-gray-2);
}
.icon {
position: absolute;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
.label-icon {
font-size: var(--sl-label-icon-size);
inset-inline-start: 0;
}
.caret {
font-size: var(--sl-caret-size);
inset-inline-end: 0;
}
select {
border: 0;
outline: none;
padding-block: 0.625rem;
padding-inline: calc(var(--sl-label-icon-size) + var(--sl-inline-padding) + 0.25rem)
calc(var(--sl-caret-size) + var(--sl-inline-padding) + 0.25rem);
margin-inline: calc(var(--sl-inline-padding) * -1);
width: calc(var(--sl-select-width) + var(--sl-inline-padding) * 2);
background-color: transparent;
text-overflow: ellipsis;
color: inherit;
cursor: pointer;
appearance: none;
}
option {
background-color: var(--sl-color-bg-nav);
color: var(--sl-color-gray-1);
}
@media (min-width: 50rem) {
select {
font-size: var(--sl-text-sm);
}
}
</style>

View file

@ -0,0 +1,312 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { EditorState } from "@codemirror/state";
import { highlightSelectionMatches } from "@codemirror/search";
import {
indentWithTab,
history,
defaultKeymap,
historyKeymap,
} from "@codemirror/commands";
import {
foldGutter,
indentOnInput,
indentUnit,
bracketMatching,
foldKeymap,
syntaxHighlighting,
defaultHighlightStyle,
} from "@codemirror/language";
import {
closeBrackets,
autocompletion,
closeBracketsKeymap,
completionKeymap,
} from "@codemirror/autocomplete";
import {
lineNumbers,
highlightActiveLineGutter,
highlightSpecialChars,
drawSelection,
rectangularSelection,
crosshairCursor,
highlightActiveLine,
keymap,
EditorView,
showPanel,
} from "@codemirror/view";
// Theme
import { dracula } from "@uiw/codemirror-theme-dracula";
// Language
import { javascript } from "@codemirror/lang-javascript";
import { python } from "@codemirror/lang-python";
import { rust } from "@codemirror/lang-rust";
import { cpp } from "@codemirror/lang-cpp";
import { languageNameFacet } from "./language-facets";
const editor_url = "https://snapshots.slint.dev/master/editor/";
const wasm_url =
"https://snapshots.slint.dev/master/wasm-interpreter/slint_wasm_interpreter.js";
let slint_wasm_module = null;
// keep them alive
var all_instances = new Array();
// Function to create the Copy button and add it to the panel
function createCopyButton(view) {
const button = document.createElement("button");
button.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-copy" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round">
<title>Copy</title>
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<rect x="8" y="8" width="12" height="12" rx="2" />
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2" />
</svg>`;
button.style.marginRight = "10px";
button.onclick = () => {
const content = view.state.doc.toString();
navigator.clipboard.writeText(content).then(
() => {
alert("Content copied to clipboard!");
},
(err) => {
console.error("Could not copy text: ", err);
},
);
};
return button;
}
// Function to create the Run/Preview button and add it to the panel
function createRunButton(view) {
const button = document.createElement("button");
button.innerHTML = `<svg width="24" height="24" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>Open in SlintPad</title>
<path d="M20.6632 55.828L48.7333 37.0309C48.7333 37.0309 50 36.3278 50 35.2182C50 33.7406 48.3981 33.2599 48.3981 33.2599L32.9557 27.355C32.4047 27.1462 31.6464 27.7312 32.3564 28.4728L37.4689 33.4165C37.4689 33.4165 38.889 34.765 38.889 35.6494C38.889 36.5338 38.017 37.322 38.017 37.322L19.4135 54.6909C18.7517 55.3089 19.6464 56.4294 20.6632 55.828Z" fill="#2379F4"/>
<path d="M43.3368 8.17339L15.2667 26.9677C15.2667 26.9677 14 27.6708 14 28.7804C14 30.258 15.6019 30.7387 15.6019 30.7387L31.0443 36.6464C31.5953 36.8524 32.3565 36.2674 31.6436 35.5286L26.5311 30.5684C26.5311 30.5684 25.111 29.2226 25.111 28.3355C25.111 27.4483 25.983 26.6628 25.983 26.6628L44.5752 9.30769C45.2483 8.68973 44.3565 7.56916 43.3368 8.17339Z" fill="#2379F4"/>
</svg>`;
button.onclick = () => {
const content = view.state.doc.toString();
window.open(
`${editor_url}?snippet=${encodeURIComponent(content)}`,
"_blank",
);
};
return button;
}
// Define the status panel with copy and run buttons
function statusPanel(view) {
const dom = document.createElement("div");
dom.className = "cm-status-panel";
// Add the buttons to the panel
const copyButton = createCopyButton(view);
dom.appendChild(copyButton);
const language = view.state.facet(languageNameFacet);
if (language === "slint") {
const runButton = createRunButton(view);
dom.appendChild(runButton);
}
return {
dom,
update(_update) {
// You can update the panel content based on editor state changes if needed
},
};
}
// Debounce function to limit how often updates are made
function debounce(func, wait) {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
async function updateWasmPreview(previewContainer, content) {
const { component, error_string } =
await slint_wasm_module.compile_from_string(content, "");
var error_div = previewContainer.parentNode.querySelector(".error-status");
if (error_string !== "") {
var text = document.createTextNode(error_string);
var p = document.createElement("pre");
p.appendChild(text);
error_div.innerHTML =
"<pre style='color: red; background-color:#fee; margin:0'>" +
p.innerHTML +
"</pre>";
} else {
error_div.innerHTML = "";
}
if (component !== undefined) {
const canvas_id = previewContainer.getAttribute("data-canvas-id");
const instance = await component.create(canvas_id);
await instance.show();
all_instances.push(instance);
}
}
// Wrap updateWasmPreview in a debounce function (500ms delay)
const debouncedUpdateWasmPreview = debounce(updateWasmPreview, 500);
async function initializePreviewContainers(previewContainer, _content) {
const canvas_id = "canvas_" + Math.random().toString(36).substring(2, 9);
const canvas = document.createElement("canvas");
canvas.id = canvas_id;
previewContainer.appendChild(canvas);
previewContainer.setAttribute("data-canvas-id", `${canvas_id}`);
const error_div = document.createElement("div");
error_div.classList.add("error-status");
previewContainer.parentNode.appendChild(error_div);
}
async function loadSlintWasmInterpreter(_editor) {
try {
if (slint_wasm_module) {
return;
}
// Dynamically import the Slint WASM module
slint_wasm_module = await import(wasm_url);
await slint_wasm_module.default(); // Wait for WASM to initialize
try {
slint_wasm_module.run_event_loop(); // Run the event loop, which will trigger an exception
} catch (e) {
// Swallow the expected JavaScript exception that breaks out of Rust's event loop
}
return;
} catch (error) {
console.error(
"Error during Slint WASM interpreter initialization:",
error,
);
throw error; // Re-throw error to handle it in the calling context
}
}
// Initialize CodeMirror based on the language passed as a data attribute
window.initCodeMirror = (editorDiv, language, content) => {
// const editorDiv_id = editorDiv.getAttribute("id");
const extensions = [
lineNumbers(),
highlightActiveLineGutter(),
highlightSpecialChars(),
history(),
foldGutter(),
drawSelection(),
indentUnit.of(" "),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
highlightActiveLine(),
highlightSelectionMatches(),
keymap.of([
indentWithTab,
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
]),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
languageNameFacet.of(language),
dracula,
showPanel.of(statusPanel),
];
// Get the appropriate language extension
let isReadOnly = true;
let previewContainer;
switch (language.toLowerCase()) {
case "javascript":
extensions.push(javascript());
break;
case "python":
extensions.push(python());
break;
case "cpp":
extensions.push(cpp());
break;
case "rust":
extensions.push(rust());
break;
case "slint":
isReadOnly = false;
extensions.push(javascript());
if (
editorDiv.getAttribute("data-readonly") === "true" ||
editorDiv.getAttribute("data-ignore") === "true"
) {
break;
}
previewContainer = document.createElement("div");
previewContainer.classList.add("preview-container");
editorDiv.classList.add("show-preview");
extensions.push(
EditorView.updateListener.of(async (editor) => {
if (editor.docChanged) {
const newContent = editor.state.doc.toString();
debouncedUpdateWasmPreview(
previewContainer,
newContent,
);
}
}),
);
break;
default:
}
extensions.push(EditorView.editable.of(!isReadOnly));
const editor = new EditorView({
state: EditorState.create({
doc: content,
extensions: extensions,
}),
parent: editorDiv,
});
if (previewContainer) {
editorDiv.append(previewContainer);
loadSlintWasmInterpreter(editor)
.then(async () => {
initializePreviewContainers(previewContainer, content);
updateWasmPreview(previewContainer, content);
})
.catch((error) => {
console.error("Error loading Slint WASM interpreter:", error);
});
}
};
document.addEventListener("DOMContentLoaded", async () => {
// Find all the divs that need a CodeMirror editor
document
.querySelectorAll(".codemirror-editor")
.forEach((editorDiv) => {
const editorContent = editorDiv.querySelector(
".codemirror-content",
);
const language = editorDiv.getAttribute("data-lang");
const content = editorContent.textContent.trim();
window.initCodeMirror(editorDiv, language, content);
});
});

View file

@ -0,0 +1,11 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { Facet } from "@codemirror/state";
// Define a custom facet to hold the language name
export const languageNameFacet = Facet.define({
combine(languages) {
return languages.length ? languages[0] : null; // Combine to get the first language if set
},
});

View file

@ -0,0 +1,29 @@
{
"name": "slint-docs",
"version": "1.11.0",
"type": "module",
"scripts": {
"build": "rollup -c",
"format": "biome format",
"format:fix": "biome format --write",
"lint": "biome lint",
"lint:fix": "biome lint --fix"
},
"devDependencies": {
"rollup": "^3.5.1",
"@rollup/plugin-node-resolve": "^15.0.1"
},
"dependencies": {
"@codemirror/commands": "^6.1.2",
"@codemirror/lang-javascript": "^6.1.1",
"@codemirror/lang-rust": "^6.0.0",
"@codemirror/lang-cpp": "^6.0.0",
"@codemirror/lang-python": "^6.1.0",
"@codemirror/search": "^6.2.3",
"@codemirror/theme-one-dark": "^6.1.0",
"@codemirror/view": "^6.6.0",
"minify": "^9.1.0",
"@uiw/codemirror-theme-dracula": "^4.23.5",
"@babel/runtime": "^7.25.7"
}
}

View file

@ -0,0 +1,19 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import resolve from "@rollup/plugin-node-resolve";
export default {
input: "codemirror.js", // Adjust to your entry file
output: {
file: "../../target/slintdocs/_static/cm6.bundle.js",
format: "iife", // Use IIFE format for browser compatibility
name: "cm6", // Name for the global variable
},
plugins: [
resolve(), // Helps Rollup find external modules
],
external: [
"https://snapshots.slint.dev/master/wasm-interpreter/slint_wasm_interpreter.js", // Mark as external
],
};

View file

@ -0,0 +1,9 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { defineCollection } from "astro:content";
import { docsLoader } from "@astrojs/starlight/loaders";
import { docsSchema } from "@astrojs/starlight/schema";
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
};

View file

@ -0,0 +1,106 @@
---
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
title: Button
description: Button api.
---
import SlintProperty from '/src/components/SlintProperty.astro';
import Link from '/src/components/Link.astro';
```slint playground
import { Button, VerticalBox } from "std-widgets.slint";
export component Example inherits Window {
width: 200px;
height: 100px;
VerticalBox {
label := Text {
text: "Button not clicked";
}
Button {
text: "Click Me";
clicked => {
label.text = " Button clicked";
}
}
}
}
```
A simple button. Common types of buttons can also be created with <Link type="StandardButton" />.
## Properties
### checkable
<SlintProperty propName="checkable" typeName="bool" defaultValue="false">
Shows whether the button can be checked or not. This enables the `checked` property to possibly become true.
```slint "checkable: true;"
Button {
text: "Checkable Button";
checkable: true;
}
```
</SlintProperty>
### checked
<SlintProperty propName="checked" typeName="bool" defaultValue="false" propertyVisibility="in-out">
Shows whether the button is checked or not. Needs `checkable` to be true to work.
</SlintProperty>
### enabled
<SlintProperty propName="enabled" typeName="bool" defaultValue="true">
Defaults to true. When false, the button cannot be pressed.
</SlintProperty>
### has-focus
<SlintProperty propName="has-focus" typeName="bool" defaultValue="false" propertyVisibility="out">
Set to true when the button has keyboard focus
</SlintProperty>
### icon
<SlintProperty propName="icon" typeName="image">
The image to show in the button. Note that not all styles support drawing icons.
</SlintProperty>
### pressed
<SlintProperty propName="pressed" typeName="bool" defaultValue="false" propertyVisibility="out">
Set to true when the button is pressed.
</SlintProperty>
### text
<SlintProperty propName="text" typeName="string">
The text written in the button.
```slint 'text: "Button with text";'
Button {
text: "Button with text";
}
```
</SlintProperty>
### primary
<SlintProperty propName="primary" typeName="bool" defaultValue="false">
If set to true the button is displayed with the primary accent color.
</SlintProperty>
### colorize-icon
<SlintProperty propName="colorize-icon" typeName="bool" defaultValue="false">
If set to true, the icon will be colorized to the same color as the Button's text color.
</SlintProperty>
## Callbacks
### clicked()
Invoked when clicked: A finger or the left mouse button is pressed, then released on this element.
```slint {3-5}
Button {
text: "Click me";
clicked() => {
debug("Button clicked");
}
}
```

View file

@ -0,0 +1,74 @@
---
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
title: CheckBox
description: CheckBox api.
---
import CodeSnippetMD from '/src/components/CodeSnippetMD.astro';
import SlintProperty from '/src/components/SlintProperty.astro';
{/* <CodeSnippetMD needsBackground imagePath="/src/assets/generated/std-widgets-checkbox-example.png" scale="3" imageWidth="100" imageHeight="50" imageAlt='checkbox example'>
```slint
import { CheckBox } from "std-widgets.slint";
export component Example inherits Window {
width: 200px;
height: 25px;
background: transparent;
CheckBox {
x: 5px;
width: parent.width;
height: parent.height;
text: "Hello World";
}
}
```
</CodeSnippetMD> */}
Use a `CheckBox` to let the user select or deselect values, for example in a list with multiple options. Consider using a `Switch` element instead if the action resembles more something that's turned on or off.
## Properties
### checked
<SlintProperty propName="checked" typeName="bool" defaultValue="false" propertyVisibility="in-out">
Whether the checkbox is checked or not.
```slint "checked: true;"
CheckBox {
text: self.checked ? "Checked" : "Not checked";
checked: true;
}
```
</SlintProperty>
### enabled
<SlintProperty propName="enabled" typeName="bool" defaultValue="true">
Defaults to true. When false, the checkbox can't be pressed.
</SlintProperty>
### has-focus
<SlintProperty propName="has-focus" typeName="bool" defaultValue="false" propertyVisibility="out" >
Set to true when the checkbox has keyboard focus.
</SlintProperty>
### text
<SlintProperty propName="text" typeName="string">
The text written next to the checkbox.
```slint 'text: "CheckBox with text";'
CheckBox {
text: "CheckBox with text";
}
```
</SlintProperty>
## Callbacks
### toggled()
The checkbox value changed
```slint {3-5}
CheckBox {
text: "CheckBox";
toggled() => {
debug("CheckBox checked: ", self.checked);
}
}
```

View file

@ -0,0 +1,119 @@
---
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
title: Overview
description: Widgets Overview.
---
import CodeSnippetMD from '/src/components/CodeSnippetMD.astro';
import SlintProperty from '/src/components/SlintProperty.astro';
import Link from '/src/components/Link.astro';
```slint playground
import { Palette, HorizontalBox } from "std-widgets.slint";
export component MyCustomWidget {
in property <string> text <=> label.text;
Rectangle {
background: Palette.control-background;
HorizontalBox {
label := Text {
color: Palette.control-foreground;
}
}
}
}
```
Slint provides a series of built-in widgets that can be imported from `"std-widgets.slint"`.
The widget appearance depends on the selected style.
See <Link type="StyleWidgets" label="Selecting a Widget Style"/> for details how to select the style. If no style is selected, `native` is the default. If `native` isn't available, `fluent` is the default.
All widgets support all <Link type="CommonProperties" label="properties common to builtin elements"/>.
## Palette Properties
Use `Palette` to create custom widgets that match the colors of
the selected style e.g. fluent, cupertino, material, or qt.
### background
<SlintProperty propName="background" typeName="brush" propertyVisibility="out">
Defines the default background brush. Use this if none of the more specialized background brushes apply.
</SlintProperty>
### foreground
<SlintProperty propName="foreground" typeName="brush" propertyVisibility="out">
Defines the foreground brush that is used for content that is displayed on `background` brush.
</SlintProperty>
### alternate-background
<SlintProperty propName="alternate-background" typeName="brush" propertyVisibility="out">
Defines an alternate background brush that is used for example for text input controls or panels like a side bar.
</SlintProperty>
### alternate-foreground
<SlintProperty propName="alternate-foreground" typeName="brush" propertyVisibility="out">
Defines the foreground brush that is used for content that is displayed on `alternate-background` brush.
</SlintProperty>
### control-background
<SlintProperty propName="control-background" typeName="brush" propertyVisibility="out">
Defines the default background brush for controls, such as push buttons, combo boxes, etc.
</SlintProperty>
### control-foreground
<SlintProperty propName="control-foreground" typeName="brush" propertyVisibility="out">
Defines the foreground brush that is used for content that is displayed on `control-background` brush.
</SlintProperty>
### accent-background
<SlintProperty propName="accent-background" typeName="brush" propertyVisibility="out">
Defines the background brush for highlighted controls such as primary buttons.
</SlintProperty>
### accent-foreground
<SlintProperty propName="accent-foreground" typeName="brush" propertyVisibility="out">
Defines the foreground brush that is used for content that is displayed on `accent-background` brush.
</SlintProperty>
### selection-background
<SlintProperty propName="selection-background" typeName="brush" propertyVisibility="out">
Defines the background brush that is used to highlight a selection such as a text selection.
</SlintProperty>
### selection-foreground
<SlintProperty propName="selection-foreground" typeName="brush" propertyVisibility="out">
Defines the foreground brush that is used for content that is displayed on `selection-background` brush.
</SlintProperty>
### border
<SlintProperty propName="border" typeName="brush" propertyVisibility="out">
Defines the brush that is used for borders such as separators and widget borders.
</SlintProperty>
### color-scheme
<SlintProperty propName="color-scheme" typeName="enum" enumName="ColorScheme" propertyVisibility="in-out">
Read this property to determine the color scheme used by the palette.
Set this property to force a dark or light color scheme. All styles
except for the Qt style support setting a dark or light color scheme.
</SlintProperty>
## StyleMetrics Properties
Use `StyleMetrics` to create custom widgets that match the layout settings of
the selected style e.g. fluent, cupertino, material, or qt.
### layout-spacing
<SlintProperty propName="layout-spacing" typeName="length" propertyVisibility="out">
Defines the default layout spacing. This spacing is also used by `VerticalBox`, `HorizontalBox` and `GridBox`.
</SlintProperty>
### layout-padding
<SlintProperty propName="layout-padding" typeName="length" propertyVisibility="out">
Defines the default layout padding. This padding is also used by `VerticalBox`, `HorizontalBox` and `GridBox`.
</SlintProperty>

View file

@ -0,0 +1,89 @@
---
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> ; SPDX-License-Identifier: MIT -->
// cSpell: ignore DSLINT
title: Widget Styles
description: std-widgets Style.
---
import { Tabs, TabItem } from '@astrojs/starlight/components';
You can modify the look of these widgets by choosing a style.
The styles available include:
| Style Name | Light Variant | Dark Variant | Description |
|------------|--------------|--------------|------------|
| `fluent` | `fluent-light`| `fluent-dark`| These variants belong to the **Fluent** style, which is based on the [Fluent Design System](https://fluent2.microsoft.design/). |
| `material` | `material-light`| `material-dark`| These variants are part of the **Material** style, which follows the [Material Design](https://m3.material.io). |
| `cupertino`| `cupertino-light`| `cupertino-dark`| The **Cupertino** variants emulate the style used by macOS. |
| `cosmic`| `cosmic-light`| `cosmic-dark`| The **Cosmic** variants emulate the style used by [Cosmic Desktop](https://github.com/pop-os/cosmic). |
| `qt` | | | The **Qt** style uses [Qt](https://en.wikipedia.org/wiki/Qt_(software)) to render widgets. This style requires Qt to be installed on your system. |
| `native` | | | This is an alias to one of the other styles depending on the platform. It is `cupertino` on macOS, `fluent` on Windows, `material` on Android, `qt` on linux if Qt is available, or `fluent` otherwise. |
By default, the styles automatically adapt to the system's dark or light color setting. Select a `-light` or `-dark` variant to override the system setting and always show either dark or light colors.
The widget style is determined at your project's compile time. The method to select a style depends on how you use Slint.
If no style is selected, `native` is the default.
<Tabs syncKey="dev-language">
<TabItem label="Rust">
You can select the style before starting your compilation by setting the `SLINT_STYLE` environment variable to the name of your chosen style.
When using the `slint_build` API, call the [`slint_build::compile_with_config()`](https://docs.rs/slint-build/newest/slint_build/fn.compile_with_config.html) function.
When using the `slint_interpreter` API, call the [`slint_interpreter::ComponentCompiler::set_style()`](https://docs.rs/slint-interpreter/newest/slint_interpreter/struct.ComponentCompiler.html#method.set_style) function.
</TabItem>
<TabItem label="C++">
Define a `SLINT_STYLE` CMake cache variable to contain the style name as a string. This can be done, for instance, on the command line:
```sh
cmake -DSLINT_STYLE="material" /path/to/source
```
</TabItem>
<TabItem label="NodeJS">
You can select the style by setting the `style` property in [`LoadFileOptions`](slint-node:interfaces/LoadFileOptions) passed to [`loadFile`](slint-node:functions/loadFile):
```js
import * as slint from "slint-ui";
let ui = slint.loadFile("main.slint", { style: "fluent" });
let main = new ui.Main();
main.greeting = "Hello friends";
```
</TabItem>
</Tabs>
## Previewing Designs With `slint-viewer`
Select the style either by setting the `SLINT_STYLE` environment variable, or by passing the style name with the `--style` argument:
slint-viewer --style material /path/to/design.slint
## Previewing Designs With The Slint Visual Studio Code Extension
To select the style, first open the Visual Studio Code settings editor:
<Tabs syncKey="dev-platform">
<TabItem label="Windows" icon="seti:windows">
File > Preferences > Settings
</TabItem>
<TabItem label="macOS" icon="apple">
Code > Preferences > Settings
</TabItem>
<TabItem label="Linux" icon="linux">
File > Preferences > Settings
</TabItem>
</Tabs>
Then enter the style name in Extensions > Slint > Preview:Style
## Previewing Designs With The Generic LSP Process
Choose the style by setting the `SLINT_STYLE` environment variable before launching the process.
Alternatively, if your IDE integration allows for command line parameters, you can specify the style using `--style`.

View file

@ -0,0 +1,251 @@
{
"name": "slint",
"scopeName": "source.slint",
"patterns": [
{
"include": "#document"
}
],
"repository": {
"document": {
"patterns": [
{
"include": "#general"
},
{
"match": "(?<!-)\\b(from|export)\\b(?!-)",
"name": "keyword"
},
{
"match": "(?<!-)\\b(animate|states|transitions|private|public|pure|function|in|out|in-out)\\b(?!-)",
"name": "keyword.other"
},
{
"match": "(?<!-)\\b(if|for|return)\\b(?!-)",
"name": "keyword.control"
},
{
"match": "(?<!-)\\b(root|parent|this|self)\\b(?!-)",
"name": "variable.language"
},
{
"match": "\\b([A-Z][a-zA-Z0-9_-]*)\\s*\\{",
"captures": {
"1": {
"name": "entity.name.type"
}
}
},
{
"match": "(?<!-)\\b(import)\\s*\\{\\s*(([a-zA-Z_][a-zA-Z0-9_-]*)(\\s*,\\s*([a-zA-Z_][a-zA-Z0-9_-]*))*)\\s*\\}",
"captures": {
"1": {
"name": "keyword.other"
},
"3": {
"name": "entity.name.type"
},
"5": {
"name": "entity.name.type"
}
}
},
{
"match": "(?<!-)\\b([a-zA-Z_][a-zA-Z0-9_-]*)\\s*:",
"captures": {
"1": {
"name": "variable.parameter"
}
}
},
{
"match": "(?<!-)\\b([a-zA-Z_][a-zA-Z0-9_-]*)\\s*\\(.*\\)\\s*=>",
"captures": {
"1": {
"name": "entity.name.function"
}
}
},
{
"match": "(?<!-)\\b(callback)\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\s*",
"captures": {
"1": {
"name": "entity.name.function"
},
"2": {
"name": "entity.name.type"
}
}
},
{
"begin": "(?<!-)\\b(struct)\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\s*\\{",
"end": "\\}",
"beginCaptures": {
"1": {
"name": "storage.type"
},
"2": {
"name": "entity.name.type"
}
},
"patterns": [
{
"match": "([a-zA-Z_][a-zA-Z0-9_-]*)\\s*:\\s*([a-zA-Z_][a-zA-Z0-9_-]*)\\s*,?",
"captures": {
"1": {
"name": "variable.parameter"
},
"2": {
"name": "entity.name.type"
}
}
}
]
},
{
"begin": "(?<!-)\\b(global)\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\s*\\{",
"end": "\\}",
"beginCaptures": {
"1": {
"name": "storage.type"
},
"2": {
"name": "entity.name.type"
}
},
"patterns": [
{
"include": "#property"
}
]
},
{
"begin": "(?<!-)\\b(enum)\\s+([a-zA-Z_][a-zA-Z0-9_-]*)\\s*\\{",
"end": "\\}",
"beginCaptures": {
"1": {
"name": "storage.type"
},
"2": {
"name": "entity.name.type"
}
},
"patterns": [
{
"match": "([a-zA-Z_][a-zA-Z0-9_-]*)\\s*,?",
"name": "entity.name.type"
}
]
},
{
"match": "(?<!-)\\b(component|inherits)\\s+([a-zA-Z_][a-zA-Z0-9_-]*)",
"captures": {
"1": {
"name": "storage.type"
},
"2": {
"name": "entity.name.type"
}
}
},
{
"match": "([a-zA-Z_][a-zA-Z0-9_-])*\\s*(:=)\\s*([a-zA-Z_][a-zA-Z0-9_-]*)",
"captures": {
"1": {
"name": "variable.parameter"
},
"2": {
"name": "keyword.operator"
},
"3": {
"name": "entity.name.type"
}
}
},
{
"match": "(?<!-)\\b(blue|red|green|yellow|red|black|linear|ease-in-quad|ease-out-quad|ease-in-out-quad|ease|ease-in|ease-out|ease-in-out|ease-in-quart|ease-out-quart|ease-in-out-quart|ease-in-quint|ease-out-quint|ease-in-out-quint|ease-in-expo|ease-out-expo|ease-in-out-expo|ease-in-sine|ease-out-sine|ease-in-out-sine|ease-in-back|ease-out-back|ease-in-out-back|ease-in-circ|ease-out-circ|ease-in-out-circ|ease-in-elastic|ease-out-elastic|ease-in-out-elastic|ease-in-bounce|ease-out-bounce|ease-in-out-bounce|cubic-bezier)\\b(?!-)",
"name": "support.constant"
},
{
"include": "#property"
}
]
},
"general": {
"patterns": [
{
"include": "#block-comments"
},
{
"match": "//.*$",
"name": "comment.line"
},
{
"name": "string.quoted.double",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.untitled",
"match": "\\\\(n|\\\\|u\\{\\d+\\}|\\{[^\\}]+\\})"
}
]
},
{
"match": "#([a-fA-F0-9]){3,8}",
"name": "constant.other"
},
{
"match": "\\b\\d+(\\.\\d*)?(%|px|phx|pt|in|mm|cm|ms|s|deg|rad|turn)?\\b",
"name": "constant.numeric"
}
]
},
"property": {
"patterns": [
{
"begin": "\\b(property)\\b",
"end": "(;|:|<=>)",
"beginCaptures": {
"1": {
"name": "keyword.other"
}
},
"patterns": [
{
"match": "<([a-zA-Z_][a-zA-Z0-9_-]*)>",
"captures": {
"1": {
"name": "entity.name.type"
}
}
},
{
"match": "[a-zA-Z_][a-zA-Z0-9_-]*",
"name": "variable.parameter"
},
{
"match": "\\b(<=>|:)\\b",
"name": "keyword.operator"
}
]
}
]
},
"block-comments": {
"patterns": [
{
"name": "comment.block",
"begin": "/\\*",
"end": "\\*/",
"comment": "Block comment.",
"patterns": [
{
"include": "#block-comments"
}
]
}
]
}
}
}

View file

@ -0,0 +1,132 @@
.code-image-container {
display: flex;
flex-direction: row;
width: 100%;
align-items: center;
}
.code-block {
width: 80%;
/* Reduced from 300px to accommodate the gap */
overflow-x: auto;
}
.image-block {
width: 20%;
margin-top: 0 !important;
margin-left: 20px;
border-radius: 10px;
}
.image-block img {
width: auto;
height: auto;
border-radius: 3px;
}
.no-underline {
text-decoration: none;
}
.default-value code {
margin-left: -0.3rem;
}
.default-value {
margin-left: 0.1rem;
font-size: 0.8em;
}
.plain-code {
background: none !important;
}
.sl-markdown-content table td:first-child {
min-width: 100px !important;
/* Tweak the table so the first column is wider */
}
/* Dark mode colors. */
:root {
--sl-hue-blue: 222;
--sl-text-h3: var(--sl-text-2xl);
--sl-text-h4: 1.2rem;
--sl-content-width: 50rem;
--sl-color-bg: #1b1b1f;
--sl-color-gray-6: #161618;
--sl-color-hairline: #212329;
--sl-color-hairline-shade: var(--sl-color-hairline);
--badge-border-color: --sl-color-hairline;
--slint-code-background: #151517;
.screenshot-container {
background-color: #cdcdcd;
}
--sl-color-accent-low: hsl(228, 70%, 30%);
--sl-color-accent: hsl(228, 100%, 70%);
--sl-color-accent-high: hsl(228, 90%, 85%);
}
/* Light mode colors. */
:root[data-theme="light"] {
--sl-text-h3: var(--sl-text-2xl);
--sl-content-width: 50rem;
--sl-color-bg: #ffffff;
--badge-border-color: lightgrey;
--sl-color-hairline: #edeef3;
--slint-code-background: #f6f6f7;
.screenshot-container {
background-color: whitesmoke;
}
--sl-color-accent-high: hsl(222, 80%, 35%);
--sl-color-accent: hsl(222, 89%, 55%);
--sl-color-accent-low: hsl(222, 89%, 85%);
.site-title {
color: #000;
}
}
.hero {
display: flex;
gap: 1.5rem;
flex-direction: column-reverse;
padding-block: initial;
}
.hero .copy {
align-items: center;
}
.site-title {
font-size: 1.3rem;
color: #fff;
margin-top: -4px;
}
span {
display: inline-block;
margin-top: 2px;
}
.version-banner {
background-color: var(--sl-color-orange-low);
box-shadow: var(--sl-shadow-sm);
color: var(--sl-color-orange-high);
line-height: var(--sl-line-height-headings);
padding: var(--sl-nav-pad-y) var(--sl-nav-pad-x);
text-align: center;
text-wrap: balance;
}
.version-banner a {
color: var(--sl-color-orange-high);
}
.sl-markdown-content {
.slint-property {
margin-top: 0.1rem;
}
}

View file

@ -0,0 +1,34 @@
theme-switcher {
align-items: center;
}
.theme-selector-light,
.theme-selector-dark {
user-select: none;
z-index: 999999;
position: relative;
cursor: pointer;
}
.theme-selector-light:hover,
.theme-selector-dark:hover {
color: var(--sl-color-accent-high);
}
:root {
.theme-selector-light {
display: none;
}
.theme-selector-dark {
display: inline-block;
}
}
:root[data-theme="light"] {
.theme-selector-light {
display: inline-block;
}
.theme-selector-dark {
display: none;
}
.theme-selector-light:hover,
.theme-selector-dark:hover {
color: var(--sl-color-accent);
}
}

View file

@ -0,0 +1,200 @@
{
"AnimationRef": {
"href": "reference/primitive-types/#animation"
},
"AnimationTick": {
"href": "reference/global-functions/builtinfunctions/#animation-tick---duration"
},
"angle": {
"href": "reference/primitive-types/#angle"
},
"bool": {
"href": "reference/primitive-types/#bool"
},
"brush": {
"href": "reference/primitive-types/#brush"
},
"BorderRadiusRectangle": {
"href": "reference/elements/rectangle/#border-radius-properties"
},
"cache-rendering-hint": {
"href": "reference/common/#cache-rendering-hint"
},
"ColorsRef": {
"href": "reference/colors-and-brushes/"
},
"color": {
"href": "reference/primitive-types/#color"
},
"ComponentLibraries": {
"href": "guide/language/coding/file/#component-libraries"
},
"CommonProperties": {
"href": "reference/common/"
},
"duration": {
"href": "reference/primitive-types/#duration"
},
"DebugFn": {
"href": "reference/global-functions/builtinfunctions/#debug"
},
"easing": {
"href": "reference/primitive-types/#easing"
},
"EnumType": {
"href": "reference/global-structs-enums/"
},
"Expressions": {
"href": "guide/language/coding/expressions-and-statements/"
},
"float": {
"href": "reference/primitive-types/#float"
},
"FocusHandling": {
"href": "guide/development/focus/"
},
"FontHandling": {
"href": "guide/development/fonts/"
},
"GridLayout": {
"href": "reference/layouts/gridlayout/"
},
"Globals": {
"href": "reference/global-structs-enums/"
},
"HorizontalBox": {
"href": "reference/std-widgets/layouts/horizontalbox/"
},
"HorizontalLayout": {
"href": "reference/layouts/horizontallayout/"
},
"Image": {
"href": "reference/elements/image/"
},
"ImageType": {
"href": "reference/primitive-types/#image"
},
"int": {
"href": "reference/primitive-types/#int"
},
"KeyEvent": {
"href": "reference/keyboard-input/overview/"
},
"length": {
"href": "reference/primitive-types/#length"
},
"ListView": {
"href": "reference/std-widgets/views/listview/"
},
"LineEdit": {
"href": "reference/std-widgets/views/lineedit/"
},
"LinuxkmsBackend": {
"href": "guide/backends-and-renderers/backend_linuxkms/"
},
"MenuBar": {
"href": "reference/window/menubar/"
},
"Menu": {
"href": "reference/window/contextmenuarea/#menu"
},
"Modules": {
"href": "guide/language/coding/file/#modules"
},
"Models": {
"href": "guide/language/coding/repetition-and-data-models/#models"
},
"NumericTypes": {
"href": "reference/primitive-types/#numeric-types"
},
"Path": {
"href": "reference/elements/path/"
},
"percent": {
"href": "reference/primitive-types/#percent"
},
"physicalLength": {
"href": "reference/primitive-types/#physical-length"
},
"PopupWindow": {
"href": "reference/window/popupwindow/"
},
"ProgressIndicator": {
"href": "reference/std-widgets/basic-widgets/progressindicator/"
},
"Purity": {
"href": "guide/language/concepts/reactivity/"
},
"Rectangle": {
"href": "reference/elements/rectangle/"
},
"relativeFontSize": {
"href": "reference/primitive-types/#relative-font-size"
},
"slintFile": {
"href": "guide/language/coding/file/"
},
"ScrollView": {
"href": "reference/std-widgets/views/scrollview/"
},
"StandardButton": {
"href": "reference/std-widgets/basic-widgets/standardbutton/"
},
"StringType": {
"href": "reference/primitive-types/#string"
},
"StructType": {
"href": "reference/global-structs-enums/"
},
"StyleWidgets": {
"href": "reference/std-widgets/style/"
},
"Text": {
"href": "reference/elements/text/"
},
"TextEdit": {
"href": "reference/std-widgets/views/textedit/"
},
"TextInput": {
"href": "reference/keyboard-input/textinput/"
},
"Timer": {
"href": "reference/timer/"
},
"Types": {
"href": "reference/primitive-types/"
},
"VerticalBox": {
"href": "reference/std-widgets/layouts/verticalbox/"
},
"VerticalLayout": {
"href": "reference/layouts/verticallayout/"
},
"QtBackend": {
"href": "guide/backends-and-renderers/backend_qt/"
},
"Window": {
"href": "reference/window/window/"
},
"WinitBackend": {
"href": "guide/backends-and-renderers/backend_winit/"
},
"translations": {
"href": "guide/development/translations/"
},
"backends_and_renderers": {
"href": "guide/backends-and-renderers/backends_and_renderers/"
},
"globals": {
"href": "guide/language/coding/globals/"
},
"quickstart": {
"href": "tutorial/quickstart/"
},
"modules": {
"href": "guide/language/coding/file/#modules"
},
"index": {
"href": ""
}
}

View file

@ -0,0 +1,13 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
export const BASE_URL = "https://localhost";
export const BASE_PATH = "/docs/";
export const SLINT_DOWNLOAD_VERSION = "nightly";
export const CPP_BASE_URL = `${BASE_URL}${BASE_PATH}../cpp/`;
export const RUST_BASE_URL = `${BASE_URL}${BASE_PATH}../rust/`;
export const RUST_SLINT_CRATE_URL = `${RUST_BASE_URL}slint/`;
export const RUST_SLINT_INTERPRETER_CRATE_URL = `${RUST_BASE_URL}slint_interpreter/`;
export const RUST_SLINT_BUILD_CRATE_URL = `${RUST_BASE_URL}slint_build/`;
export const NODEJS_BASE_URL = `${BASE_URL}${BASE_PATH}../node/`;
export const PYTHON_BASE_URL = `${BASE_URL}${BASE_PATH}../python/`;

View file

@ -0,0 +1,210 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
export async function getEnumContent(enumName: string | undefined) {
if (enumName) {
try {
const module = await import(
`../content/collections/enums/${enumName}.md`
);
return module.compiledContent();
} catch (error) {
console.error(`Failed to load enum file for ${enumName}:`, error);
return "";
}
}
return "";
}
export async function getStructContent(
structName: string | undefined,
): Promise<string> {
if (structName === undefined) {
return "";
}
const baseStruct = structName.replace(/[\[\]]/g, "");
if (baseStruct === "Time" || baseStruct === "Date") {
try {
const module = await import(
`../content/collections/std-widgets/${baseStruct}.md`
);
return module.compiledContent();
} catch (error) {
console.error(`Failed to load enum file for ${baseStruct}:`, error);
return "";
}
}
if (baseStruct) {
try {
const module = await import(
`../content/collections/structs/${baseStruct}.md`
);
return module.compiledContent();
} catch (error) {
console.error(
`Failed to load struct file for ${baseStruct}:`,
error,
);
return "";
}
}
return "";
}
export type KnownType =
| "angle"
| "bool"
| "brush"
| "color"
| "duration"
| "easing"
| "enum"
| "float"
| "image"
| "int"
| "length"
| "percent"
| "physical-length"
| "Point"
| "relative-font-size"
| "string"
| "struct";
export type PropertyVisibility = "private" | "in" | "out" | "in-out";
export interface TypeInfo {
href: string;
defaultValue: string;
}
export function getTypeInfo(typeName: KnownType): TypeInfo {
const baseType = typeName.replace(/[\[\]]/g, "") as KnownType;
switch (baseType) {
case "angle":
return {
href: linkMap.angle.href,
defaultValue: "0deg",
};
case "bool":
return {
href: linkMap.bool.href,
defaultValue: "false",
};
case "brush":
return {
href: linkMap.brush.href,
defaultValue: "a transparent brush",
};
case "color":
return {
href: linkMap.color.href,
defaultValue: "a transparent color",
};
case "duration":
return {
href: linkMap.duration.href,
defaultValue: "0ms",
};
case "easing":
return {
href: linkMap.easing.href,
defaultValue: "linear",
};
case "enum":
return {
href: "", // No need to link here!
defaultValue: "the first enum value",
};
case "float":
return {
href: linkMap.float.href,
defaultValue: "0.0",
};
case "image":
return {
href: linkMap.ImageType.href,
defaultValue: "the empty image",
};
case "int":
return {
href: linkMap.int.href,
defaultValue: "0",
};
case "length":
return {
href: linkMap.length.href,
defaultValue: "0px",
};
case "percent":
return {
href: linkMap.percent.href,
defaultValue: "0%",
};
case "physical-length":
return {
href: linkMap.physicalLength.href,
defaultValue: "0phx",
};
case "Point":
return {
href: linkMap.StructType.href,
defaultValue: "(0px, 0px)",
};
case "relative-font-size":
return {
href: linkMap.relativeFontSize.href,
defaultValue: "0rem",
};
case "string":
return {
href: linkMap.StringType.href,
defaultValue: '""',
};
case "struct":
return {
href: linkMap.StructType.href,
defaultValue: "a struct with all default values",
};
default: {
console.error("Unknown type: ", typeName);
return {
href: "",
defaultValue: "<???>",
};
}
}
}
export function extractLines(
fileContent: string,
start: number,
end: number,
): string {
return fileContent
.split("\n")
.slice(start - 1, end)
.join("\n");
}
export function removeLeadingSpaces(input: string, spaces = 4): string {
const lines = input.split("\n");
const modifiedLines = lines.map((line) => {
const leadingSpaces = line.match(/^ */)?.[0].length ?? 0;
if (leadingSpaces >= spaces) {
return line.slice(spaces);
}
return line;
});
return modifiedLines.join("\n");
}
type LinkMapType = {
[K: string]: {
href: string;
};
};
import linkMapData from "./link-data.json" assert { type: "json" };
export const linkMap: Readonly<LinkMapType> = linkMapData;

View file

@ -0,0 +1,18 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import { test, expect } from "@playwright/test";
test("smoke test", async ({ page }) => {
await page.goto("");
await expect(page.locator('[id="_top"]')).toContainText("Welcome to Slint");
await page
.getByLabel("Main")
.getByRole("link", { name: "Reference" })
.click();
await page.getByText("Visual Elements").click();
await page.getByRole("link", { name: "Image" }).click();
await page.getByRole("link", { name: "colorize" }).click();
await expect(page.locator("#colorize")).toContainText("colorize");
await page.getByRole("link", { name: "brush", exact: true }).click();
await expect(page.locator("#brush")).toContainText("brush");
});

View file

@ -0,0 +1,4 @@
{
"extends": "astro/tsconfigs/strict",
"exclude": ["dist", "test-results", "playwright-report"]
}

View file

@ -0,0 +1,36 @@
# Copyright © SixtyFPS GmbH <info@slint.dev>
# SPDX-License-Identifier: MIT
[package]
name = "material-gallery"
version = "1.11.0"
authors = ["Slint Developers <info@slint.dev>"]
edition = "2021"
publish = false
license = "MIT"
[lib]
crate-type = ["lib", "cdylib"]
path = "src/lib.rs"
name = "gallery_lib"
[[bin]]
path = "src/main.rs"
name = "gallery"
[dependencies]
slint = { path = "../../../../api/rs/slint", features = ["backend-android-activity-06"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2" }
console_error_panic_hook = "0.1.5"
[build-dependencies]
slint-build = { path = "../../../../api/rs/build" }
[package.metadata.android]
package = "com.slint.material"
apk_name = "gallery"
[package.metadata.android.application]
label = "Slint Material"

View file

@ -0,0 +1,6 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
fn main() {
slint_build::compile("ui/main.slint").expect("Slint build failed");
}

View file

@ -0,0 +1,54 @@
<!DOCTYPE html>
<!-- Copyright © SixtyFPS GmbH <info@slint.dev> -->
<!-- SPDX-License-Identifier: MIT -->
<html>
<head>
<meta charset="UTF-8">
<title>musi lili confetti (Web Assembly version)</title>
</head>
<style>
body {
padding: 0px;
margin: 0px;
max-width: none;
}
#container {
display: grid;
justify-items: stretch;
align-content: stretch;
align-items: stretch;
flex-direction: column;
width: 100vw;
height: 100vh;
padding: 0px;
margin: 0px;
grid-template-columns: auto;
grid-template-rows: max-content auto max-content;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
<body>
<div id="spinner" style="position: absolute; top: 50%; width: 100%">
<div class="spinner">Loading...</div>
</div>
<div id="container">
<canvas id="canvas"></canvas>
</div>
<script type="module">
import init from './pkg/gallery_lib.js';
init().finally(() => {
document.getElementById("spinner").remove();
});
</script>
</body>
</html>

View file

@ -0,0 +1,25 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
slint::include_modules!();
fn ui() -> MainWindow {
MainWindow::new().unwrap()
}
#[cfg_attr(target_arch = "wasm32", wasm_bindgen(start))]
pub fn main() {
let ui = ui();
ui.run().unwrap();
}
#[cfg(target_os = "android")]
#[no_mangle]
fn android_main(android_app: slint::android::AndroidApp) {
slint::android::init(android_app).unwrap();
let ui = ui();
ui.run().unwrap();
}

View file

@ -0,0 +1,9 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
// In order to be compatible with both desktop, wasm, and android, the example is both a binary and a library.
// Just forward to the library in main
fn main() {
gallery_lib::main();
}

View file

@ -0,0 +1,42 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import {
MaterialText,
OutlinedCard,
Typography,
MaterialStyleMetrics
} from "../../../../material.slint";
export component ComponentCard {
in property <string> title;
HorizontalLayout {
alignment: center;
VerticalLayout {
spacing: 4px;
alignment: start;
MaterialText {
horizontal_alignment: center;
text: root.title;
style: Typography.title_medium;
}
OutlinedCard {
width: 360px;
VerticalLayout {
padding_left: 2px;
padding_right: self.padding_left;
padding_top: MaterialStyleMetrics.padding_8;
padding_bottom: self.padding_top;
spacing: MaterialStyleMetrics.spacing_8;
@children
}
}
}
}
}

View file

@ -0,0 +1,31 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import {
MaterialText,
MaterialPalette,
Typography
} from "../../../../material.slint";
export component Group {
in property <string> title;
Rectangle {
border_radius: 12px;
background: MaterialPalette.surface_bright;
VerticalLayout {
alignment: start;
padding: 8px;
spacing: 16px;
MaterialText {
horizontal_alignment: center;
text: root.title;
style: Typography.headline_small;
}
@children
}
}
}

View file

@ -0,0 +1,24 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
import {
IconButton,
MaterialText
} from "../../../../material.slint";
export component TextIconButton {
in property <image> icon <=> button.icon;
in property <string> text <=> label.text;
VerticalLayout {
HorizontalLayout {
alignment: center;
button := IconButton {}
}
label := MaterialText {
horizontal_alignment: center;
}
}
}

View file

@ -0,0 +1,68 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT
export global FilledIcons {
out property <image> account_box: @image-url("./icons/filled/account_box.svg");
out property <image> calendar_month: @image-url("./icons/filled/calendar_month.svg");
out property <image> delete: @image-url("./icons/filled/delete.svg");
out property <image> favorite: @image-url("./icons/filled/favorite.svg");
out property <image> inbox: @image-url("./icons/filled/inbox.svg");
out property <image> music_note: @image-url("./icons/filled/music_note.svg");
out property <image> play_arrow: @image-url("./icons/filled/play_arrow.svg");
out property <image> today: @image-url("./icons/filled/today.svg");
out property <image> add: @image-url("./icons/filled/add.svg");
out property <image> chat_bubble: @image-url("./icons/filled/chat_bubble.svg");
out property <image> edit: @image-url("./icons/filled/edit.svg");
out property <image> group: @image-url("./icons/filled/group.svg");
out property <image> mail: @image-url("./icons/filled/mail.svg");
out property <image> outbox: @image-url("./icons/filled/outbox.svg");
out property <image> search: @image-url("./icons/filled/search.svg");
out property <image> video_chat: @image-url("./icons/filled/video_call.svg");
out property <image> bookmark: @image-url("./icons/filled/bookmark.svg");
out property <image> check: @image-url("./icons/filled/check.svg");
out property <image> explore: @image-url("./icons/filled/explore.svg");
out property <image> image: @image-url("./icons/filled/image.svg");
out property <image> more_vert: @image-url("./icons/filled/more_vert.svg");
out property <image> pets: @image-url("./icons/filled/pets.svg");
out property <image> settings: @image-url("./icons/filled/settings.svg");
out property <image> view_week: @image-url("./icons/filled/view_week.svg");
out property <image> light_mode: @image-url("./icons/filled/light_mode.svg");
out property <image> dark_mode: @image-url("./icons/filled/dark_mode.svg");
out property <image> dashboard: @image-url("./icons/filled/dashboard.svg");
out property <image> pause: @image-url("./icons/filled/pause.svg");
out property <image> archive: @image-url("./icons/filled/archive.svg");
out property <image> share: @image-url("./icons/filled/share.svg");
}
export global OutlinedIcons {
out property <image> account_box: @image-url("./icons/outlined/account_box.svg");
out property <image> calendar_month: @image-url("./icons/outlined/calendar_month.svg");
out property <image> delete: @image-url("./icons/outlined/delete.svg");
out property <image> favorite: @image-url("./icons/outlined/favorite.svg");
out property <image> inbox: @image-url("./icons/outlined/inbox.svg");
out property <image> music_note: @image-url("./icons/outlined/music_note.svg");
out property <image> play_arrow: @image-url("./icons/outlined/play_arrow.svg");
out property <image> today: @image-url("./icons/outlined/today.svg");
out property <image> add: @image-url("./icons/outlined/add.svg");
out property <image> chat_bubble: @image-url("./icons/outlined/chat_bubble.svg");
out property <image> edit: @image-url("./icons/outlined/edit.svg");
out property <image> group: @image-url("./icons/outlined/group.svg");
out property <image> mail: @image-url("./icons/outlined/mail.svg");
out property <image> outbox: @image-url("./icons/outlined/outbox.svg");
out property <image> search: @image-url("./icons/outlined/search.svg");
out property <image> video_chat: @image-url("./icons/outlined/video_chat.svg");
out property <image> bookmark: @image-url("./icons/outlined/bookmark.svg");
out property <image> check: @image-url("./icons/outlined/check.svg");
out property <image> explore: @image-url("./icons/outlined/explore.svg");
out property <image> image: @image-url("./icons/outlined/image.svg");
out property <image> more_vert: @image-url("./icons/outlined/more_vert.svg");
out property <image> pets: @image-url("./icons/outlined/pets.svg");
out property <image> settings: @image-url("./icons/outlined/settings.svg");
out property <image> view_week: @image-url("./icons/outlined/view_week.svg");
out property <image> light_mode: @image-url("./icons/outlined/light_mode.svg");
out property <image> dark_mode: @image-url("./icons/outlined/dark_mode.svg");
out property <image> dashboard: @image-url("./icons/outlined/dashboard.svg");
out property <image> pause: @image-url("./icons/outlined/pause.svg");
out property <image> archive: @image-url("./icons/outlined/archive.svg");
out property <image> share: @image-url("./icons/outlined/share.svg");
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 3c1.93 0 3.5 1.57 3.5 3.5S13.93 13 12 13s-3.5-1.57-3.5-3.5S10.07 6 12 6zm7 13H5v-.23c0-.62.28-1.2.76-1.58C7.47 15.82 9.64 15 12 15s4.53.82 6.24 2.19c.48.38.76.97.76 1.58V19z"/></svg>

After

Width:  |  Height:  |  Size: 354 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>

After

Width:  |  Height:  |  Size: 136 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m20.54 5.23-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5 6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"/></svg>

After

Width:  |  Height:  |  Size: 332 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M17 3H7c-1.1 0-1.99.9-1.99 2L5 21l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 160 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V10h14v10zM9 14H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm-8 4H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2z"/></svg>

After

Width:  |  Height:  |  Size: 310 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 167 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>

After

Width:  |  Height:  |  Size: 150 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26 5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z"/></svg>

After

Width:  |  Height:  |  Size: 220 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/></svg>

After

Width:  |  Height:  |  Size: 162 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>

After

Width:  |  Height:  |  Size: 178 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a.996.996 0 0 0 0-1.41l-2.34-2.34a.996.996 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>

After

Width:  |  Height:  |  Size: 246 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 10.9c-.61 0-1.1.49-1.1 1.1s.49 1.1 1.1 1.1c.61 0 1.1-.49 1.1-1.1s-.49-1.1-1.1-1.1zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm2.19 12.19L6 18l3.81-8.19L18 6l-3.81 8.19z"/></svg>

After

Width:  |  Height:  |  Size: 296 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m12 21.35-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>

After

Width:  |  Height:  |  Size: 274 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></svg>

After

Width:  |  Height:  |  Size: 390 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>

After

Width:  |  Height:  |  Size: 221 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 3H4.99c-1.11 0-1.98.89-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5a2 2 0 0 0-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V5H19v10z"/></svg>

After

Width:  |  Height:  |  Size: 244 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37a.996.996 0 0 0-1.41 0 .996.996 0 0 0 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0a.996.996 0 0 0 0-1.41l-1.06-1.06zm1.06-10.96a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36a.996.996 0 0 0 0-1.41.996.996 0 0 0-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/></svg>

After

Width:  |  Height:  |  Size: 878 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4-8 5-8-5V6l8 5 8-5v2z"/></svg>

After

Width:  |  Height:  |  Size: 209 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 246 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/></svg>

After

Width:  |  Height:  |  Size: 186 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 3H4.99c-1.11 0-1.98.9-1.98 2L3 19c0 1.1.88 2 1.99 2H19c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 12h-4c0 1.66-1.35 3-3 3s-3-1.34-3-3H4.99V5H19v10zM8 11h2v3h4v-3h2l-4-4-4 4z"/></svg>

After

Width:  |  Height:  |  Size: 270 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>

After

Width:  |  Height:  |  Size: 132 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle cx="4.5" cy="9.5" r="2.5"/><circle cx="9" cy="5.5" r="2.5"/><circle cx="15" cy="5.5" r="2.5"/><circle cx="19.5" cy="9.5" r="2.5"/><path d="M17.34 14.86c-.87-1.02-1.6-1.89-2.48-2.91-.46-.54-1.05-1.08-1.75-1.32-.11-.04-.22-.07-.33-.09-.25-.04-.52-.04-.78-.04s-.53 0-.79.05c-.11.02-.22.05-.33.09-.7.24-1.28.78-1.75 1.32-.87 1.02-1.6 1.89-2.48 2.91-1.31 1.31-2.92 2.76-2.62 4.79.29 1.02 1.02 2.03 2.33 2.32.73.15 3.06-.44 5.54-.44h.18c2.48 0 4.81.58 5.54.44 1.31-.29 2.04-1.31 2.33-2.32.31-2.04-1.3-3.49-2.61-4.8z"/></svg>

After

Width:  |  Height:  |  Size: 609 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>

After

Width:  |  Height:  |  Size: 114 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/></svg>

After

Width:  |  Height:  |  Size: 303 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58a.49.49 0 0 0 .12-.61l-1.92-3.32a.488.488 0 0 0-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54a.484.484 0 0 0-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58a.49.49 0 0 0-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>

After

Width:  |  Height:  |  Size: 793 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z"/></svg>

After

Width:  |  Height:  |  Size: 460 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"/></svg>

After

Width:  |  Height:  |  Size: 231 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4zM14 13h-3v3H9v-3H6v-2h3V8h2v3h3v2z"/></svg>

After

Width:  |  Height:  |  Size: 236 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M5.33 20H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2h1.33c1.1 0 2 .9 2 2v12a2 2 0 0 1-2 2zM22 18V6c0-1.1-.9-2-2-2h-1.33c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2H20a2 2 0 0 0 2-2zm-7.33 0V6c0-1.1-.9-2-2-2h-1.33c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h1.33c1.1 0 2-.9 2-2z"/></svg>

After

Width:  |  Height:  |  Size: 346 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 16H7v-.24C8.42 17.62 10.16 17 12 17s3.58.62 5 1.76V19zm2-1.14C17.2 16.09 14.73 15 12 15s-5.2 1.09-7 2.86V5h14v12.86zM12 13c1.93 0 3.5-1.57 3.5-3.5S13.93 6 12 6 8.5 7.57 8.5 9.5 10.07 13 12 13zm0-5c.83 0 1.5.67 1.5 1.5S12.83 11 12 11s-1.5-.67-1.5-1.5S11.17 8 12 8z"/></svg>

After

Width:  |  Height:  |  Size: 444 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>

After

Width:  |  Height:  |  Size: 136 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="m20.54 5.23-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM6.24 5h11.52l.81.97H5.44l.8-.97zM5 19V8h14v11H5zm8.45-9h-2.9v3H8l4 4 4-4h-2.55z"/></svg>

After

Width:  |  Height:  |  Size: 346 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M17 3H7c-1.1 0-2 .9-2 2v16l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 153 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20a2 2 0 0 0 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V10h14v10zm0-12H5V6h14v2zM9 14H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2zm-8 4H7v-2h2v2zm4 0h-2v-2h2v2zm4 0h-2v-2h2v2z"/></svg>

After

Width:  |  Height:  |  Size: 325 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20 2H4c-1.1 0-2 .9-2 2v18l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 167 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>

After

Width:  |  Height:  |  Size: 158 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9.37 5.51A7.35 7.35 0 0 0 9.1 7.5c0 4.08 3.32 7.4 7.4 7.4.68 0 1.35-.09 1.99-.27A7.014 7.014 0 0 1 12 19c-3.86 0-7-3.14-7-7 0-2.93 1.81-5.45 4.37-6.49zM12 3a9 9 0 1 0 9 9c0-.46-.04-.92-.1-1.36a5.389 5.389 0 0 1-4.4 2.26 5.403 5.403 0 0 1-3.14-9.8c-.44-.06-.9-.1-1.36-.1z"/></svg>

After

Width:  |  Height:  |  Size: 372 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19 5v2h-4V5h4M9 5v6H5V5h4m10 8v6h-4v-6h4M9 17v2H5v-2h4M21 3h-8v6h8V3zM11 3H3v10h8V3zm10 8h-8v10h8V11zm-10 4H3v6h8v-6z"/></svg>

After

Width:  |  Height:  |  Size: 219 B

Some files were not shown because too many files have changed in this diff Show more