v0.2.1 release

This commit is contained in:
Michael Freno
2025-11-16 09:36:46 -05:00
parent 4142b7e831
commit 39ccf0c450
26 changed files with 11070 additions and 220 deletions

228
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,228 @@
name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: write
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Extract version from tag or FlexLove.lua
id: version
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
echo "Triggered by tag: $GITHUB_REF_NAME"
else
VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
echo "Triggered manually, using FlexLove.lua version"
fi
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
FLEX_VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
echo "FlexLove.lua version: $FLEX_VERSION"
echo "Release version: $VERSION"
if [ "$FLEX_VERSION" != "$VERSION" ]; then
echo "⚠️ Warning: Version mismatch detected"
echo " FlexLove.lua: $FLEX_VERSION"
echo " Release version: $VERSION"
echo " Using: $VERSION"
else
echo "✓ Version check passed"
fi
- name: Install lua-language-server
run: |
LLS_VERSION="3.7.4"
wget -q "https://github.com/LuaLS/lua-language-server/releases/download/${LLS_VERSION}/lua-language-server-${LLS_VERSION}-linux-x64.tar.gz"
mkdir -p ~/.local/bin/lua-language-server
tar -xzf "lua-language-server-${LLS_VERSION}-linux-x64.tar.gz" -C ~/.local/bin/lua-language-server
echo "$HOME/.local/bin/lua-language-server/bin" >> $GITHUB_PATH
rm "lua-language-server-${LLS_VERSION}-linux-x64.tar.gz"
- name: Verify lua-language-server installation
run: |
lua-language-server --version
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
cache-dependency-path: docs/package.json
- name: Install Node.js dependencies
working-directory: docs
run: npm ci
- name: Make scripts executable
run: |
chmod +x scripts/generate_docs.sh
chmod +x scripts/create-release.sh
chmod +x scripts/archive-docs.sh
- name: Archive previous documentation version
run: |
if [ -f "docs/api.html" ]; then
OLD_VERSION=$(grep -o 'FlexLöve v[0-9.]*' docs/api.html | head -1 | sed 's/FlexLöve v//')
if [ -n "$OLD_VERSION" ]; then
echo "Found previous version: v${OLD_VERSION}"
mkdir -p "docs/versions/v${OLD_VERSION}"
cp docs/api.html "docs/versions/v${OLD_VERSION}/api.html"
echo "✓ Archived previous documentation to docs/versions/v${OLD_VERSION}/"
else
echo "No previous version found, skipping archival"
fi
else
echo "No existing documentation to archive"
fi
- name: Generate documentation
run: |
./scripts/generate_docs.sh
# Verify api.html was created
if [ ! -f "docs/api.html" ]; then
echo "Error: docs/api.html was not generated"
exit 1
fi
echo "✓ Documentation generated successfully"
- name: Commit archived documentation
if: startsWith(github.ref, 'refs/tags/')
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add docs/versions/ docs/api.html docs/doc.json docs/doc.md
git commit -m "Archive previous documentation and generate v${{ steps.version.outputs.version }} docs [skip ci]" || echo "No changes to commit"
git push origin HEAD:main || echo "Nothing to push"
- name: Create release package
run: |
# Run release script non-interactively (auto-confirm overwrite)
echo "y" | ./scripts/create-release.sh || ./scripts/create-release.sh
# Verify files were created
VERSION="${{ steps.version.outputs.version }}"
if [ ! -f "releases/flexlove-v${VERSION}.zip" ]; then
echo "Error: Release zip was not created"
exit 1
fi
if [ ! -f "releases/flexlove-v${VERSION}.zip.sha256" ]; then
echo "Error: Checksum file was not created"
exit 1
fi
echo "✓ Release package created successfully"
- name: Upload release artifacts
uses: actions/upload-artifact@v4
with:
name: release-assets
path: |
releases/flexlove-v${{ steps.version.outputs.version }}.zip
releases/flexlove-v${{ steps.version.outputs.version }}.zip.sha256
docs/api.html
retention-days: 90
- name: Download release artifacts
uses: actions/download-artifact@v4
with:
name: release-assets
path: ./
- name: Extract checksum for release notes
id: checksum
run: |
VERSION="${{ steps.version.outputs.version }}"
CHECKSUM=$(cat "releases/flexlove-v${VERSION}.zip.sha256" | cut -d ' ' -f 1)
echo "checksum=$CHECKSUM" >> $GITHUB_OUTPUT
echo "Checksum: $CHECKSUM"
- name: Check if pre-release
id: prerelease
run: |
VERSION="${{ steps.version.outputs.version }}"
if [[ "$VERSION" =~ (alpha|beta|rc|dev) ]]; then
echo "is_prerelease=true" >> $GITHUB_OUTPUT
echo "This is a pre-release version"
else
echo "is_prerelease=false" >> $GITHUB_OUTPUT
echo "This is a stable release"
fi
- name: Generate release notes
id: release_notes
run: |
VERSION="${{ steps.version.outputs.version }}"
CHECKSUM="${{ steps.checksum.outputs.checksum }}"
cat > release_notes.md << 'EOF'
## Installation
Download `flexlove-v${{ steps.version.outputs.version }}.zip` and extract to your LÖVE2D project:
```bash
unzip flexlove-v${{ steps.version.outputs.version }}.zip
cp -r flexlove/modules ./
cp flexlove/FlexLove.lua ./
```
## Verification
Verify the download integrity using SHA256:
```bash
shasum -a 256 -c flexlove-v${{ steps.version.outputs.version }}.zip.sha256
```
**SHA256 Checksum:**
```
${{ steps.checksum.outputs.checksum }}
```
## Documentation
📚 [View Documentation](https://github.com/${{ github.repository }}/tree/main/docs)
## What's Included
- `FlexLove.lua` - Main library file
- `modules/` - All required module files (27 files)
- `LICENSE` - MIT License
- `README.txt` - Installation instructions
## Requirements
- LÖVE2D 11.0 or higher
---
_For examples and full source code, visit the [repository](https://github.com/${{ github.repository }})._
EOF
cat release_notes.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ steps.version.outputs.version }}
name: FlexLöve v${{ steps.version.outputs.version }}
body_path: release_notes.md
files: |
releases/flexlove-v${{ steps.version.outputs.version }}.zip
releases/flexlove-v${{ steps.version.outputs.version }}.zip.sha256
prerelease: ${{ steps.prerelease.outputs.is_prerelease }}
draft: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

