v0.2.1 release
This commit is contained in:
0
docs/.nojekyll
Normal file
0
docs/.nojekyll
Normal file
@@ -4,23 +4,28 @@ This directory contains auto-generated API documentation from LuaLS annotations.
|
||||
|
||||
## Files
|
||||
|
||||
- **api.html** - Beautiful, searchable API documentation (2.2MB)
|
||||
- **index.html** - GitHub Pages landing page
|
||||
- **doc.md** - Markdown API reference (47,000+ lines)
|
||||
- **doc.json** - JSON API reference for tooling (11MB)
|
||||
- **build-docs.js** - Node.js script to convert markdown to HTML
|
||||
- **package.json** - Node.js dependencies for HTML generation
|
||||
- **.nojekyll** - Tells GitHub Pages to bypass Jekyll processing
|
||||
- **doc.md** - Raw markdown (gitignored, 960KB)
|
||||
- **doc.json** - Raw JSON (gitignored, 11MB)
|
||||
|
||||
## Regenerating Documentation
|
||||
|
||||
To regenerate the documentation after making changes:
|
||||
|
||||
```bash
|
||||
./generate_docs.sh
|
||||
./scripts/generate_docs.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
|
||||
```bash
|
||||
lua-language-server --doc=. --doc_out_path=./docs
|
||||
```
|
||||
This will:
|
||||
1. Extract version from `FlexLove.lua` (single source of truth)
|
||||
2. Generate markdown from LuaLS annotations
|
||||
3. Convert to beautiful, searchable HTML with syntax highlighting
|
||||
4. Create navigation sidebar with search functionality
|
||||
5. Display version in page titles and headers
|
||||
|
||||
## Viewing Locally
|
||||
|
||||
@@ -66,4 +71,66 @@ The documentation is generated from LuaLS (Lua Language Server) annotations usin
|
||||
|
||||
## Requirements
|
||||
|
||||
- lua-language-server (install via `brew install lua-language-server` on macOS)
|
||||
- **lua-language-server** - For generating markdown from annotations
|
||||
- macOS: `brew install lua-language-server`
|
||||
- Linux: See https://github.com/LuaLS/lua-language-server
|
||||
|
||||
- **Node.js** - For converting markdown to beautiful HTML
|
||||
- macOS: `brew install node`
|
||||
- Linux: Use your package manager or https://nodejs.org
|
||||
|
||||
## Features
|
||||
|
||||
The generated HTML documentation includes:
|
||||
- 🔍 **Live search** - Find classes and methods instantly
|
||||
- 📱 **Responsive design** - Works on all devices
|
||||
- 🌙 **Dark theme** - Easy on the eyes
|
||||
- 🎨 **Syntax highlighting** - Code examples are beautifully formatted
|
||||
- 🗂️ **Collapsible navigation** - Organized class/method structure
|
||||
- ⚡ **Fast** - Single-page application, no page reloads
|
||||
- 🎯 **Filtered** - Only user-facing classes, no internal implementation
|
||||
- 🏷️ **Versioned** - Auto-displays version from `FlexLove.lua`
|
||||
|
||||
## Customizing Documentation
|
||||
|
||||
Edit `doc-filter.js` to control which classes appear in the documentation:
|
||||
|
||||
```javascript
|
||||
module.exports = {
|
||||
// Whitelist mode: Only these classes will be included
|
||||
include: [
|
||||
'Animation',
|
||||
'Color',
|
||||
'Element',
|
||||
'Theme',
|
||||
// ... add more
|
||||
],
|
||||
|
||||
// Blacklist mode: These classes will be excluded
|
||||
exclude: [
|
||||
'Context',
|
||||
'Performance',
|
||||
// ... add more
|
||||
],
|
||||
|
||||
// Which mode to use
|
||||
mode: 'whitelist' // or 'blacklist'
|
||||
};
|
||||
```
|
||||
|
||||
**Current filter:** Whitelist mode with 20 classes (down from 33)
|
||||
|
||||
## Version Management
|
||||
|
||||
The documentation automatically pulls the version from `FlexLove.lua`:
|
||||
|
||||
```lua
|
||||
flexlove._VERSION = "0.2.0" -- Single source of truth
|
||||
```
|
||||
|
||||
To update the version:
|
||||
1. Change `_VERSION` in `FlexLove.lua`
|
||||
2. Run `./scripts/generate_docs.sh`
|
||||
3. Version appears in page titles, sidebar, and footer
|
||||
|
||||
See `VERSIONING.md` for detailed version management workflow.
|
||||
|
||||
80
docs/VERSIONING.md
Normal file
80
docs/VERSIONING.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Version Management for FlexLöve Documentation
|
||||
|
||||
The documentation automatically pulls the version from `FlexLove.lua` and displays it throughout the docs.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Version Source**: `FlexLove.lua` contains the authoritative version:
|
||||
```lua
|
||||
flexlove._VERSION = "0.2.0"
|
||||
```
|
||||
|
||||
2. **Automatic Detection**: The build script reads this value and injects it into:
|
||||
- Page title: `FlexLöve v0.2.0 - API Reference`
|
||||
- Sidebar header: `FlexLöve v0.2.0`
|
||||
- Landing page: `FlexLöve v0.2.0`
|
||||
|
||||
3. **Single Source of Truth**: Update the version in ONE place (`FlexLove.lua`) and docs auto-update
|
||||
|
||||
## Updating the Version
|
||||
|
||||
### Option 1: Manual Update
|
||||
Edit `FlexLove.lua`:
|
||||
```lua
|
||||
flexlove._VERSION = "0.3.0" -- Change here
|
||||
```
|
||||
|
||||
Then regenerate docs:
|
||||
```bash
|
||||
./scripts/generate_docs.sh
|
||||
```
|
||||
|
||||
### Option 2: Script-Based (Recommended for Releases)
|
||||
Create a release script that:
|
||||
1. Updates version in `FlexLove.lua`
|
||||
2. Regenerates documentation
|
||||
3. Commits changes
|
||||
4. Tags release
|
||||
|
||||
Example `release.sh`:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
NEW_VERSION=$1
|
||||
|
||||
if [ -z "$NEW_VERSION" ]; then
|
||||
echo "Usage: ./release.sh <version>"
|
||||
echo "Example: ./release.sh 0.3.0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Update version in FlexLove.lua
|
||||
sed -i '' "s/flexlove._VERSION = \".*\"/flexlove._VERSION = \"$NEW_VERSION\"/" FlexLove.lua
|
||||
|
||||
# Regenerate docs
|
||||
./scripts/generate_docs.sh
|
||||
|
||||
# Commit and tag
|
||||
git add FlexLove.lua docs/
|
||||
git commit -m "Release v$NEW_VERSION"
|
||||
git tag "v$NEW_VERSION"
|
||||
|
||||
echo "✓ Released v$NEW_VERSION"
|
||||
echo "Don't forget to: git push && git push --tags"
|
||||
```
|
||||
|
||||
## Version Display Locations
|
||||
|
||||
- **API Reference** (`api.html`):
|
||||
- Browser tab title
|
||||
- Sidebar header (smaller, grayed out)
|
||||
|
||||
- **Landing Page** (`index.html`):
|
||||
- Footer: "FlexLöve v0.2.0 | MIT License"
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Consider adding:
|
||||
- **CHANGELOG.md** - Track changes between versions
|
||||
- **Version dropdown** - View docs for older versions
|
||||
- **GitHub Releases link** - Link to release notes
|
||||
- **Breaking changes banner** - Warn users about API changes
|
||||
153
docs/WORKFLOW.md
Normal file
153
docs/WORKFLOW.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Documentation Workflow
|
||||
|
||||
## Overview
|
||||
|
||||
FlexLöve's documentation system automatically manages versioning and archival. When you generate new documentation, the previous version is automatically archived.
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Manual Documentation Updates (No Version Change)
|
||||
|
||||
When you update annotations without bumping the version:
|
||||
|
||||
```bash
|
||||
./scripts/generate_docs.sh
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
- Script detects current version (e.g., v0.2.0) from `docs/api.html`
|
||||
- Compares with `FlexLove.lua` version
|
||||
- If versions match: **Overwrites** `docs/api.html` (same version)
|
||||
- Previous archived version remains unchanged
|
||||
|
||||
**Use case:** You added better documentation, fixed typos, or improved examples without releasing a new version.
|
||||
|
||||
### 2. Version Bump (New Release)
|
||||
|
||||
When you bump the version in `FlexLove.lua`:
|
||||
|
||||
```bash
|
||||
# 1. Update version in FlexLove.lua
|
||||
# flexlove._VERSION = "0.3.0"
|
||||
|
||||
# 2. Generate documentation
|
||||
./scripts/generate_docs.sh
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
- Script detects old version (v0.2.0) from `docs/api.html`
|
||||
- Compares with new version (v0.3.0) from `FlexLove.lua`
|
||||
- **Archives** old `docs/api.html` → `docs/versions/v0.2.0/api.html`
|
||||
- Generates new `docs/api.html` for v0.3.0
|
||||
|
||||
### 3. Automated Release (via GitHub Actions)
|
||||
|
||||
When you push a git tag:
|
||||
|
||||
```bash
|
||||
git tag v0.3.0
|
||||
git push origin v0.3.0
|
||||
```
|
||||
|
||||
**What happens:**
|
||||
1. GitHub Actions workflow triggers
|
||||
2. Archives previous documentation version
|
||||
3. Generates new documentation for v0.3.0
|
||||
4. Commits both archived and new docs to repository
|
||||
5. Creates release package with checksums
|
||||
6. Creates GitHub release with assets
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
docs/
|
||||
├── api.html # Always the LATEST version
|
||||
├── index.html # Landing page
|
||||
└── versions/
|
||||
├── v0.1.0/
|
||||
│ └── api.html # Documentation for v0.1.0
|
||||
├── v0.2.0/
|
||||
│ └── api.html # Documentation for v0.2.0
|
||||
└── v0.3.0/
|
||||
└── api.html # Documentation for v0.3.0
|
||||
```
|
||||
|
||||
## Version Detection
|
||||
|
||||
The system automatically detects versions by:
|
||||
1. **Current docs version**: Reads from `docs/api.html` header (`FlexLöve v0.2.0`)
|
||||
2. **Code version**: Reads from `FlexLove.lua` (`flexlove._VERSION = "0.2.0"`)
|
||||
|
||||
### Behavior Matrix
|
||||
|
||||
| Old Version | New Version | Action |
|
||||
|-------------|-------------|--------|
|
||||
| v0.2.0 | v0.2.0 | Overwrite current (same version update) |
|
||||
| v0.2.0 | v0.3.0 | Archive v0.2.0, generate v0.3.0 |
|
||||
| None | v0.2.0 | Generate v0.2.0 (first time) |
|
||||
|
||||
## Examples
|
||||
|
||||
### Scenario 1: Fix Documentation Typo
|
||||
|
||||
```bash
|
||||
# Fix typo in annotations
|
||||
# Version still 0.2.0 in FlexLove.lua
|
||||
|
||||
./scripts/generate_docs.sh
|
||||
# Output: "Same version (v0.2.0), will overwrite current documentation"
|
||||
# Result: docs/api.html updated, no archival
|
||||
```
|
||||
|
||||
### Scenario 2: Release New Version
|
||||
|
||||
```bash
|
||||
# Update FlexLove.lua
|
||||
# flexlove._VERSION = "0.3.0"
|
||||
|
||||
./scripts/generate_docs.sh
|
||||
# Output: "Found previous version v0.2.0, archiving before generating new docs..."
|
||||
# Output: "✓ Archived previous documentation to docs/versions/v0.2.0/"
|
||||
# Result:
|
||||
# - docs/versions/v0.2.0/api.html (archived)
|
||||
# - docs/api.html (new v0.3.0)
|
||||
```
|
||||
|
||||
### Scenario 3: Automated Release
|
||||
|
||||
```bash
|
||||
# Tag and push
|
||||
git tag v0.3.0
|
||||
git push origin v0.3.0
|
||||
|
||||
# GitHub Actions will:
|
||||
# 1. Archive v0.2.0 automatically
|
||||
# 2. Generate v0.3.0 docs
|
||||
# 3. Commit both to repository
|
||||
# 4. Create GitHub release
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **No manual archival needed** - Automatically handled
|
||||
✅ **Safe overwrites** - Same version updates won't create duplicate archives
|
||||
✅ **Version history preserved** - All previous versions accessible
|
||||
✅ **Seamless workflow** - Just run `./scripts/generate_docs.sh`
|
||||
✅ **Automated releases** - Tag and forget
|
||||
|
||||
## Version Dropdown
|
||||
|
||||
Users can access any version via the dropdown in the documentation header:
|
||||
- Current version shows "(Latest)" badge
|
||||
- Previous versions listed chronologically
|
||||
- Click to navigate to archived documentation
|
||||
|
||||
## Manual Archival (If Needed)
|
||||
|
||||
If you ever need to manually archive a version:
|
||||
|
||||
```bash
|
||||
./scripts/archive-docs.sh
|
||||
```
|
||||
|
||||
This creates `docs/versions/v{version}/api.html` based on the current `FlexLove.lua` version.
|
||||
3803
docs/api.html
Normal file
3803
docs/api.html
Normal file
File diff suppressed because it is too large
Load Diff
683
docs/build-docs.js
Normal file
683
docs/build-docs.js
Normal file
@@ -0,0 +1,683 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const MarkdownIt = require('markdown-it');
|
||||
const anchor = require('markdown-it-anchor');
|
||||
const hljs = require('highlight.js');
|
||||
const filter = require('./doc-filter');
|
||||
|
||||
// Extract version from FlexLove.lua
|
||||
function getVersion() {
|
||||
try {
|
||||
const flexlovePath = path.join(__dirname, '..', 'FlexLove.lua');
|
||||
const content = fs.readFileSync(flexlovePath, 'utf8');
|
||||
const match = content.match(/flexlove\._VERSION\s*=\s*["']([^"']+)["']/);
|
||||
return match ? match[1] : 'unknown';
|
||||
} catch (e) {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
const VERSION = getVersion();
|
||||
console.log(`Building docs for FlexLöve v${VERSION}`);
|
||||
|
||||
const md = new MarkdownIt({
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value;
|
||||
} catch (__) {}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}).use(anchor, {
|
||||
permalink: anchor.permalink.headerLink()
|
||||
});
|
||||
|
||||
// Read the markdown file
|
||||
let markdownContent = fs.readFileSync(path.join(__dirname, 'doc.md'), 'utf8');
|
||||
|
||||
// Filter content based on doc-filter.js configuration
|
||||
function filterMarkdown(content) {
|
||||
const lines = content.split('\n');
|
||||
const filtered = [];
|
||||
let currentClass = null;
|
||||
let skipUntilNextClass = false;
|
||||
let classContent = [];
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
const h1Match = line.match(/^# (.+)$/);
|
||||
|
||||
if (h1Match) {
|
||||
// New class found - decide if we should keep previous class
|
||||
if (currentClass && !skipUntilNextClass) {
|
||||
filtered.push(...classContent);
|
||||
}
|
||||
|
||||
currentClass = h1Match[1];
|
||||
classContent = [line];
|
||||
|
||||
// Check if this class should be included
|
||||
if (filter.mode === 'whitelist') {
|
||||
skipUntilNextClass = !filter.include.includes(currentClass);
|
||||
} else {
|
||||
skipUntilNextClass = filter.exclude.includes(currentClass);
|
||||
}
|
||||
} else {
|
||||
classContent.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't forget the last class
|
||||
if (currentClass && !skipUntilNextClass) {
|
||||
filtered.push(...classContent);
|
||||
}
|
||||
|
||||
return filtered.join('\n');
|
||||
}
|
||||
|
||||
markdownContent = filterMarkdown(markdownContent);
|
||||
|
||||
// Sort properties: public first, then internal (prefixed with _)
|
||||
function sortAndInjectWarning(content) {
|
||||
const lines = content.split('\n');
|
||||
const result = [];
|
||||
let i = 0;
|
||||
|
||||
while (i < lines.length) {
|
||||
const line = lines[i];
|
||||
|
||||
// Check if this is a class heading (h1)
|
||||
if (line.match(/^# .+$/)) {
|
||||
// Found a class, collect all its properties/methods
|
||||
result.push(line);
|
||||
i++;
|
||||
|
||||
const properties = [];
|
||||
let currentProperty = null;
|
||||
|
||||
// Collect all properties until next class or end of file
|
||||
while (i < lines.length && !lines[i].match(/^# .+$/)) {
|
||||
const propLine = lines[i];
|
||||
const h2Match = propLine.match(/^## (.+)$/);
|
||||
|
||||
if (h2Match) {
|
||||
// Save previous property if exists
|
||||
if (currentProperty) {
|
||||
properties.push(currentProperty);
|
||||
}
|
||||
// Start new property
|
||||
currentProperty = {
|
||||
name: h2Match[1],
|
||||
lines: [propLine],
|
||||
isInternal: h2Match[1].startsWith('_')
|
||||
};
|
||||
} else if (currentProperty) {
|
||||
// Add line to current property
|
||||
currentProperty.lines.push(propLine);
|
||||
} else {
|
||||
// Line before any property (e.g., class description)
|
||||
result.push(propLine);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Save last property
|
||||
if (currentProperty) {
|
||||
properties.push(currentProperty);
|
||||
}
|
||||
|
||||
// Sort: public first, then internal
|
||||
const publicProps = properties.filter(p => !p.isInternal);
|
||||
const internalProps = properties.filter(p => p.isInternal);
|
||||
|
||||
// Add public properties
|
||||
publicProps.forEach(prop => {
|
||||
result.push(...prop.lines);
|
||||
});
|
||||
|
||||
// Add warning and internal properties if any exist
|
||||
if (internalProps.length > 0) {
|
||||
result.push('');
|
||||
result.push('---');
|
||||
result.push('');
|
||||
result.push('## ⚠️ Internal Properties');
|
||||
result.push('');
|
||||
result.push('> **Warning:** The following properties are internal implementation details and should not be accessed directly. They are prefixed with `_` to indicate they are private. Accessing these properties may break in future versions without notice.');
|
||||
result.push('');
|
||||
result.push('---');
|
||||
result.push('');
|
||||
|
||||
internalProps.forEach(prop => {
|
||||
result.push(...prop.lines);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
result.push(line);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return result.join('\n');
|
||||
}
|
||||
|
||||
markdownContent = sortAndInjectWarning(markdownContent);
|
||||
|
||||
// Parse markdown structure to build navigation
|
||||
const lines = markdownContent.split('\n');
|
||||
const navigation = [];
|
||||
let currentClass = null;
|
||||
|
||||
lines.forEach(line => {
|
||||
const h1Match = line.match(/^# (.+)$/);
|
||||
const h2Match = line.match(/^## (.+)$/);
|
||||
|
||||
if (h1Match) {
|
||||
currentClass = {
|
||||
name: h1Match[1],
|
||||
id: h1Match[1].toLowerCase().replace(/[^a-z0-9]+/g, '-'),
|
||||
members: []
|
||||
};
|
||||
navigation.push(currentClass);
|
||||
} else if (h2Match && currentClass) {
|
||||
currentClass.members.push({
|
||||
name: h2Match[1],
|
||||
id: h2Match[1].toLowerCase().replace(/[^a-z0-9]+/g, '-')
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Scan for available documentation versions
|
||||
function getAvailableVersions() {
|
||||
const versionsDir = path.join(__dirname, 'versions');
|
||||
const versions = [];
|
||||
|
||||
try {
|
||||
if (fs.existsSync(versionsDir)) {
|
||||
const entries = fs.readdirSync(versionsDir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory() && entry.name.startsWith('v')) {
|
||||
const apiPath = path.join(versionsDir, entry.name, 'api.html');
|
||||
if (fs.existsSync(apiPath)) {
|
||||
versions.push(entry.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Warning: Could not scan versions directory:', e.message);
|
||||
}
|
||||
|
||||
// Sort versions (newest first)
|
||||
versions.sort((a, b) => {
|
||||
const parseVersion = (v) => {
|
||||
const parts = v.substring(1).split('.').map(Number);
|
||||
return parts[0] * 10000 + parts[1] * 100 + parts[2];
|
||||
};
|
||||
return parseVersion(b) - parseVersion(a);
|
||||
});
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
const availableVersions = getAvailableVersions();
|
||||
console.log(`Found ${availableVersions.length} archived version(s):`, availableVersions.join(', '));
|
||||
|
||||
// Convert markdown to HTML
|
||||
const htmlContent = md.render(markdownContent);
|
||||
|
||||
// Create HTML template
|
||||
const template = `<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>FlexLöve v${VERSION} - API Reference</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
|
||||
background-color: #0d1117;
|
||||
color: #c9d1d9;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
background-color: #161b22;
|
||||
border-right: 1px solid #30363d;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #30363d;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.sidebar-header h2 {
|
||||
color: #58a6ff;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.sidebar-header a {
|
||||
color: #8b949e;
|
||||
text-decoration: none;
|
||||
font-size: 0.9rem;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.sidebar-header a:hover {
|
||||
color: #58a6ff;
|
||||
}
|
||||
|
||||
#search {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
background-color: #0d1117;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
color: #c9d1d9;
|
||||
font-size: 14px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#search:focus {
|
||||
outline: none;
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
|
||||
.nav-section {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.nav-class {
|
||||
color: #c9d1d9;
|
||||
font-weight: 600;
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.2s;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-class:hover {
|
||||
background-color: #21262d;
|
||||
}
|
||||
|
||||
.nav-members {
|
||||
display: none;
|
||||
padding-left: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.nav-members.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-member {
|
||||
color: #8b949e;
|
||||
padding: 4px 12px;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.2s;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-member:hover {
|
||||
background-color: #21262d;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 280px;
|
||||
flex: 1;
|
||||
padding: 40px 60px;
|
||||
max-width: 1200px;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
color: #58a6ff;
|
||||
font-size: 2rem;
|
||||
margin: 2rem 0 1rem 0;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid #30363d;
|
||||
}
|
||||
|
||||
.content h1:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.content h2 {
|
||||
color: #79c0ff;
|
||||
font-size: 1.5rem;
|
||||
margin: 1.5rem 0 0.8rem 0;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.content h3 {
|
||||
color: #c9d1d9;
|
||||
font-size: 1.2rem;
|
||||
margin: 1.2rem 0 0.6rem 0;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin: 0.8rem 0;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
|
||||
.content code {
|
||||
background-color: #161b22;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.content pre {
|
||||
background-color: #161b22;
|
||||
padding: 16px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
margin: 1rem 0;
|
||||
border: 1px solid #30363d;
|
||||
}
|
||||
|
||||
.content pre code {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content a {
|
||||
color: #58a6ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.content ul, .content ol {
|
||||
margin: 0.8rem 0;
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.content li {
|
||||
margin: 0.4rem 0;
|
||||
}
|
||||
|
||||
.content table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.content th, .content td {
|
||||
border: 1px solid #30363d;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.content th {
|
||||
background-color: #161b22;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.content blockquote {
|
||||
background-color: #1c2128;
|
||||
border-left: 4px solid #f85149;
|
||||
padding: 12px 16px;
|
||||
margin: 1rem 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.content blockquote p {
|
||||
margin: 0.4rem 0;
|
||||
}
|
||||
|
||||
.content blockquote strong {
|
||||
color: #f85149;
|
||||
}
|
||||
|
||||
.content hr {
|
||||
border: none;
|
||||
border-top: 1px solid #30363d;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.version-selector {
|
||||
margin-top: 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.version-selector select {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
background-color: #0d1117;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
color: #c9d1d9;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg fill="%238b949e" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="M4.427 7.427l3.396 3.396a.25.25 0 00.354 0l3.396-3.396A.25.25 0 0011.396 7H4.604a.25.25 0 00-.177.427z"/></svg>');
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 8px center;
|
||||
background-size: 12px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
.version-selector select:hover {
|
||||
background-color: #161b22;
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
|
||||
.version-selector select:focus {
|
||||
outline: none;
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
|
||||
.version-badge {
|
||||
display: inline-block;
|
||||
background-color: #238636;
|
||||
color: #fff;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 10px;
|
||||
margin-left: 6px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.back-to-top {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
right: 30px;
|
||||
background-color: #21262d;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
padding: 10px 15px;
|
||||
color: #c9d1d9;
|
||||
text-decoration: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.back-to-top.visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.back-to-top:hover {
|
||||
background-color: #30363d;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
transform: translateX(-100%);
|
||||
transition: transform 0.3s;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.sidebar.mobile-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<nav class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h2>FlexLöve <span style="font-size: 0.6em; color: #8b949e;">v${VERSION}</span></h2>
|
||||
<a href="index.html">← Back to Home</a>
|
||||
${availableVersions.length > 0 ? `
|
||||
<div class="version-selector">
|
||||
<select id="version-dropdown" onchange="window.versionNavigate(this.value)">
|
||||
<option value="">📚 Switch Version</option>
|
||||
<option value="current">v${VERSION} (Latest)</option>
|
||||
${availableVersions.map(v => `<option value="${v}">` + v + '</option>').join('\n ')}
|
||||
</select>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
<input type="text" id="search" placeholder="Search API...">
|
||||
|
||||
<div id="nav-content">
|
||||
${navigation.map(cls => `
|
||||
<div class="nav-section" data-class="${cls.name.toLowerCase()}">
|
||||
<a href="#${cls.id}" class="nav-class">${cls.name}</a>
|
||||
<div class="nav-members">
|
||||
${cls.members.map(member => ` <a href="#${member.id}" class="nav-member">${member.name}</a>`).join('\n')}
|
||||
</div>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="content">
|
||||
${htmlContent}
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<a href="#" class="back-to-top" id="backToTop">↑ Top</a>
|
||||
|
||||
<script>
|
||||
// Search functionality
|
||||
const searchInput = document.getElementById('search');
|
||||
const navSections = document.querySelectorAll('.nav-section');
|
||||
|
||||
searchInput.addEventListener('input', (e) => {
|
||||
const query = e.target.value.toLowerCase();
|
||||
|
||||
navSections.forEach(section => {
|
||||
const className = section.querySelector('.nav-class').textContent.toLowerCase();
|
||||
const members = section.querySelectorAll('.nav-member');
|
||||
let hasMatch = className.includes(query);
|
||||
|
||||
members.forEach(member => {
|
||||
const memberName = member.textContent.toLowerCase();
|
||||
if (memberName.includes(query)) {
|
||||
member.style.display = 'block';
|
||||
hasMatch = true;
|
||||
} else {
|
||||
member.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
section.style.display = hasMatch ? 'block' : 'none';
|
||||
if (hasMatch && query) {
|
||||
section.querySelector('.nav-members').classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Expand/collapse navigation
|
||||
document.querySelectorAll('.nav-class').forEach(navClass => {
|
||||
navClass.addEventListener('click', (e) => {
|
||||
const members = navClass.nextElementSibling;
|
||||
members.classList.toggle('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Back to top button
|
||||
const backToTop = document.getElementById('backToTop');
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
if (window.scrollY > 300) {
|
||||
backToTop.classList.add('visible');
|
||||
} else {
|
||||
backToTop.classList.remove('visible');
|
||||
}
|
||||
});
|
||||
|
||||
backToTop.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
|
||||
// Auto-expand current section
|
||||
const currentHash = window.location.hash;
|
||||
if (currentHash) {
|
||||
const section = document.querySelector(\`[href="\${currentHash}"]\`)?.closest('.nav-section');
|
||||
if (section) {
|
||||
section.querySelector('.nav-members').classList.add('active');
|
||||
}
|
||||
}
|
||||
|
||||
// Version navigation
|
||||
window.versionNavigate = function(value) {
|
||||
if (!value) return;
|
||||
|
||||
if (value === 'current') {
|
||||
// Navigate to current/latest version (root api.html)
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath.includes('/versions/')) {
|
||||
// We're in a versioned doc, go back to root
|
||||
window.location.href = '../../api.html';
|
||||
}
|
||||
// Already on current, do nothing
|
||||
} else {
|
||||
// Navigate to specific version
|
||||
const currentPath = window.location.pathname;
|
||||
if (currentPath.includes('/versions/')) {
|
||||
// We're in a versioned doc, navigate to sibling version
|
||||
window.location.href = \`../\${value}/api.html\`;
|
||||
} else {
|
||||
// We're in root, navigate to versions subdirectory
|
||||
window.location.href = \`versions/\${value}/api.html\`;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
// Write the HTML file
|
||||
fs.writeFileSync(path.join(__dirname, 'api.html'), template, 'utf8');
|
||||
console.log('✓ Generated api.html');
|
||||
47
docs/doc-filter.js
Normal file
47
docs/doc-filter.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// Classes to INCLUDE in documentation (whitelist approach)
|
||||
// Only these classes and their related types will appear in the docs
|
||||
module.exports = {
|
||||
// Main user-facing classes
|
||||
include: [
|
||||
"Animation",
|
||||
"AnimationProps",
|
||||
//"Border",
|
||||
"Color",
|
||||
"Element",
|
||||
"ElementProps",
|
||||
"EventHandler",
|
||||
"FlexLove",
|
||||
"FontFamily",
|
||||
"InputEvent",
|
||||
//"InputEventProps",
|
||||
//"LayoutEngine",
|
||||
//"LayoutEngineProps",
|
||||
"Theme",
|
||||
"ThemeComponent",
|
||||
"ThemeDefinition",
|
||||
"TextEditor",
|
||||
"TextEditorConfig",
|
||||
"TransformProps",
|
||||
"TransitionProps",
|
||||
],
|
||||
|
||||
// Alternative: exclude specific classes (blacklist)
|
||||
exclude: [
|
||||
"Context",
|
||||
"Performance",
|
||||
"Trace",
|
||||
"Proto",
|
||||
"LuaLS",
|
||||
"ImageCache",
|
||||
"ImageRenderer",
|
||||
"Renderer",
|
||||
"StateManager",
|
||||
"ScrollManager",
|
||||
"ErrorCodes",
|
||||
"ThemeManager",
|
||||
"ThemeRegion",
|
||||
],
|
||||
|
||||
// Which mode to use: 'whitelist' or 'blacklist'
|
||||
mode: "whitelist",
|
||||
};
|
||||
@@ -430,10 +430,10 @@
|
||||
16
|
||||
],
|
||||
"type": "doc.type.table",
|
||||
"view": "{ width: number?, height: number?, opacity: number? }"
|
||||
"view": "{ width: number, height: number, opacity: number }"
|
||||
}
|
||||
],
|
||||
"view": "{ width: number?, height: number?, opacity: number? }"
|
||||
"view": "{ width: number, height: number, opacity: number }"
|
||||
},
|
||||
"file": "modules/Animation.lua",
|
||||
"finish": [
|
||||
@@ -446,7 +446,7 @@
|
||||
10
|
||||
],
|
||||
"type": "doc.field",
|
||||
"view": "{ width: number?, height: number?, opacity: number? }",
|
||||
"view": "{ width: number, height: number, opacity: number }",
|
||||
"visible": "public"
|
||||
},
|
||||
{
|
||||
@@ -736,10 +736,10 @@
|
||||
16
|
||||
],
|
||||
"type": "doc.type.table",
|
||||
"view": "{ width: number?, height: number?, opacity: number? }"
|
||||
"view": "{ width: number, height: number, opacity: number }"
|
||||
}
|
||||
],
|
||||
"view": "{ width: number?, height: number?, opacity: number? }"
|
||||
"view": "{ width: number, height: number, opacity: number }"
|
||||
},
|
||||
"file": "modules/Animation.lua",
|
||||
"finish": [
|
||||
@@ -752,7 +752,7 @@
|
||||
10
|
||||
],
|
||||
"type": "doc.field",
|
||||
"view": "{ width: number?, height: number?, opacity: number? }",
|
||||
"view": "{ width: number, height: number, opacity: number }",
|
||||
"visible": "public"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -49,7 +49,7 @@ function Animation.fade(duration: number, fromOpacity: number, toOpacity: number
|
||||
|
||||
|
||||
```lua
|
||||
{ width: number?, height: number?, opacity: number? }
|
||||
{ width: number, height: number, opacity: number }
|
||||
```
|
||||
|
||||
## interpolate
|
||||
@@ -86,7 +86,7 @@ function Animation.scale(duration: number, fromScale: table, toScale: table)
|
||||
|
||||
|
||||
```lua
|
||||
{ width: number?, height: number?, opacity: number? }
|
||||
{ width: number, height: number, opacity: number }
|
||||
```
|
||||
|
||||
## transform
|
||||
|
||||
1075
docs/examples.html
Normal file
1075
docs/examples.html
Normal file
File diff suppressed because it is too large
Load Diff
446
docs/index.html
446
docs/index.html
@@ -1,152 +1,237 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>FlexLöve Documentation</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown.min.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/github-markdown-css@5/github-markdown.min.css"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
|
||||
background-color: #0d1117;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 3rem 0;
|
||||
border-bottom: 1px solid #30363d;
|
||||
}
|
||||
.header h1 {
|
||||
font-size: 3rem;
|
||||
margin: 0;
|
||||
background: linear-gradient(45deg, #58a6ff, #79c0ff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.header p {
|
||||
font-size: 1.2rem;
|
||||
color: #8b949e;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.nav {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.nav a {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background-color: #21262d;
|
||||
color: #c9d1d9;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #30363d;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.nav a:hover {
|
||||
background-color: #30363d;
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
.markdown-body {
|
||||
background-color: #0d1117;
|
||||
padding: 2rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.section {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin: 3rem 0;
|
||||
}
|
||||
.feature-card {
|
||||
background-color: #161b22;
|
||||
padding: 2rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #30363d;
|
||||
}
|
||||
.feature-card h3 {
|
||||
color: #58a6ff;
|
||||
margin-top: 0;
|
||||
}
|
||||
code {
|
||||
background-color: #161b22;
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
|
||||
}
|
||||
pre {
|
||||
background-color: #161b22;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 3rem 0;
|
||||
border-top: 1px solid #30363d;
|
||||
margin-top: 4rem;
|
||||
color: #8b949e;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
|
||||
Helvetica, Arial, sans-serif;
|
||||
background-color: #0d1117;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 3rem 0;
|
||||
border-bottom: 1px solid #30363d;
|
||||
}
|
||||
.header h1 {
|
||||
font-size: 3rem;
|
||||
margin: 0;
|
||||
background: linear-gradient(45deg, #58a6ff, #79c0ff);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
.header p {
|
||||
font-size: 1.2rem;
|
||||
color: #8b949e;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.nav {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.nav a {
|
||||
padding: 0.75rem 1.5rem;
|
||||
background-color: #21262d;
|
||||
color: #c9d1d9;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #30363d;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.nav a:hover {
|
||||
background-color: #30363d;
|
||||
border-color: #58a6ff;
|
||||
}
|
||||
.markdown-body {
|
||||
background-color: #0d1117;
|
||||
padding: 2rem;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.section {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
.features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin: 3rem 0;
|
||||
}
|
||||
.feature-card {
|
||||
background-color: #161b22;
|
||||
padding: 2rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #30363d;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
color: inherit;
|
||||
}
|
||||
.feature-card:hover {
|
||||
background-color: #1c2128;
|
||||
border-color: #58a6ff;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(88, 166, 255, 0.15);
|
||||
}
|
||||
.feature-card h3 {
|
||||
color: #58a6ff;
|
||||
margin-top: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.feature-card h3::after {
|
||||
content: "→";
|
||||
font-size: 1.5rem;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
.feature-card:hover h3::after {
|
||||
opacity: 1;
|
||||
}
|
||||
.feature-card p {
|
||||
color: #8b949e;
|
||||
margin: 0.5rem 0 0 0;
|
||||
}
|
||||
code {
|
||||
background-color: #161b22;
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 3px;
|
||||
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo,
|
||||
monospace;
|
||||
}
|
||||
pre {
|
||||
background-color: #161b22;
|
||||
padding: 1rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
position: relative;
|
||||
}
|
||||
.copy-button {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
background-color: #21262d;
|
||||
color: #8b949e;
|
||||
border: 1px solid #30363d;
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: all 0.2s;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
pre:hover .copy-button {
|
||||
opacity: 1;
|
||||
}
|
||||
.copy-button:hover {
|
||||
background-color: #30363d;
|
||||
border-color: #58a6ff;
|
||||
color: #c9d1d9;
|
||||
}
|
||||
.copy-button:active {
|
||||
background-color: #238636;
|
||||
border-color: #238636;
|
||||
color: #ffffff;
|
||||
}
|
||||
.copy-button.copied {
|
||||
background-color: #238636;
|
||||
border-color: #238636;
|
||||
color: #ffffff;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 3rem 0;
|
||||
border-top: 1px solid #30363d;
|
||||
margin-top: 4rem;
|
||||
color: #8b949e;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>FlexLöve</h1>
|
||||
<p>A comprehensive UI library for LÖVE Framework based on flexbox</p>
|
||||
</div>
|
||||
<div class="header">
|
||||
<h1>FlexLöve</h1>
|
||||
<p>A comprehensive UI library for LÖVE Framework based on flexbox</p>
|
||||
</div>
|
||||
|
||||
<div class="nav">
|
||||
<a href="https://github.com/mikefreno/FlexLove">GitHub</a>
|
||||
<a href="#getting-started">Getting Started</a>
|
||||
<a href="doc.md">API Reference (Markdown)</a>
|
||||
<a href="doc.json">API Reference (JSON)</a>
|
||||
</div>
|
||||
<div class="nav">
|
||||
<a href="https://github.com/mikefreno/FlexLove">GitHub</a>
|
||||
<a href="#getting-started">Getting Started</a>
|
||||
<a href="examples.html">Examples</a>
|
||||
<a href="api.html">API Reference</a>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="features">
|
||||
<div class="feature-card">
|
||||
<h3>🎨 Flexbox & Grid Layouts</h3>
|
||||
<p>Modern CSS-like layout system with full flexbox and grid support for building responsive UIs.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h3>🎭 Theme System</h3>
|
||||
<p>9-patch NinePatch theming with state support (normal, hover, pressed, disabled).</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h3>✨ Animations</h3>
|
||||
<p>Built-in animation support for smooth transitions and effects with easing functions.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h3>📱 Responsive Design</h3>
|
||||
<p>Viewport units (vw, vh, %) for automatic resizing and responsive layouts.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h3>⚡ Immediate Mode</h3>
|
||||
<p>Optional immediate mode support alongside traditional retained mode rendering.</p>
|
||||
</div>
|
||||
<div class="feature-card">
|
||||
<h3>🎯 Event System</h3>
|
||||
<p>Rich event handling with callbacks, focus management, and input fields.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2 style="text-align: center; margin-bottom: 2rem">✨ Features</h2>
|
||||
<div class="features">
|
||||
<a href="examples.html#layout" class="feature-card">
|
||||
<h3>🎨 Flexbox & Grid Layouts</h3>
|
||||
<p>
|
||||
Modern CSS-like layout system with full flexbox and grid support
|
||||
for building responsive UIs.
|
||||
</p>
|
||||
</a>
|
||||
<a href="examples.html#theme" class="feature-card">
|
||||
<h3>🎭 Theme System</h3>
|
||||
<p>
|
||||
9-patch NinePatch theming with state support (normal, hover,
|
||||
pressed, disabled).
|
||||
</p>
|
||||
</a>
|
||||
<a href="examples.html#state" class="feature-card">
|
||||
<h3>✨ State Management</h3>
|
||||
<p>
|
||||
Interactive components with state tracking, counters, toggles, and
|
||||
dynamic updates.
|
||||
</p>
|
||||
</a>
|
||||
<a href="examples.html#scroll" class="feature-card">
|
||||
<h3>📜 Scrollable Content</h3>
|
||||
<p>
|
||||
Smooth scrolling containers with backdrop blur effects and
|
||||
overflow handling for long content lists.
|
||||
</p>
|
||||
</a>
|
||||
<a href="examples.html#slider" class="feature-card">
|
||||
<h3>🎚️ Sliders & Controls</h3>
|
||||
<p>
|
||||
Draggable sliders with value tracking, perfect for settings menus
|
||||
and adjustable parameters.
|
||||
</p>
|
||||
</a>
|
||||
<a href="examples.html#input" class="feature-card">
|
||||
<h3>⌨️ Input & Events</h3>
|
||||
<p>
|
||||
Rich event handling with mouse, keyboard, and touch support. Focus
|
||||
management and input fields.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section markdown-body" id="getting-started">
|
||||
<h2>Quick Start</h2>
|
||||
<pre><code class="language-lua">local FlexLove = require("FlexLove")
|
||||
<div class="section" id="getting-started">
|
||||
<h2>Quick Start</h2>
|
||||
<pre><code class="language-lua">local FlexLove = require("FlexLove")
|
||||
|
||||
-- Initialize with base scaling and theme
|
||||
FlexLove.init({
|
||||
@@ -174,29 +259,70 @@ end
|
||||
function love.draw()
|
||||
FlexLove.draw()
|
||||
end</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Documentation</h2>
|
||||
<p>The API reference is available in two formats:</p>
|
||||
<ul>
|
||||
<li><a href="doc.md">Markdown format</a> - Easy to read in browser or convert to HTML</li>
|
||||
<li><a href="doc.json">JSON format</a> - For programmatic access and tooling</li>
|
||||
</ul>
|
||||
<p>These docs are auto-generated from LuaLS annotations using the Lua Language Server.</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Installation</h2>
|
||||
<p>Add the <code>modules</code> directory and <code>FlexLove.lua</code> into your LÖVE project.</p>
|
||||
<pre><code>git clone https://github.com/mikefreno/FlexLove.git
|
||||
<div class="section">
|
||||
<h2>Installation</h2>
|
||||
<p>
|
||||
Add the <code>modules</code> directory and
|
||||
<code>FlexLove.lua</code> into your LÖVE project.
|
||||
</p>
|
||||
<pre><code>git clone https://github.com/mikefreno/FlexLove.git
|
||||
cp -r FlexLove/modules your-project/
|
||||
cp FlexLove/FlexLove.lua your-project/</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>FlexLöve v0.2.0 | MIT License | <a href="https://github.com/mikefreno/FlexLove" style="color: #58a6ff;">GitHub Repository</a></p>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<p>
|
||||
FlexLöve v0.2.0 | MIT License |
|
||||
<a href="https://github.com/mikefreno/FlexLove" style="color: #58a6ff"
|
||||
>GitHub Repository</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script>
|
||||
hljs.highlightAll();
|
||||
|
||||
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
|
||||
anchor.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute("href"));
|
||||
if (target) {
|
||||
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add copy buttons to code blocks
|
||||
document.querySelectorAll("pre code").forEach((codeBlock) => {
|
||||
const pre = codeBlock.parentElement;
|
||||
const button = document.createElement("button");
|
||||
button.className = "copy-button";
|
||||
button.textContent = "Copy";
|
||||
button.title = "Copy to clipboard";
|
||||
|
||||
button.addEventListener("click", async () => {
|
||||
const code = codeBlock.textContent;
|
||||
try {
|
||||
await navigator.clipboard.writeText(code);
|
||||
button.textContent = "Copied!";
|
||||
button.classList.add("copied");
|
||||
setTimeout(() => {
|
||||
button.textContent = "Copy";
|
||||
button.classList.remove("copied");
|
||||
}, 2000);
|
||||
} catch (err) {
|
||||
console.error("Failed to copy:", err);
|
||||
button.textContent = "Failed";
|
||||
setTimeout(() => {
|
||||
button.textContent = "Copy";
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
|
||||
pre.appendChild(button);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
125
docs/package-lock.json
generated
Normal file
125
docs/package-lock.json
generated
Normal file
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"name": "flexlove-docs",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "flexlove-docs",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"highlight.js": "^11.9.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"markdown-it-anchor": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/markdown-it": {
|
||||
"version": "14.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/linkify-it": "^5",
|
||||
"@types/mdurl": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/highlight.js": {
|
||||
"version": "11.11.1",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
|
||||
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.0",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it-anchor": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-9.2.0.tgz",
|
||||
"integrity": "sha512-sa2ErMQ6kKOA4l31gLGYliFQrMKkqSO0ZJgGhDHKijPf0pNFM9vghjAh3gn26pS4JDRs7Iwa9S36gxm3vgZTzg==",
|
||||
"license": "Unlicense",
|
||||
"peerDependencies": {
|
||||
"@types/markdown-it": "*",
|
||||
"markdown-it": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
13
docs/package.json
Normal file
13
docs/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "flexlove-docs",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "node update-version.js && node build-docs.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"markdown-it": "^14.0.0",
|
||||
"markdown-it-anchor": "^9.0.0",
|
||||
"highlight.js": "^11.9.0"
|
||||
}
|
||||
}
|
||||
34
docs/update-version.js
Normal file
34
docs/update-version.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Extract version from FlexLove.lua
|
||||
function getVersion() {
|
||||
try {
|
||||
const flexlovePath = path.join(__dirname, '..', 'FlexLove.lua');
|
||||
const content = fs.readFileSync(flexlovePath, 'utf8');
|
||||
const match = content.match(/flexlove\._VERSION\s*=\s*["']([^"']+)["']/);
|
||||
return match ? match[1] : 'unknown';
|
||||
} catch (e) {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
// Update index.html with current version
|
||||
function updateIndexVersion() {
|
||||
const version = getVersion();
|
||||
const indexPath = path.join(__dirname, 'index.html');
|
||||
let content = fs.readFileSync(indexPath, 'utf8');
|
||||
|
||||
// Update version in multiple places
|
||||
content = content.replace(
|
||||
/FlexLöve v[\d.]+/g,
|
||||
`FlexLöve v${version}`
|
||||
);
|
||||
|
||||
fs.writeFileSync(indexPath, content, 'utf8');
|
||||
console.log(`✓ Updated index.html to version ${version}`);
|
||||
}
|
||||
|
||||
const version = getVersion();
|
||||
console.log(`Current version: ${version}`);
|
||||
updateIndexVersion();
|
||||
86
docs/versions/README.md
Normal file
86
docs/versions/README.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# FlexLöve Documentation Versions
|
||||
|
||||
This directory stores versioned snapshots of the FlexLöve API documentation.
|
||||
|
||||
## Purpose
|
||||
|
||||
Each time a new version of FlexLöve is released, the documentation is archived here so users can reference docs for specific versions they're using.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
docs/
|
||||
├── api.html # Latest/current version documentation
|
||||
├── index.html # Landing page with version selector
|
||||
└── versions/
|
||||
├── v0.2.0/
|
||||
│ └── api.html # Documentation for v0.2.0
|
||||
├── v0.3.0/
|
||||
│ └── api.html # Documentation for v0.3.0
|
||||
└── v1.0.0/
|
||||
└── api.html # Documentation for v1.0.0
|
||||
```
|
||||
|
||||
## Naming Convention
|
||||
|
||||
- Version directories follow the pattern: `v{major}.{minor}.{patch}`
|
||||
- Examples: `v0.2.0`, `v1.0.0`, `v2.1.3`
|
||||
- Each directory contains `api.html` (the full API documentation for that version)
|
||||
|
||||
## Access
|
||||
|
||||
### Via GitHub Pages
|
||||
|
||||
Once deployed, versions are accessible at:
|
||||
- Latest: `https://{user}.github.io/{repo}/api.html`
|
||||
- Specific version: `https://{user}.github.io/{repo}/versions/v0.2.0/api.html`
|
||||
|
||||
### Via Repository
|
||||
|
||||
Browse directly in the repository:
|
||||
- `docs/api.html` - Always shows latest
|
||||
- `docs/versions/v0.2.0/api.html` - Specific version
|
||||
|
||||
## Automation
|
||||
|
||||
Documentation versions are automatically archived when:
|
||||
1. A new git tag is pushed (e.g., `git push origin v0.3.0`)
|
||||
2. GitHub Actions workflow runs
|
||||
3. Documentation is generated and archived
|
||||
4. Version is committed back to the repository
|
||||
|
||||
See `.github/workflows/release.yml` for implementation details.
|
||||
|
||||
## Manual Archival
|
||||
|
||||
To manually archive a version:
|
||||
|
||||
```bash
|
||||
# Generate docs for current version
|
||||
./scripts/generate_docs.sh
|
||||
|
||||
# Create version directory
|
||||
VERSION="0.2.0"
|
||||
mkdir -p "docs/versions/v${VERSION}"
|
||||
|
||||
# Copy documentation
|
||||
cp docs/api.html "docs/versions/v${VERSION}/api.html"
|
||||
|
||||
# Commit
|
||||
git add docs/versions/
|
||||
git commit -m "Archive documentation for v${VERSION}"
|
||||
git push
|
||||
```
|
||||
|
||||
## Storage Considerations
|
||||
|
||||
- Each `api.html` file is approximately 200-300KB
|
||||
- Storing 10-20 versions = 2-6MB total
|
||||
- GitHub has a 1GB repository soft limit (we're well within it)
|
||||
- Old versions are kept indefinitely for reference
|
||||
|
||||
## Version Dropdown
|
||||
|
||||
The main documentation pages (`api.html` and `index.html`) include a version dropdown that automatically detects and lists all available versions from this directory.
|
||||
|
||||
Users can switch between versions without leaving the documentation.
|
||||
3732
docs/versions/v0.2.0/api.html
Normal file
3732
docs/versions/v0.2.0/api.html
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user