Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions .github/workflows/update-landing-page.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Update Landing Page

on:
release:
types: [published]
workflow_dispatch: # Manual trigger for testing/emergency updates

permissions:
contents: write

jobs:
update-version:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.GITHUB_TOKEN }}

- name: Extract version from tag
id: version
run: |
# Extract version from git tag (removes 'v' prefix)
VERSION="${GITHUB_REF#refs/tags/v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Extracted version: ${VERSION}"

- name: Update download.js
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "Updating download.js to version ${VERSION}..."

# Update CURRENT_VERSION constant in download.js
sed -i "s/const CURRENT_VERSION = '[^']*'/const CURRENT_VERSION = '${VERSION}'/" docs/download.js

# Verify the change
grep "CURRENT_VERSION" docs/download.js

- name: Update index.html
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "Updating index.html to version ${VERSION}..."

# Update all version references (e.g., v0.0.37 -> v0.0.38)
# This handles version badges, links, and download URLs
sed -i "s/v[0-9]\+\.[0-9]\+\.[0-9]\+/v${VERSION}/g" docs/index.html

# Verify changes
echo "Updated version references:"
grep -n "v${VERSION}" docs/index.html | head -5

- name: Verify changes
run: |
echo "=== Git status ==="
git status

echo "=== Changed files ==="
git diff --name-only

echo "=== Version in download.js ==="
grep "CURRENT_VERSION" docs/download.js

echo "=== Version badge in index.html ==="
grep -A2 "Latest:" docs/index.html | head -3

- name: Commit and push changes
run: |
VERSION="${{ steps.version.outputs.version }}"

# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Stage changes
git add docs/download.js docs/index.html

# Commit (skip if no changes)
git commit -m "Update landing page to v${VERSION}" || {
echo "No changes to commit"
exit 0
}

# Push to main
git push origin main

- name: Summary
run: |
VERSION="${{ steps.version.outputs.version }}"
echo "✅ Landing page updated to v${VERSION}"
echo "📦 Changes committed and pushed to main branch"
echo "🌐 Live at: https://familiar-software.github.io/familiar/"
echo ""
echo "Updated files:"
echo " - docs/download.js"
echo " - docs/index.html"
83 changes: 83 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Familiar Landing Page

This folder contains the GitHub Pages landing page for Familiar.

## Overview

The landing page provides:
- Auto-detected architecture downloads (Apple Silicon vs Intel)
- Feature highlights and benefits
- How-it-works guide with screenshots
- System requirements
- FAQ section
- Automatic version updates via GitHub Actions

## Structure

```
docs/
├── index.html # Main landing page
├── input.css # Tailwind source
├── styles.css # Compiled Tailwind CSS (generated)
├── download.js # Architecture detection logic
├── assets/
│ ├── familiar-icon.png # App icon
│ ├── familiar-settings.png # Settings screenshot
│ └── og-image.png # Social preview (1200x630)
└── README.md # This file
```

## Development

**Build CSS:**
```bash
npm run css:landing
```

**Watch mode (auto-rebuild on changes):**
```bash
npm run css:landing:watch
```

**Preview locally:**
Open `docs/index.html` in a browser.

## Deployment

The landing page is automatically deployed via GitHub Pages from the `docs/` folder on the `main` branch.

**Live URL:** https://familiar-software.github.io/familiar/

## Version Updates

Version numbers are automatically updated by `.github/workflows/update-landing-page.yml` when a new release is published.

The workflow updates:
- `docs/download.js` - CURRENT_VERSION constant
- `docs/index.html` - Version badges and links

## Architecture Detection

The page uses JavaScript to detect the user's Mac architecture (Apple Silicon vs Intel) and presents the correct download automatically.

**Fallbacks:**
- Non-Mac users see a "macOS only" message
- JavaScript-disabled users see both download options
- Users can always access the alternative download via "Need a different version?"

## Assets

**Required images:**
- `familiar-icon.png` - Copied from `src/icon.png`
- `familiar-settings.png` - Copied from `docs/readme/familiar-settings.png`
- `og-image.png` - Create a 1200x630px social preview image

To update assets, modify the originals and run:
```bash
cp src/icon.png docs/assets/familiar-icon.png
cp docs/readme/familiar-settings.png docs/assets/familiar-settings.png
```

## License

GPL-3.0-only (same as the main project)
Binary file added docs/assets/familiar-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/familiar-settings.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/assets/og-image.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: Create a 1200x630px Open Graph image for social media previews
155 changes: 155 additions & 0 deletions docs/download.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Architecture detection and download link generation for Familiar
const GITHUB_REPO = 'familiar-software/familiar';
const CURRENT_VERSION = '0.0.37'; // Auto-updated by CI

