mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-13 20:49:15 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46aa1429a7 | ||
|
|
4b68a741bd | ||
|
|
bd58f7f0a1 | ||
|
|
e8f366835c | ||
|
|
70df6fea1f |
11
cspell.json
11
cspell.json
@@ -70,6 +70,7 @@
|
||||
"exportparts",
|
||||
"fetchpriority",
|
||||
"fieldsets",
|
||||
"flexbox",
|
||||
"focusin",
|
||||
"focusout",
|
||||
"fontawesome",
|
||||
@@ -114,9 +115,6 @@
|
||||
"listbox",
|
||||
"listitem",
|
||||
"litelement",
|
||||
"llm",
|
||||
"llms",
|
||||
"llmstxt",
|
||||
"longform",
|
||||
"lowercasing",
|
||||
"Lucide",
|
||||
@@ -154,6 +152,7 @@
|
||||
"ParamagicDev",
|
||||
"peta",
|
||||
"petabit",
|
||||
"pointercancel",
|
||||
"Preact",
|
||||
"preconnect",
|
||||
"prerendered",
|
||||
@@ -207,6 +206,8 @@
|
||||
"thead",
|
||||
"Themer",
|
||||
"tinycolor",
|
||||
"touchcancel",
|
||||
"touchend",
|
||||
"transitionend",
|
||||
"treeitem",
|
||||
"treeshaking",
|
||||
@@ -240,8 +241,6 @@
|
||||
"src/translations/!(en).ts",
|
||||
"**/*.min.js"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"(^|[^a-z])sl[a-z]*(^|[^a-z])"
|
||||
],
|
||||
"ignoreRegExpList": ["(^|[^a-z])sl[a-z]*(^|[^a-z])"],
|
||||
"useGitignore": true
|
||||
}
|
||||
|
||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -14040,7 +14040,6 @@
|
||||
"@wc-toolkit/jsx-types": "^1.3.0",
|
||||
"eleventy-plugin-git-commit-date": "^0.1.3",
|
||||
"esbuild": "^0.25.11",
|
||||
"gray-matter": "^4.0.3",
|
||||
"npm-check-updates": "^19.1.2"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -7,7 +7,6 @@ import fs from 'fs';
|
||||
import * as path from 'node:path';
|
||||
import { pascalCase } from 'pascal-case';
|
||||
import * as url from 'url';
|
||||
import { llmsTxtPlugin } from './scripts/llms.js';
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
|
||||
const packageData = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
|
||||
@@ -189,13 +188,6 @@ export default {
|
||||
},
|
||||
}),
|
||||
|
||||
// Generate llms.txt
|
||||
llmsTxtPlugin({
|
||||
outdir,
|
||||
docsDir: path.join(__dirname, 'docs'),
|
||||
baseUrl: 'https://webawesome.com',
|
||||
}),
|
||||
|
||||
//
|
||||
// TODO - figure out why this broke when events were updated
|
||||
//
|
||||
|
||||
@@ -29,12 +29,8 @@
|
||||
<li><a href="/docs/resources/contributing">Contributing</a></li>
|
||||
<li><a href="/docs/resources/changelog">Changelog</a></li>
|
||||
<li><a href="/docs/resources/visual-tests">Visual Tests</a></li>
|
||||
<li>
|
||||
<a class="wa-cluster wa-gap-xs" href="/docs/resources/llms">
|
||||
LLMs
|
||||
<wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
<!-- Components -->
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
:root {
|
||||
--wa-brand-orange: #f36944;
|
||||
--wa-brand-grey: #30323b;
|
||||
|
||||
/* layout-based example style aspects */
|
||||
--layout-example-border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
--layout-example-border-radius: var(--wa-border-radius-l);
|
||||
--layout-example-padding: var(--wa-space-s);
|
||||
--layout-example-element-background: var(--wa-color-indigo-60);
|
||||
--layout-example-element-border-radius: var(--wa-border-radius-m);
|
||||
}
|
||||
|
||||
.wa-dark .only-light,
|
||||
|
||||
@@ -41,7 +41,7 @@ Use the `--spacing` custom property to change the amount of space between the di
|
||||
|
||||
### Orientation
|
||||
|
||||
The default orientation for dividers is `horizontal`. Set `orientation` attribute to `vertical` to draw a vertical divider. The divider will span the full height of its container.
|
||||
The default orientation for dividers is `horizontal`. Set `orientation` attribute to `vertical` to draw a vertical divider. The divider will span the full height of its [Flexbox](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox) or [CSS Grid](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/grid) container.
|
||||
|
||||
```html {.example}
|
||||
<div style="display: flex; align-items: center;">
|
||||
@@ -53,6 +53,10 @@ The default orientation for dividers is `horizontal`. Set `orientation` attribut
|
||||
</div>
|
||||
```
|
||||
|
||||
:::info
|
||||
If your container isn't Flexbox or CSS Grid, you may need to set an explicit height for the divider.
|
||||
:::
|
||||
|
||||
### Dropdown Dividers
|
||||
|
||||
Use dividers in [dropdowns](/docs/components/dropdown) to visually group dropdown items.
|
||||
|
||||
@@ -13,10 +13,12 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
|
||||
|
||||
## Next
|
||||
|
||||
- Added llms.txt to assist AI agents with using Web Awesome [discuss:1100]
|
||||
- Added `pointercancel` and `touchcancel` event handling to draggable elements to prevent drags from getting stuck
|
||||
- Added `wa-justify-content-*` utility classes [pr:1930]
|
||||
- Added missing `wa-gap-4xl` utility class [pr:1931]
|
||||
- Fixed a bug in `<wa-combobox>` that prevented the listbox from opening when options were preselected [issue:1883]
|
||||
- Added `justify-content` CSS utilities [pr:1930]
|
||||
- Added missing `.wa-gap-4xl` utility class [pr:1931]
|
||||
- Fixed a bug in draggable elements that caused a TypeError on `touchend` events when `event.touches` was empty
|
||||
- Modified `wa-align-items-*` utility classes to apply `display: flex` by default [pr:1943]
|
||||
|
||||
## 3.1.0
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
title: LLMs
|
||||
description: Web Awesome provides an llms.txt file to help AI assistants understand and work with our components.
|
||||
layout: page-outline
|
||||
---
|
||||
|
||||
The [llms.txt specification](https://llmstxt.org/) is a proposed standard for providing information to large language models (LLMs) in a format they can easily consume. It's like a robots.txt, but instead of telling search engines how to crawl your site, it helps AI assistants understand your project.
|
||||
|
||||
Web Awesome publishes an `llms.txt` file that provides AI tools with structured information about our components, including their APIs, properties, events, methods, slots, and CSS custom properties.
|
||||
|
||||
:::warning
|
||||
This feature is experimental! The llms.txt format and its contents may change as we refine the output based on feedback and evolving AI capabilities.
|
||||
:::
|
||||
|
||||
## Why Use It?
|
||||
|
||||
When working with AI coding assistants like Claude, ChatGPT, Copilot, or Cursor, you can reference the llms.txt file to give the AI context about Web Awesome components. This can lead to more accurate code suggestions and fewer hallucinations when the AI generates Web Awesome code.
|
||||
|
||||
## Accessing the File
|
||||
|
||||
The llms.txt file is available in every Web Awesome build at:
|
||||
|
||||
```
|
||||
/dist/llms.txt
|
||||
/dist-cdn/llms.txt
|
||||
```
|
||||
|
||||
You can also find it in your `node_modules` directory if you've installed Web Awesome via npm:
|
||||
|
||||
```
|
||||
node_modules/@awesome.me/webawesome/dist/llms.txt
|
||||
```
|
||||
|
||||
## How to Use It
|
||||
|
||||
How you reference the file depends on which AI tool you're using.
|
||||
|
||||
### Claude Projects
|
||||
|
||||
If you're using [Claude Projects](https://www.anthropic.com/news/projects), you can add the llms.txt URL to your project knowledge. Claude will use this context when helping you write Web Awesome code.
|
||||
|
||||
### Cursor
|
||||
|
||||
In [Cursor](https://cursor.sh/), you can add the file to your project's documentation sources via **Cursor Settings > Features > Docs**. You can also reference the file directly in chat using `@Docs` after adding it, or paste the content into the chat context.
|
||||
|
||||
### VS Code + Copilot
|
||||
|
||||
GitHub Copilot in VS Code doesn't have a built-in way to reference external documentation files, but you can:
|
||||
|
||||
1. Copy the llms.txt file into your project's root directory
|
||||
2. Open it in a VS Code tab (Copilot considers open files as context)
|
||||
3. Use `#file` in Copilot Chat to explicitly reference it (e.g., `#file:llms.txt how do I create a dialog?`)
|
||||
|
||||
### VS Code + Claude Code
|
||||
|
||||
If you're using the [Claude Code extension](https://marketplace.visualstudio.com/items?itemName=anthropics.claude-code), you can reference the file directly by path:
|
||||
|
||||
```
|
||||
@node_modules/@awesome.me/webawesome/dist/llms.txt
|
||||
```
|
||||
|
||||
Or simply ask Claude to read it — Claude Code can access files in your project directly.
|
||||
|
||||
### Other AI Tools
|
||||
|
||||
Most AI coding assistants allow you to provide context through URLs, file uploads, or direct pasting. Check your tool's documentation for the best way to include external references.
|
||||
|
||||
## What's Included
|
||||
|
||||
The llms.txt file contains:
|
||||
|
||||
- An overview of Web Awesome and its capabilities
|
||||
- Links to documentation sections
|
||||
- A complete list of all components with descriptions
|
||||
- Detailed API reference for each component including:
|
||||
- Slots
|
||||
- Properties and their types
|
||||
- Methods and their signatures
|
||||
- Events
|
||||
- CSS custom properties
|
||||
- CSS parts
|
||||
- CSS states
|
||||
|
||||
## Feedback
|
||||
|
||||
Since this is experimental, we'd love to hear how it works for you! If you find issues with the generated content or have suggestions for improvement, please [open an issue on GitHub](https://github.com/shoelace-style/webawesome/issues).
|
||||
@@ -7,15 +7,16 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
.preview-wrapper {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
min-block-size: 3em;
|
||||
min-inline-size: 5em;
|
||||
padding: var(--wa-space-2xs);
|
||||
}
|
||||
|
||||
.preview-block {
|
||||
aspect-ratio: 1 / 1;
|
||||
background-color: var(--wa-color-neutral-fill-loud);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
min-block-size: 1em;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
:is(.wa-flank, .wa-grid, .wa-stack) > [class*='wa-cluster']:has(div:empty) {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: var(--wa-space-s);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--layout-example-border-radius);
|
||||
padding: var(--layout-example-padding);
|
||||
}
|
||||
|
||||
[class*='wa-cluster'] div:empty {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--layout-example-element-border-radius);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
:is(.wa-flank, .wa-grid, .wa-stack) > [class*='wa-flank']:has(div:empty) {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: var(--wa-space-s);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--layout-example-border-radius);
|
||||
padding: var(--layout-example-padding);
|
||||
}
|
||||
|
||||
[class*='wa-flank'] div:empty {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--layout-example-element-border-radius);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,13 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
[class*='wa-frame']:has(div:empty) {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
padding: var(--wa-space-s);
|
||||
border: var(--layout-example-border);
|
||||
padding: var(--layout-example-padding);
|
||||
}
|
||||
|
||||
[class*='wa-frame'] div:empty {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--layout-example-element-border-radius);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,19 @@ tags: layoutUtilities
|
||||
---
|
||||
|
||||
<style>
|
||||
.preview-wrapper {
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
min-block-size: 3em;
|
||||
min-inline-size: 5em;
|
||||
padding: var(--wa-space-2xs);
|
||||
}
|
||||
|
||||
.preview-block {
|
||||
aspect-ratio: 1 / 1;
|
||||
background-color: var(--wa-color-neutral-fill-loud);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
min-block-size: 1.5em;
|
||||
min-block-size: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -20,15 +28,15 @@ Besides `wa-gap-0`, which sets `gap` to zero, each class corresponds to one of t
|
||||
|
||||
| Class Name | `gap` Value | Preview |
|
||||
| ------------ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
|
||||
| `wa-gap-0` | `0` | <div class="wa-cluster wa-gap-0"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-3xs` | `--wa-space-3xs` | <div class="wa-cluster wa-gap-3xs"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-2xs` | `--wa-space-2xs` | <div class="wa-cluster wa-gap-2xs"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-xs` | `--wa-space-xs` | <div class="wa-cluster wa-gap-xs"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-s` | `--wa-space-s` | <div class="wa-cluster wa-gap-s"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-m` | `--wa-space-m` | <div class="wa-cluster wa-gap-m"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-l` | `--wa-space-l` | <div class="wa-cluster wa-gap-l"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-xl` | `--wa-space-xl` | <div class="wa-cluster wa-gap-xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-2xl` | `--wa-space-2xl` | <div class="wa-cluster wa-gap-2xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-3xl` | `--wa-space-3xl` | <div class="wa-cluster wa-gap-3xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-0` | `0` | <div class="preview-wrapper wa-cluster wa-gap-0"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-3xs` | `--wa-space-3xs` | <div class="preview-wrapper wa-cluster wa-gap-3xs"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-2xs` | `--wa-space-2xs` | <div class="preview-wrapper wa-cluster wa-gap-2xs"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-xs` | `--wa-space-xs` | <div class="preview-wrapper wa-cluster wa-gap-xs"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-s` | `--wa-space-s` | <div class="preview-wrapper wa-cluster wa-gap-s"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-m` | `--wa-space-m` | <div class="preview-wrapper wa-cluster wa-gap-m"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-l` | `--wa-space-l` | <div class="preview-wrapper wa-cluster wa-gap-l"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-xl` | `--wa-space-xl` | <div class="preview-wrapper wa-cluster wa-gap-xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-2xl` | `--wa-space-2xl` | <div class="preview-wrapper wa-cluster wa-gap-2xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
| `wa-gap-3xl` | `--wa-space-3xl` | <div class="preview-wrapper wa-cluster wa-gap-3xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
|
||||
<!-- Pending 3.2.0 release -->
|
||||
<!-- | `wa-gap-4xl` | `--wa-space-4xl` | <div class="wa-cluster wa-gap-4xl"><div class="preview-block"></div><div class="preview-block"></div></div> | -->
|
||||
<!-- | `wa-gap-4xl` | `--wa-space-4xl` | <div class="preview-wrapper wa-cluster wa-gap-4xl"><div class="preview-block"></div><div class="preview-block"></div></div> | -->
|
||||
|
||||
@@ -7,14 +7,14 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
:is(.wa-flank, .wa-grid, .wa-stack) > [class*='wa-grid']:has(div:empty) {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: var(--wa-space-s);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--layout-example-border-radius);
|
||||
padding: var(--layout-example-padding);
|
||||
}
|
||||
|
||||
[class*='wa-grid'] div:empty {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--layout-example-element-border-radius);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
@@ -9,15 +9,16 @@ unlisted: true
|
||||
|
||||
<style>
|
||||
.preview-wrapper {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
min-block-size: 3em;
|
||||
min-inline-size: 5em;
|
||||
padding: var(--wa-space-2xs);
|
||||
}
|
||||
|
||||
.preview-block {
|
||||
aspect-ratio: 1 / 1;
|
||||
background-color: var(--wa-color-neutral-fill-loud);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--wa-border-radius-s);
|
||||
min-block-size: 1em;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
:is(.wa-flank, .wa-grid, .wa-stack) > [class*='wa-split']:has(div:empty) {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: var(--wa-space-s);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--layout-example-border-radius);
|
||||
padding: var(--layout-example-padding);
|
||||
}
|
||||
|
||||
[class*='wa-split'] div:empty {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--layout-example-element-border-radius);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
@@ -7,14 +7,14 @@ tags: layoutUtilities
|
||||
|
||||
<style>
|
||||
:is(.wa-flank, .wa-grid, .wa-stack) > [class*='wa-stack']:has(div:empty) {
|
||||
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
|
||||
border-radius: var(--wa-border-radius-l);
|
||||
padding: var(--wa-space-s);
|
||||
border: var(--layout-example-border);
|
||||
border-radius: var(--layout-example-border-radius);
|
||||
padding: var(--layout-example-padding);
|
||||
}
|
||||
|
||||
[class*='wa-stack'] div:empty {
|
||||
background-color: var(--wa-color-indigo-60);
|
||||
border-radius: var(--wa-border-radius-m);
|
||||
background-color: var(--layout-example-element-background);
|
||||
border-radius: var(--layout-example-element-border-radius);
|
||||
min-block-size: 4rem;
|
||||
min-inline-size: 4rem;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@
|
||||
"@wc-toolkit/jsx-types": "^1.3.0",
|
||||
"eleventy-plugin-git-commit-date": "^0.1.3",
|
||||
"esbuild": "^0.25.11",
|
||||
"gray-matter": "^4.0.3",
|
||||
"npm-check-updates": "^19.1.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import matter from 'gray-matter';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { getAllComponents } from './shared.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/** Removes newlines from text to keep llms.txt formatting clean. */
|
||||
function removeNewlines(str) {
|
||||
return str ? str.replace(/\n/g, ' ').trim() : '';
|
||||
}
|
||||
|
||||
/** Loads front-matter from all component markdown files. */
|
||||
function loadAllFrontMatter(components, docsDir) {
|
||||
const cache = new Map();
|
||||
|
||||
for (const component of components) {
|
||||
const componentName = component.tagName.replace(/^wa-/, '');
|
||||
const mdPath = path.join(docsDir, 'docs/components', `${componentName}.md`);
|
||||
|
||||
if (fs.existsSync(mdPath)) {
|
||||
try {
|
||||
const content = fs.readFileSync(mdPath, 'utf-8');
|
||||
const { data } = matter(content);
|
||||
cache.set(component.tagName, data);
|
||||
} catch {
|
||||
// Skip if parsing fails
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
/** Generates the API reference section for a single component. */
|
||||
function generateComponentApiSection(component, frontMatterCache, baseUrl) {
|
||||
const lines = [];
|
||||
const frontMatter = frontMatterCache.get(component.tagName);
|
||||
const componentSlug = component.tagName.replace(/^wa-/, '');
|
||||
const description = removeNewlines(frontMatter?.description || component.summary || '');
|
||||
|
||||
lines.push(`#### \`<${component.tagName}>\``);
|
||||
lines.push('');
|
||||
lines.push(`**Description:** ${description || 'No description available.'}`);
|
||||
lines.push('');
|
||||
lines.push(`**Documentation:** ${baseUrl}/docs/components/${componentSlug}`);
|
||||
lines.push('');
|
||||
|
||||
// Slots
|
||||
if (component.slots?.length > 0) {
|
||||
lines.push('**Slots:**');
|
||||
lines.push('');
|
||||
for (const slot of component.slots) {
|
||||
const slotName = slot.name || '(default)';
|
||||
lines.push(`- \`${slotName}\`: ${removeNewlines(slot.description) || 'No description.'}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// Properties
|
||||
const properties =
|
||||
component.members?.filter(m => m.kind === 'field' && m.privacy !== 'private' && m.description) || [];
|
||||
|
||||
if (properties.length > 0) {
|
||||
lines.push('**Properties:**');
|
||||
lines.push('');
|
||||
for (const prop of properties) {
|
||||
// Find corresponding attribute if any
|
||||
const attr = component.attributes?.find(a => a.fieldName === prop.name);
|
||||
const attrNote = attr && attr.name !== prop.name ? ` (attribute: \`${attr.name}\`)` : '';
|
||||
const typeStr = prop.type?.text ? `Type: \`${removeNewlines(prop.type.text)}\`` : '';
|
||||
const defaultStr = prop.default ? `Default: \`${prop.default}\`` : '';
|
||||
const meta = [typeStr, defaultStr].filter(Boolean).join(', ');
|
||||
|
||||
lines.push(
|
||||
`- \`${prop.name}\`${attrNote}: ${removeNewlines(prop.description) || 'No description.'}${meta ? ` (${meta})` : ''}`,
|
||||
);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// Methods
|
||||
const methods = component.members?.filter(m => m.kind === 'method' && m.privacy !== 'private' && m.description) || [];
|
||||
|
||||
if (methods.length > 0) {
|
||||
lines.push('**Methods:**');
|
||||
lines.push('');
|
||||
for (const method of methods) {
|
||||
const params = method.parameters?.length
|
||||
? `(${method.parameters.map(p => `${p.name}: ${removeNewlines(p.type?.text) || 'unknown'}`).join(', ')})`
|
||||
: '()';
|
||||
lines.push(`- \`${method.name}${params}\`: ${removeNewlines(method.description) || 'No description.'}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// Events
|
||||
const events = component.events?.filter(e => e.name) || [];
|
||||
if (events.length > 0) {
|
||||
lines.push('**Events:**');
|
||||
lines.push('');
|
||||
for (const event of events) {
|
||||
lines.push(`- \`${event.name}\`: ${removeNewlines(event.description) || 'No description.'}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// CSS Custom Properties
|
||||
if (component.cssProperties?.length > 0) {
|
||||
lines.push('**CSS Custom Properties:**');
|
||||
lines.push('');
|
||||
for (const prop of component.cssProperties) {
|
||||
const defaultStr = prop.default ? ` (Default: \`${prop.default}\`)` : '';
|
||||
lines.push(`- \`${prop.name}\`: ${removeNewlines(prop.description) || 'No description.'}${defaultStr}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// CSS Parts
|
||||
if (component.cssParts?.length > 0) {
|
||||
lines.push('**CSS Parts:**');
|
||||
lines.push('');
|
||||
for (const part of component.cssParts) {
|
||||
lines.push(`- \`${part.name}\`: ${removeNewlines(part.description) || 'No description.'}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
// CSS States
|
||||
if (component.cssStates?.length > 0) {
|
||||
lines.push('**CSS States:**');
|
||||
lines.push('');
|
||||
for (const state of component.cssStates) {
|
||||
lines.push(`- \`${state.name}\`: ${removeNewlines(state.description) || 'No description.'}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the complete llms.txt content.
|
||||
*/
|
||||
function generateLlmsTxt({ components, packageData, frontMatterCache, baseUrl }) {
|
||||
const lines = [];
|
||||
|
||||
// H1 Title (required by llmstxt.org spec)
|
||||
lines.push('# Web Awesome');
|
||||
lines.push('');
|
||||
|
||||
// Blockquote summary
|
||||
lines.push(`> ${packageData.description} Version ${packageData.version}.`);
|
||||
lines.push('');
|
||||
|
||||
// Overview section
|
||||
lines.push(
|
||||
`
|
||||
Web Awesome provides a comprehensive set of customizable, accessible web components for building modern
|
||||
web applications. All components use shadow DOM and are framework-agnostic, working with vanilla JavaScript
|
||||
or any framework including React, Vue, Angular, and Svelte.
|
||||
|
||||
Form controls are form-associated custom elements that work with native form validation and the
|
||||
Constraint Validation API.
|
||||
|
||||
Font Awesome is the default icon library, so \`<wa-icon name="...">\` values should reference Font Awesome
|
||||
icon names.
|
||||
`.trim(),
|
||||
);
|
||||
lines.push('');
|
||||
|
||||
//
|
||||
// Documentation
|
||||
//
|
||||
lines.push('## Documentation');
|
||||
lines.push('');
|
||||
lines.push(`For comprehensive documentation, visit ${baseUrl}/docs/`);
|
||||
lines.push('');
|
||||
lines.push(`- [Getting Started](${baseUrl}/docs/getting-started): Installation and setup guide`);
|
||||
lines.push(`- [Components Overview](${baseUrl}/docs/components): Complete component reference`);
|
||||
lines.push(`- [Theming](${baseUrl}/docs/theming): Customization and design tokens`);
|
||||
lines.push(`- [Form Controls](${baseUrl}/docs/form-controls): Form integration and validation`);
|
||||
lines.push('');
|
||||
|
||||
//
|
||||
// Components
|
||||
//
|
||||
lines.push('## Components');
|
||||
lines.push('');
|
||||
|
||||
const sortedComponentsList = [...components].sort((a, b) => a.tagName.localeCompare(b.tagName));
|
||||
|
||||
for (const component of sortedComponentsList) {
|
||||
const frontMatter = frontMatterCache.get(component.tagName);
|
||||
const description = removeNewlines(frontMatter?.description || component.summary || '');
|
||||
const componentSlug = component.tagName.replace(/^wa-/, '');
|
||||
const title = frontMatter?.title || componentSlug;
|
||||
|
||||
lines.push(
|
||||
`- [${title}](${baseUrl}/docs/components/${componentSlug}): ${description || 'No description available.'}`,
|
||||
);
|
||||
}
|
||||
lines.push('');
|
||||
|
||||
//
|
||||
// Optional
|
||||
//
|
||||
lines.push('## Optional');
|
||||
lines.push('');
|
||||
lines.push(
|
||||
`The following is a quick reference describing every component's API. For comprehensive documentation, refer to the component documentation using the URLs provided above.`,
|
||||
);
|
||||
lines.push('');
|
||||
|
||||
// Sort components alphabetically by tag name for the API reference
|
||||
const sortedComponents = [...components].sort((a, b) => a.tagName.localeCompare(b.tagName));
|
||||
|
||||
for (const component of sortedComponents) {
|
||||
lines.push(...generateComponentApiSection(component, frontMatterCache, baseUrl));
|
||||
}
|
||||
|
||||
return lines.join('\n').trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* A CEM plugin that generates an llms.txt file following the llmstxt.org specification.
|
||||
*/
|
||||
export function llmsTxtPlugin(options = {}) {
|
||||
const {
|
||||
outdir = 'dist-cdn',
|
||||
docsDir = path.resolve(__dirname, '../docs'),
|
||||
baseUrl = 'https://webawesome.com',
|
||||
} = options;
|
||||
|
||||
return {
|
||||
name: 'wa-llms-txt',
|
||||
packageLinkPhase({ customElementsManifest }) {
|
||||
const components = getAllComponents(customElementsManifest);
|
||||
const packageData = customElementsManifest.package || {};
|
||||
const frontMatterCache = loadAllFrontMatter(components, docsDir);
|
||||
|
||||
const llmsTxt = generateLlmsTxt({
|
||||
components,
|
||||
packageData,
|
||||
frontMatterCache,
|
||||
baseUrl,
|
||||
});
|
||||
|
||||
// Write to the output directory
|
||||
const outputPath = path.join(outdir, 'llms.txt');
|
||||
fs.writeFileSync(outputPath, llmsTxt, 'utf-8');
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default llmsTxtPlugin;
|
||||
@@ -79,7 +79,7 @@ export default class WaTooltip extends WebAwesomeElement {
|
||||
/** The amount of time to wait before showing the tooltip when the user mouses in. */
|
||||
@property({ attribute: 'show-delay', type: Number }) showDelay = 150;
|
||||
|
||||
/** The amount of time to wait before hiding the tooltip when the user mouses out.. */
|
||||
/** The amount of time to wait before hiding the tooltip when the user mouses out. */
|
||||
@property({ attribute: 'hide-delay', type: Number }) hideDelay = 0;
|
||||
|
||||
/**
|
||||
|
||||
@@ -99,20 +99,24 @@ export class DraggableElement {
|
||||
|
||||
document.addEventListener('pointerup', this.handleDragStop);
|
||||
document.addEventListener('pointermove', this.handleDragMove);
|
||||
document.addEventListener('pointercancel', this.handleDragStop);
|
||||
document.addEventListener('touchend', this.handleDragStop);
|
||||
document.addEventListener('touchmove', this.handleDragMove);
|
||||
document.addEventListener('touchcancel', this.handleDragStop);
|
||||
this.options.start(clientX, clientY);
|
||||
};
|
||||
|
||||
private handleDragStop = (event: PointerEvent | TouchEvent) => {
|
||||
const clientX = 'touches' in event ? event.touches[0].clientX : (event as PointerEvent).clientX;
|
||||
const clientY = 'touches' in event ? event.touches[0].clientY : (event as PointerEvent).clientY;
|
||||
const clientX = 'changedTouches' in event ? event.changedTouches[0].clientX : (event as PointerEvent).clientX;
|
||||
const clientY = 'changedTouches' in event ? event.changedTouches[0].clientY : (event as PointerEvent).clientY;
|
||||
|
||||
this.isDragging = false;
|
||||
document.removeEventListener('pointerup', this.handleDragStop);
|
||||
document.removeEventListener('pointermove', this.handleDragMove);
|
||||
document.removeEventListener('pointercancel', this.handleDragStop);
|
||||
document.removeEventListener('touchend', this.handleDragStop);
|
||||
document.removeEventListener('touchmove', this.handleDragMove);
|
||||
document.removeEventListener('touchcancel', this.handleDragStop);
|
||||
this.options.stop(clientX, clientY);
|
||||
};
|
||||
|
||||
@@ -141,8 +145,10 @@ export class DraggableElement {
|
||||
public stop() {
|
||||
document.removeEventListener('pointerup', this.handleDragStop);
|
||||
document.removeEventListener('pointermove', this.handleDragMove);
|
||||
document.removeEventListener('pointercancel', this.handleDragStop);
|
||||
document.removeEventListener('touchend', this.handleDragStop);
|
||||
document.removeEventListener('touchmove', this.handleDragMove);
|
||||
document.removeEventListener('touchcancel', this.handleDragStop);
|
||||
this.element.removeEventListener('pointerdown', this.handleDragStart);
|
||||
if (supportsTouch) {
|
||||
this.element.removeEventListener('touchstart', this.handleDragStart);
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
@layer wa-utilities {
|
||||
/* Apply Flexbox with 0 specificity to ensure an align-items util produces a visible change */
|
||||
:where(
|
||||
.wa-align-items-start,
|
||||
.wa-align-items-end,
|
||||
.wa-align-items-center,
|
||||
.wa-align-items-stretch,
|
||||
.wa-align-items-baseline
|
||||
) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.wa-align-items-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
@layer wa-utilities {
|
||||
/* Apply Flexbox with 0 specificity to ensure a justify-content util produces a visible change */
|
||||
:where(
|
||||
.wa-justify-content-start,
|
||||
.wa-justify-content-end,
|
||||
.wa-justify-content-center,
|
||||
.wa-justify-content-space-around,
|
||||
.wa-justify-content-space-between,
|
||||
.wa-justify-content-space-evenly
|
||||
) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.wa-justify-content-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user