4
.gitignore vendored
View File

@@ -8,3 +8,7 @@ themes/space/
tasks
testoutput
luacov.*
docs/doc.json
docs/doc.md
docs/node_modules
releases/

View File

@@ -63,8 +63,8 @@ Units.initialize(Context)
Units.initializeErrorHandler(ErrorHandler)
-- Add version and metadata
flexlove._VERSION = "0.2.0"
flexlove._DESCRIPTION = "UI Library for LÖVE Framework based on flexbox"
flexlove._VERSION = "0.2.1"
flexlove._DESCRIPTION = "0I Library for LÖVE Framework based on flexbox"
flexlove._URL = "https://github.com/mikefreno/FlexLove"
flexlove._LICENSE = [[
MIT License

View File

@@ -1,4 +1,4 @@
# FlexLöve v0.2.0
# FlexLöve v0.2.1
**A comprehensive UI library providing flexbox/grid layouts, theming, animations, and event handling for LÖVE2D games.**
@@ -67,6 +67,25 @@ function love.draw()
end
```
## Documentation
📚 **[View Full API Documentation](https://mikefreno.github.io/FlexLove/api.html)**
Complete API reference with all classes, methods, and properties is available on GitHub Pages. The documentation includes:
- Searchable sidebar navigation
- Syntax-highlighted code examples
- Version selector (access docs for previous versions)
- Detailed parameter and return value descriptions
### Documentation Versions
Access documentation for specific versions:
- **Latest:** [https://mikefreno.github.io/FlexLove/api.html](https://mikefreno.github.io/FlexLove/api.html)
- **Specific version:** `https://mikefreno.github.io/FlexLove/versions/v0.2.0/api.html`
Use the version dropdown in the documentation header to switch between versions.
## API Conventions
### Method Patterns

209
RELEASE.md Normal file
View File

@@ -0,0 +1,209 @@
# FlexLöve Release Process
This document describes how to create and publish a new release of FlexLöve.
## Automated Release (Recommended)
The easiest way to create a release is using the automated script:
```bash
./scripts/make-tag.sh
```
This interactive script will:
1. Show your current version
2. Ask you to select: Major / Minor / Patch / Custom version bump
3. Calculate the new version (resetting lower components to 0)
4. Update `FlexLove.lua` with the new version
5. Update `README.md` first line with the new version
6. Create a git commit: `v{version} release`
7. Create a git tag: `v{version}`
8. Prompt you to push the changes
After pushing the tag, GitHub Actions automatically:
- Archives previous documentation
- Generates new documentation
- Creates release package with SHA256 checksums
- Publishes GitHub release with download assets
### Example Usage
```bash
$ ./scripts/make-tag.sh
═══════════════════════════════════════
FlexLöve Version Bump & Tag Tool
═══════════════════════════════════════
Current version: v0.2.0
Select version bump type:
1) Major (breaking changes) 0.2.0 → 1.0.0
2) Minor (new features) 0.2.0 → 0.3.0
3) Patch (bug fixes) 0.2.0 → 0.2.1
4) Custom version
5) Cancel
Enter choice (1-5): 2
New version: v0.3.0
This will:
1. Update FlexLove.lua → flexlove._VERSION = "0.3.0"
2. Update README.md → first line version
3. Stage changes for commit
4. Create git tag v0.3.0
Proceed? (y/n) y
✓ Version bump complete!
Next steps:
1. Push commit and tag:
git push && git push origin v0.3.0
2. GitHub Actions will automatically:
• Archive previous documentation
• Generate new documentation
• Create release package with checksums
• Publish GitHub release
```
## Manual Release Workflow
If you need more control, follow these steps:
### 1. Update Version
Edit `FlexLove.lua` and update the version:
```lua
flexlove._VERSION = "0.3.0" -- Update this line
```
Also update `README.md` first line:
```markdown
# FlexLöve v0.3.0
```
### 2. Commit and Tag
```bash
git add FlexLove.lua README.md
git commit -m "v0.3.0 release"
git tag -a v0.3.0 -m "Release version 0.3.0"
git push && git push origin v0.3.0
```
### 3. GitHub Actions Takes Over
Once you push the tag, the automated workflow handles everything else.
## Local Release Package (Optional)
To create a local release package without GitHub Actions:
```bash
./scripts/create-release.sh
```
Output files:
- `releases/flexlove-v{version}.zip`
- `releases/flexlove-v{version}.zip.sha256`
### Verify Local Package
```bash
cd releases
shasum -a 256 -c flexlove-v0.3.0.zip.sha256
# Expected: flexlove-v0.3.0.zip: OK
```
## Release Checklist
- [ ] Version updated in `FlexLove.lua`
- [ ] Documentation regenerated (`./scripts/generate_docs.sh`)
- [ ] Changes committed and pushed
- [ ] Release package created (`./scripts/create-release.sh`)
- [ ] Checksum verified (`shasum -a 256 -c *.sha256`)
- [ ] Release package tested
- [ ] Git tag created and pushed
- [ ] GitHub release published with zip and checksum files
## Versioning
FlexLöve follows [Semantic Versioning](https://semver.org/):
- **MAJOR** version: Incompatible API changes
- **MINOR** version: New functionality (backwards-compatible)
- **PATCH** version: Bug fixes (backwards-compatible)
Example: `0.2.0``0.2.1` (bug fix) or `0.3.0` (new feature)
## What Gets Released
The release package includes **only** the files needed to use FlexLöve:
**Included:**
- `FlexLove.lua` - Main library
- `modules/` - All module files
- `LICENSE` - License terms
- `README.txt` - Installation instructions
**Not included:**
- `docs/` - Documentation (hosted on GitHub Pages)
- `examples/` - Example code (available in repository)
- `testing/` - Test suite
- `themes/` - Theme examples
- Development tools
Users who want examples, documentation source, or development tools should clone the full repository.
## Checksum Verification
Every release includes a SHA256 checksum file for security verification.
### For Developers (Creating Release)
The checksum is automatically generated when running `./scripts/create-release.sh`:
```bash
./scripts/create-release.sh
# Creates:
# - releases/flexlove-v0.3.0.zip
# - releases/flexlove-v0.3.0.zip.sha256
# Verify before publishing
cd releases
shasum -a 256 -c flexlove-v0.3.0.zip.sha256
# Output: flexlove-v0.3.0.zip: OK
```
### For End Users (Downloading Release)
After downloading a release from GitHub:
```bash
# Download both files:
# - flexlove-v0.3.0.zip
# - flexlove-v0.3.0.zip.sha256
# Verify integrity
shasum -a 256 -c flexlove-v0.3.0.zip.sha256
# If OK, safe to use
unzip flexlove-v0.3.0.zip
```
**macOS/Linux:** Use `shasum -a 256 -c`
**Windows:** Use `certutil -hashfile flexlove-v0.3.0.zip SHA256` and compare manually
## Automated Releases (Future)
Consider adding GitHub Actions workflow to automate:
- Version extraction
- Release package creation
- Documentation deployment
- GitHub release creation
See `.github/workflows/release.yml` (to be created)

0
docs/.nojekyll Normal file
View File

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

File diff suppressed because it is too large Load Diff

683
docs/build-docs.js Normal file
View 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
View 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",
};

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +0,0 @@
#!/bin/bash
# FlexLöve Documentation Generator
# This script generates HTML documentation from LuaLS annotations
echo "Generating FlexLöve documentation..."
# Get the directory where this script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
# Check if lua-language-server is installed
if ! command -v lua-language-server &> /dev/null; then
echo "Error: lua-language-server not found. Please install it first."
echo " macOS: brew install lua-language-server"
echo " Linux: See https://github.com/LuaLS/lua-language-server"
exit 1
fi
# Create docs directory if it doesn't exist
mkdir -p docs
# Generate documentation using lua-language-server
echo "Running lua-language-server documentation export..."
lua-language-server \
--doc="$SCRIPT_DIR" \
--doc_out_path="$SCRIPT_DIR/docs"
if [ $? -eq 0 ]; then
echo "✓ Documentation generated successfully!"
echo " - docs/doc.md (Markdown format)"
echo " - docs/doc.json (JSON format)"
echo " - docs/index.html (GitHub Pages)"
echo ""
echo "To view locally, open: file://$SCRIPT_DIR/docs/index.html"
echo "To publish, commit the docs/ directory and enable GitHub Pages."
else
echo "✗ Documentation generation failed"
exit 1
fi

58
scripts/archive-docs.sh Executable file
View File

@@ -0,0 +1,58 @@
#!/bin/bash
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}FlexLöve Documentation Archival${NC}"
echo ""
VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$VERSION" ]; then
echo -e "${RED}Error: Could not extract version from FlexLove.lua${NC}"
exit 1
fi
echo -e "${GREEN}Version detected: ${VERSION}${NC}"
if [ ! -f "docs/api.html" ]; then
echo -e "${RED}Error: docs/api.html not found${NC}"
echo "Please run ./scripts/generate_docs.sh first"
exit 1
fi
VERSION_DIR="docs/versions/v${VERSION}"
if [ -d "$VERSION_DIR" ]; then
echo -e "${YELLOW}Warning: $VERSION_DIR already exists${NC}"
read -p "Overwrite? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Aborted${NC}"
exit 1
fi
else
echo -e "${YELLOW}Creating version directory...${NC}"
mkdir -p "$VERSION_DIR"
fi
echo -e "${YELLOW}Archiving documentation...${NC}"
cp docs/api.html "$VERSION_DIR/api.html"
if [ ! -f "$VERSION_DIR/api.html" ]; then
echo -e "${RED}Error: Failed to copy documentation${NC}"
exit 1
fi
FILE_SIZE=$(du -h "$VERSION_DIR/api.html" | cut -f1)
echo ""
echo -e "${GREEN}✓ Documentation archived successfully!${NC}"
echo ""
echo -e " ${BLUE}Version:${NC} v${VERSION}"
echo -e " ${BLUE}Location:${NC} $VERSION_DIR/api.html"
echo -e " ${BLUE}Size:${NC} $FILE_SIZE"
echo ""

99
scripts/create-release.sh Executable file
View File

@@ -0,0 +1,99 @@
#!/bin/bash
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}FlexLöve Release Builder${NC}"
echo ""
VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$VERSION" ]; then
echo -e "${RED}Error: Could not extract version from FlexLove.lua${NC}"
exit 1
fi
echo -e "${GREEN}Version detected: ${VERSION}${NC}"
# Create releases directory if it doesn't exist
RELEASE_DIR="releases"
if [ ! -d "$RELEASE_DIR" ]; then
echo -e "${YELLOW}Creating releases directory...${NC}"
mkdir -p "$RELEASE_DIR"
fi
OUTPUT_FILE="${RELEASE_DIR}/flexlove-v${VERSION}.zip"
CHECKSUM_FILE="${OUTPUT_FILE}.sha256"
if [ -f "$OUTPUT_FILE" ] || [ -f "$CHECKSUM_FILE" ]; then
echo -e "${YELLOW}Warning: Release files already exist - overwriting${NC}"
[ -f "$OUTPUT_FILE" ] && echo " - $OUTPUT_FILE" && rm "$OUTPUT_FILE"
[ -f "$CHECKSUM_FILE" ] && echo " - $CHECKSUM_FILE" && rm "$CHECKSUM_FILE"
fi
TEMP_DIR=$(mktemp -d)
BUILD_DIR="${TEMP_DIR}/flexlove"
echo -e "${YELLOW}Creating release package...${NC}"
mkdir -p "$BUILD_DIR"
echo " → Copying FlexLove.lua"
cp FlexLove.lua "$BUILD_DIR/"
echo " → Copying modules/"
cp -r modules "$BUILD_DIR/"
echo " → Copying LICENSE"
cp LICENSE "$BUILD_DIR/"
echo " → Creating README.md"
cp README.md "$BUILD_DIR/"
echo -e "${YELLOW}Creating zip archive...${NC}"
ABS_OUTPUT_FILE="$(cd "$(dirname "$OUTPUT_FILE")" && pwd)/$(basename "$OUTPUT_FILE")"
cd "$TEMP_DIR"
zip -r -q "flexlove-v${VERSION}.zip" flexlove/
mv "flexlove-v${VERSION}.zip" "$ABS_OUTPUT_FILE"
cd - > /dev/null
echo -e "${YELLOW}Generating SHA256 checksum...${NC}"
CHECKSUM_FILE="${OUTPUT_FILE}.sha256"
cd "$RELEASE_DIR"
shasum -a 256 "flexlove-v${VERSION}.zip" > "flexlove-v${VERSION}.zip.sha256"
cd - > /dev/null
CHECKSUM=$(cat "$CHECKSUM_FILE" | cut -d ' ' -f 1)
echo -e "${YELLOW}Cleaning up...${NC}"
rm -rf "$TEMP_DIR"
FILE_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
echo ""
echo -e "${GREEN}✓ Release created successfully!${NC}"
echo ""
echo -e " ${BLUE}File:${NC} $OUTPUT_FILE"
echo -e " ${BLUE}Size:${NC} $FILE_SIZE"
echo -e " ${BLUE}Version:${NC} $VERSION"
echo -e " ${BLUE}SHA256:${NC} $CHECKSUM"
echo ""
echo -e "Contents:"
echo " - FlexLove.lua"
echo " - modules/ (27 files)"
echo " - LICENSE"
echo " - README.txt"
echo ""
echo -e "Files created:"
echo " - $OUTPUT_FILE"
echo " - $CHECKSUM_FILE"
echo ""
echo -e "${YELLOW}Verify checksum:${NC}"
echo " cd releases && shasum -a 256 -c flexlove-v${VERSION}.zip.sha256"