/**
* Detect macOS architecture (Apple Silicon vs Intel)
* @returns {'arm64'|'x64'} Detected architecture
*/
function detectArchitecture() {
const ua = navigator.userAgent;

// Check if we're on macOS
if (!ua.includes('Mac')) {
return null; // Not a Mac
}

// Modern API (Chromium-based browsers)
// Note: This API is still experimental and may not be available
if (navigator.userAgentData?.platform === 'macOS') {
// Default to Apple Silicon (most common in 2026)
return 'arm64';
}

// Heuristic: Check for Intel indicators in user agent
if (ua.includes('Intel')) {
return 'x64';
}

// Check for explicit ARM/Apple Silicon indicators
if (ua.includes('ARM') || ua.includes('Apple')) {
return 'arm64';
}

// Default: arm64 (70%+ of Macs are M-series by 2026)
// This is a safe default as M1 was released in 2020
return 'arm64';
}

/**
* Check if user is on macOS
* @returns {boolean}
*/
function isMacOS() {
return navigator.userAgent.includes('Mac');
}

/**
* Generate download links for a specific version and architecture
* @param {string} version - Version number (e.g., '0.0.37')
* @param {'arm64'|'x64'} arch - Architecture
* @returns {{dmg: string, zip: string}} Download URLs
*/
function getDownloadLinks(version, arch) {
const base = `https://github.com/${GITHUB_REPO}/releases/download/v${version}`;
return {
dmg: `${base}/Familiar-${version}-${arch}.dmg`,
zip: `${base}/Familiar-${version}-${arch}-mac.zip`,
};
}

/**
* Get human-readable architecture name
* @param {'arm64'|'x64'} arch
* @returns {string}
*/
function getArchitectureName(arch) {
return arch === 'arm64' ? 'Apple Silicon (M1/M2/M3/M4)' : 'Intel';
}

/**
* Initialize download page - detect architecture and update UI
*/
function initializeDownloadPage() {
// Check if user is on macOS
if (!isMacOS()) {
showNonMacWarning();
return;
}

// Detect architecture
const arch = detectArchitecture();
const altArch = arch === 'arm64' ? 'x64' : 'arm64';

// Update detected architecture text
const detectedArchEl = document.getElementById('detected-arch');
if (detectedArchEl) {
detectedArchEl.textContent = getArchitectureName(arch);
}

// Set primary download button
const primaryBtn = document.getElementById('download-primary');
if (primaryBtn) {
const primaryLinks = getDownloadLinks(CURRENT_VERSION, arch);
primaryBtn.href = primaryLinks.dmg;

// Update button text to show architecture
const btnText = primaryBtn.querySelector('span');
if (btnText) {
btnText.textContent = `Download for ${getArchitectureName(arch)}`;
}
}

// Set alternative download link
const altLink = document.getElementById('download-alt');
if (altLink) {
const altLinks = getDownloadLinks(CURRENT_VERSION, altArch);
altLink.href = altLinks.dmg;
}

// Set alternative architecture name
const altArchName = document.getElementById('alt-arch-name');
if (altArchName) {
altArchName.textContent = getArchitectureName(altArch);
}
}

/**
* Show warning for non-Mac users
*/
function showNonMacWarning() {
const detectedArchEl = document.getElementById('detected-arch');
if (detectedArchEl) {
detectedArchEl.textContent = 'Not macOS';
detectedArchEl.classList.add('text-red-600', 'dark:text-red-400');
}

const primaryBtn = document.getElementById('download-primary');
if (primaryBtn) {
primaryBtn.disabled = true;
primaryBtn.classList.remove('bg-indigo-600', 'hover:bg-indigo-700');
primaryBtn.classList.add('bg-zinc-400', 'cursor-not-allowed');

const btnText = primaryBtn.querySelector('span');
if (btnText) {
btnText.textContent = 'macOS Only';
}

// Show helpful message
const parentEl = primaryBtn.parentElement;
if (parentEl) {
const warningMsg = document.createElement('p');
warningMsg.className = 'text-sm text-red-600 dark:text-red-400 mt-2';
warningMsg.textContent = 'Familiar is currently only available for macOS 14.0 or later.';
parentEl.appendChild(warningMsg);
}
}
}

// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeDownloadPage);
} else {
// DOM already loaded
initializeDownloadPage();
}
Loading
Loading