docs: update screenshots to reflect current UI state

Replace old screenshots with new ones showing updated dashboard design and weather widget. Update README to display mobile + desktop side-by-side, regenerate social preview images with new dashboard screenshot.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Ulas Kalayci
2026-05-05 11:22:37 +02:00
parent 289b079f47
commit f1dd8e5161
78 changed files with 143 additions and 24 deletions
+15 -16
View File
@@ -14,31 +14,30 @@
<table>
<tr>
<td align="center" width="33%">
<td align="center" width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/mobile-dark/mobile-dark-dashboard-2.png">
<source media="(prefers-color-scheme: light)" srcset="docs/screenshots/mobile-light/mobile-light-dashboard-2.png">
<img src="docs/screenshots/mobile-light/mobile-light-dashboard-2.png" alt="Dashboard" width="240">
<source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/01-mobile-dark.png">
<source media="(prefers-color-scheme: light)" srcset="docs/screenshots/01-mobile-light.png">
<img src="docs/screenshots/01-mobile-light.png" alt="Mobile Dashboard" width="280">
</picture>
<br>
<sub>Mobile Dashboard</sub>
</td>
<td align="center" width="33%">
<td align="center" width="50%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/mobile-dark/mobile-dark-tasks-2.png">
<source media="(prefers-color-scheme: light)" srcset="docs/screenshots/mobile-light/mobile-light-tasks-2.png">
<img src="docs/screenshots/mobile-light/mobile-light-tasks-2.png" alt="Tasks" width="240">
</picture>
</td>
<td align="center" width="33%">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/mobile-dark/mobile-dark-meal.png">
<source media="(prefers-color-scheme: light)" srcset="docs/screenshots/mobile-light/mobile-light-meal.png">
<img src="docs/screenshots/mobile-light/mobile-light-meal.png" alt="Meals" width="240">
<source media="(prefers-color-scheme: dark)" srcset="docs/screenshots/01-web-dark.png">
<source media="(prefers-color-scheme: light)" srcset="docs/screenshots/01-web-light.png">
<img src="docs/screenshots/01-web-light.png" alt="Desktop Dashboard" width="480">
</picture>
<br>
<sub>Desktop Dashboard</sub>
</td>
</tr>
</table>
<p align="center"><sub>Toggle GitHub light/dark mode to see both themes.</sub></p>
<p align="center">
<sub>Toggle GitHub light/dark mode to see both themes • <a href="https://ulsklyc.github.io/oikos/">View all screenshots</a></sub>
</p>
Oikos is a self-hosted web app for families who want to organize their everyday life in one place — without cloud accounts, subscriptions, or data leaving the house. It runs as a Docker container on any home server or NAS, is accessible from every device in the household, and can be installed as a PWA on phones and tablets.
+8 -8
View File
@@ -651,35 +651,35 @@
</div>
<div class="screenshots-track" role="region" aria-label="Screenshots" tabindex="0">
<div class="screenshot-item reveal">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-dashboard-2.png" data-dark="screenshots/mobile-dark/mobile-dark-dashboard-2.png" src="screenshots/mobile-light/mobile-light-dashboard-2.png" alt="Oikos Dashboard" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/01-mobile-light.png" data-dark="screenshots/01-mobile-dark.png" src="screenshots/01-mobile-light.png" alt="Oikos Dashboard" width="270" height="480" loading="lazy">
<p class="screenshot-label">Dashboard</p>
</div>
<div class="screenshot-item reveal reveal-delay-1">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-tasks-2.png" data-dark="screenshots/mobile-dark/mobile-dark-tasks-2.png" src="screenshots/mobile-light/mobile-light-tasks-2.png" alt="Task Management" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/02-mobile-light.png" data-dark="screenshots/02-mobile-dark.png" src="screenshots/02-mobile-light.png" alt="Task Management" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_tasks_title">Tasks</p>
</div>
<div class="screenshot-item reveal reveal-delay-2">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-meal.png" data-dark="screenshots/mobile-dark/mobile-dark-meal.png" src="screenshots/mobile-light/mobile-light-meal.png" alt="Meal Planning" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/03-mobile-light.png" data-dark="screenshots/03-mobile-dark.png" src="screenshots/03-mobile-light.png" alt="Meal Planning" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_meals_title">Meals</p>
</div>
<div class="screenshot-item reveal reveal-delay-3">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-shopping.png" data-dark="screenshots/mobile-dark/mobile-dark-shopping.png" src="screenshots/mobile-light/mobile-light-shopping.png" alt="Shopping Lists" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/04-mobile-light.png" data-dark="screenshots/04-mobile-dark.png" src="screenshots/04-mobile-light.png" alt="Shopping Lists" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_shopping_title">Shopping</p>
</div>
<div class="screenshot-item reveal">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-calendar.png" data-dark="screenshots/mobile-dark/mobile-dark-calendar.png" src="screenshots/mobile-light/mobile-light-calendar.png" alt="Calendar" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/05-mobile-light.png" data-dark="screenshots/05-mobile-dark.png" src="screenshots/05-mobile-light.png" alt="Calendar" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_calendar_title">Calendar</p>
</div>
<div class="screenshot-item reveal reveal-delay-1">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-budget-2.png" data-dark="screenshots/mobile-dark/mobile-dark-budget-2.png" src="screenshots/mobile-light/mobile-light-budget-2.png" alt="Budget Tracking" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/06-mobile-light.png" data-dark="screenshots/06-mobile-dark.png" src="screenshots/06-mobile-light.png" alt="Budget Tracking" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_budget_title">Budget</p>
</div>
<div class="screenshot-item reveal reveal-delay-2">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-notes-2.png" data-dark="screenshots/mobile-dark/mobile-dark-notes-2.png" src="screenshots/mobile-light/mobile-light-notes-2.png" alt="Notes" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/07-mobile-light.png" data-dark="screenshots/07-mobile-dark.png" src="screenshots/07-mobile-light.png" alt="Notes" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_notes_title">Notes</p>
</div>
<div class="screenshot-item reveal reveal-delay-3">
<img class="screenshot-img" data-light="screenshots/mobile-light/mobile-light-contacts-2.png" data-dark="screenshots/mobile-dark/mobile-dark-contacts-2.png" src="screenshots/mobile-light/mobile-light-contacts-2.png" alt="Contacts" width="270" height="480" loading="lazy">
<img class="screenshot-img" data-light="screenshots/08-mobile-light.png" data-dark="screenshots/08-mobile-dark.png" src="screenshots/08-mobile-light.png" alt="Contacts" width="270" height="480" loading="lazy">
<p class="screenshot-label" data-i18n="feat_contacts_title">Contacts</p>
</div>
</div>
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 940 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 940 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 479 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 347 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 583 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 507 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 447 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 KiB