72
scripts/generate_docs.sh Executable file
View File

@@ -0,0 +1,72 @@
#!/bin/bash
YELLOW='\033[1;33m'
GREEN='\033[0;32m'
NC='\033[0m'
echo "Generating FlexLöve documentation..."
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PROJECT_ROOT="$( cd "$SCRIPT_DIR/.." && pwd )"
cd "$PROJECT_ROOT"
if [ -f "docs/api.html" ]; then
echo -e "${YELLOW}Checking for previous documentation version...${NC}"
OLD_VERSION=$(grep -o 'FlexLöve v[0-9.]*' docs/api.html | head -1 | sed 's/FlexLöve v//')
CURRENT_VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
if [ -n "$OLD_VERSION" ] && [ "$OLD_VERSION" != "$CURRENT_VERSION" ]; then
echo -e "${YELLOW}Found previous version v${OLD_VERSION}, archiving before generating new docs...${NC}"
mkdir -p "docs/versions/v${OLD_VERSION}"
cp docs/api.html "docs/versions/v${OLD_VERSION}/api.html"
echo -e "${GREEN}✓ Archived previous documentation to docs/versions/v${OLD_VERSION}/${NC}"
elif [ -n "$OLD_VERSION" ] && [ "$OLD_VERSION" = "$CURRENT_VERSION" ]; then
echo -e "${YELLOW}Same version (v${OLD_VERSION}), will overwrite current documentation${NC}"
fi
fi
if ! command -v lua-language-server &> /dev/null; then
echo "Error: lua-language-server not found. Please install it first."
echo " macOS: brew install lua-language-server"
echo " Linux: See https://github.com/LuaLS/lua-language-server"
exit 1
fi
mkdir -p docs
echo "Running lua-language-server documentation export..."
lua-language-server \
--doc="$PROJECT_ROOT" \
--doc_out_path="$PROJECT_ROOT/docs"
if [ $? -eq 0 ]; then
echo "✓ Markdown documentation generated"
echo "Building beautiful HTML documentation..."
cd "$PROJECT_ROOT/docs"
if [ ! -d "node_modules" ]; then
echo "Installing Node.js dependencies..."
npm install --silent
fi
npm run build --silent
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ HTML documentation built successfully!${NC}"
echo ""
echo "Generated files:"
echo " - docs/api.html (Beautiful, searchable API reference)"
echo " - docs/index.html (Landing page)"
echo " - docs/doc.md (Raw markdown)"
if [ -n "$OLD_VERSION" ] && [ "$OLD_VERSION" != "$CURRENT_VERSION" ]; then
echo " - docs/versions/v${OLD_VERSION}/api.html (Previous version archived)"
fi
else
echo "✗ HTML build failed, but markdown docs are available"
exit 1
fi
else
echo "✗ Documentation generation failed"
exit 1
fi

177
scripts/make-tag.sh Executable file
View File

@@ -0,0 +1,177 @@
#!/bin/bash
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
echo -e "${BLUE}═══════════════════════════════════════${NC}"
echo -e "${BLUE} FlexLöve Version Bump & Tag Tool ${NC}"
echo -e "${BLUE}═══════════════════════════════════════${NC}"
echo ""
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PROJECT_ROOT="$( cd "$SCRIPT_DIR/.." && pwd )"
cd "$PROJECT_ROOT"
if [ ! -d .git ] && [ ! -f .git ]; then
echo -e "${RED}Error: Not in a git repository${NC}"
exit 1
fi
if ! git diff-index --quiet HEAD --; then
echo -e "${YELLOW}Warning: You have uncommitted changes${NC}"
git status --short
echo ""
read -p "Continue anyway? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Aborted${NC}"
exit 1
fi
echo ""
fi
CURRENT_VERSION=$(grep -m 1 "_VERSION" FlexLove.lua | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$CURRENT_VERSION" ]; then
echo -e "${RED}Error: Could not extract version from FlexLove.lua${NC}"
exit 1
fi
echo -e "${CYAN}Current version:${NC} ${GREEN}v${CURRENT_VERSION}${NC}"
echo ""
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
MAJOR=$(echo "$MAJOR" | sed 's/[^0-9].*//')
MINOR=$(echo "$MINOR" | sed 's/[^0-9].*//')
PATCH=$(echo "$PATCH" | sed 's/[^0-9].*//')
echo -e "${CYAN}Select version bump type:${NC}"
echo " 1) Major (breaking changes) ${MAJOR}.${MINOR}.${PATCH}$((MAJOR+1)).0.0"
echo " 2) Minor (new features) ${MAJOR}.${MINOR}.${PATCH}${MAJOR}.$((MINOR+1)).0"
echo " 3) Patch (bug fixes) ${MAJOR}.${MINOR}.${PATCH}${MAJOR}.${MINOR}.$((PATCH+1))"
echo " 4) Custom version"
echo " 5) Cancel"
echo ""
read -p "Enter choice (1-5): " -n 1 -r CHOICE
echo ""
echo ""
case $CHOICE in
1)
NEW_MAJOR=$((MAJOR+1))
NEW_MINOR=0
NEW_PATCH=0
BUMP_TYPE="major"
;;
2)
NEW_MAJOR=$MAJOR
NEW_MINOR=$((MINOR+1))
NEW_PATCH=0
BUMP_TYPE="minor"
;;
3)
NEW_MAJOR=$MAJOR
NEW_MINOR=$MINOR
NEW_PATCH=$((PATCH+1))
BUMP_TYPE="patch"
;;
4)
read -p "Enter custom version (e.g., 1.0.0-beta): " CUSTOM_VERSION
NEW_VERSION="$CUSTOM_VERSION"
BUMP_TYPE="custom"
;;
5)
echo -e "${RED}Cancelled${NC}"
exit 0
;;
*)
echo -e "${RED}Invalid choice${NC}"
exit 1
;;
esac
# Construct new version (unless custom)
if [ "$BUMP_TYPE" != "custom" ]; then
NEW_VERSION="${NEW_MAJOR}.${NEW_MINOR}.${NEW_PATCH}"
fi
echo -e "${CYAN}New version:${NC} ${GREEN}v${NEW_VERSION}${NC}"
echo ""
echo -e "${YELLOW}This will:${NC}"
echo " 1. Update FlexLove.lua → flexlove._VERSION = \"${NEW_VERSION}\""
echo " 2. Update README.md → first line version"
echo " 3. Stage changes for commit"
echo " 4. Create git tag v${NEW_VERSION}"
echo ""
read -p "Proceed? (y/n) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${RED}Aborted${NC}"
exit 1
fi
echo ""
echo -e "${CYAN}[1/4]${NC} Updating FlexLove.lua..."
sed -i.bak "s/flexlove\._VERSION = \".*\"/flexlove._VERSION = \"${NEW_VERSION}\"/" FlexLove.lua
rm -f FlexLove.lua.bak
echo -e "${GREEN}✓ FlexLove.lua updated${NC}"
echo -e "${CYAN}[2/4]${NC} Updating README.md..."
FIRST_LINE=$(head -1 README.md)
if [[ "$FIRST_LINE" =~ ^#.*FlexLöve.*v[0-9]+\.[0-9]+\.[0-9]+ ]]; then
sed -i.bak -E "1s/v[0-9]+\.[0-9]+\.[0-9]+/v${NEW_VERSION}/" README.md
rm -f README.md.bak
echo -e "${GREEN}✓ README.md updated${NC}"
else
echo -e "${YELLOW}⚠ README.md first line doesn't match expected format, skipping${NC}"
echo -e "${YELLOW}Expected: # FlexLöve v0.0.0${NC}"
echo -e "${YELLOW}Found: $FIRST_LINE${NC}"
fi
echo -e "${CYAN}[3/4]${NC} Staging changes..."
git add FlexLove.lua README.md
echo -e "${GREEN}✓ Changes staged${NC}"
echo ""
echo -e "${CYAN}Changes to be committed:${NC}"
git diff --cached --stat
echo ""
echo -e "${YELLOW}Ready to commit and create tag${NC}"
echo -e "${CYAN}Commit message:${NC} v${NEW_VERSION} release"
echo -e "${CYAN}Tag:${NC} v${NEW_VERSION}"
echo ""
read -p "Commit changes and create tag? (y/n) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}Changes staged but not committed${NC}"
echo "You can:"
echo " - Review changes: git diff --cached"
echo " - Commit manually: git commit -m 'v${NEW_VERSION} release'"
echo " - Unstage: git restore --staged FlexLove.lua README.md"
exit 0
fi
# Commit changes
echo ""
echo -e "${CYAN}[4/4]${NC} Committing and tagging..."
git commit -m "v${NEW_VERSION} release"
git tag -a "v${NEW_VERSION}" -m "Release version ${NEW_VERSION}"
echo ""
echo -e "${GREEN}═══════════════════════════════════════${NC}"
echo -e "${GREEN}✓ Version bump complete!${NC}"
echo -e "${GREEN}═══════════════════════════════════════${NC}"
echo ""
echo -e "${CYAN}Version:${NC} ${CURRENT_VERSION}${GREEN}${NEW_VERSION}${NC}"
echo -e "${CYAN}Tag created:${NC} ${GREEN}v${NEW_VERSION}${NC}"
echo ""
echo -e "${BLUE}Release will be available at:${NC}"
echo " https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/releases/tag/v${NEW_VERSION}"
echo ""