After

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 381 KiB

+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env node
import sharp from 'sharp';
import { readFileSync } from 'fs';
const SCREENSHOT = 'docs/screenshots/01-web-light.png';
const BG_COLOR = '#1A1A28';
// Social image dimensions
const DIMENSIONS = {
'og-image.png': { width: 1200, height: 630 },
'twitter-image.png': { width: 1200, height: 675 },
'social-preview.png': { width: 1280, height: 640 }
};
async function createSocialImage(filename, width, height) {
// Load and resize screenshot to fit right side (60% of width)
const screenshotWidth = Math.floor(width * 0.55);
const screenshotHeight = Math.floor(height * 0.7);
const screenshot = await sharp(SCREENSHOT)
.resize(screenshotWidth, screenshotHeight, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.toBuffer();
// Create SVG with text and layout
const svg = `
<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg">
<!-- Background -->
<rect width="${width}" height="${height}" fill="${BG_COLOR}"/>
<!-- Left side content area -->
<g transform="translate(60, ${height / 2 - 120})">
<!-- Logo badge -->
<rect x="0" y="0" width="160" height="28" rx="4" fill="#0A84FF" opacity="0.15"/>
<text x="12" y="19" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="600" fill="#0A84FF" letter-spacing="0.5">
SELF-HOSTED · OPEN SOURCE
</text>
<!-- Title -->
<text x="0" y="80" font-family="system-ui, -apple-system, sans-serif" font-size="64" font-weight="700" fill="#FFFFFF">
Oikos
</text>
<!-- Description -->
<text x="0" y="130" font-family="system-ui, -apple-system, sans-serif" font-size="18" fill="#B0B0B8" font-weight="400">
<tspan x="0" dy="0">The family planner that respects your</tspan>
<tspan x="0" dy="28">privacy. Tasks, calendars, shopping, meals,</tspan>
<tspan x="0" dy="28">budget — on your own server.</tspan>
</text>
<!-- Feature badges -->
<g transform="translate(0, 240)">
<g>
<rect x="0" y="0" width="90" height="32" rx="6" fill="#2A2A38"/>
<text x="12" y="21" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500" fill="#8E8E93">✓ Tasks</text>
</g>
<g transform="translate(100, 0)">
<rect x="0" y="0" width="110" height="32" rx="6" fill="#2A2A38"/>
<text x="12" y="21" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500" fill="#8E8E93">📅 Calendar</text>
</g>
<g transform="translate(220, 0)">
<rect x="0" y="0" width="110" height="32" rx="6" fill="#2A2A38"/>
<text x="12" y="21" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500" fill="#8E8E93">🛒 Shopping</text>
</g>
<g transform="translate(340, 0)">
<rect x="0" y="0" width="90" height="32" rx="6" fill="#2A2A38"/>
<text x="12" y="21" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="500" fill="#8E8E93">🍽 Meals</text>
</g>
</g>
</g>
</svg>
`;
// Position screenshot on the right side
const screenshotX = width - screenshotWidth - 40;
const screenshotY = Math.floor((height - screenshotHeight) / 2);
// Composite everything together
const image = await sharp({
create: {
width,
height,
channels: 4,
background: BG_COLOR
}
})
.composite([
{
input: Buffer.from(svg),
top: 0,
left: 0
},
{
input: screenshot,
top: screenshotY,
left: screenshotX
}
])
.png()
.toFile(`docs/${filename}`);
console.log(`✓ Created docs/${filename} (${width}x${height})`);
}
async function main() {
console.log('Generating social preview images...\n');
for (const [filename, { width, height }] of Object.entries(DIMENSIONS)) {
await createSocialImage(filename, width, height);
}
console.log('\n✓ All social images generated successfully!');
}
main().catch(err => {
console.error('Error:', err.message);
process.exit(1);
});