Introduce initial version of the Lonc app with core features, styling, and configurations.

- Add base app structure, including Bootstrap setup and Alpine.js integration.
- Implement authentication flow with session handling.
- Integrate stock management and label creation functionalities.
- Include responsive styling and theme using CSS variables and custom components.
- Add API clients for Tryton-based backend.
- Set up kitchen and dashboard navigation workflows.
- Configure service worker for PWA support.
This commit is contained in:
2026-04-06 09:24:22 +02:00
commit 929ee6557a
48 changed files with 4879 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" rx="120" fill="#000" />
<path d="M170 132h44v161c0 46 19 69 57 69 38 0 57-23 57-69V132h44v164c0 35-10 64-31 86-21 22-45 33-70 33s-49-11-70-33c-21-22-31-51-31-86V132z" fill="#fff" />
<circle cx="380" cy="170" r="34" fill="#fff" />
</svg>

After

Width:  |  Height:  |  Size: 337 B

+11
View File
@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<defs>
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#1f4b99" />
<stop offset="100%" stop-color="#5da9ff" />
</linearGradient>
</defs>
<rect width="512" height="512" rx="120" fill="url(#bg)" />
<path d="M170 132h44v161c0 46 19 69 57 69 38 0 57-23 57-69V132h44v164c0 35-10 64-31 86-21 22-45 33-70 33s-49-11-70-33c-21-22-31-51-31-86V132z" fill="#fff" />
<circle cx="380" cy="170" r="34" fill="#ebf3ff" />
</svg>

After

Width:  |  Height:  |  Size: 548 B

+23
View File
@@ -0,0 +1,23 @@
{
"name": "Lonc",
"short_name": "Lonc",
"description": "Kitchen stock labeling and stock management client for Tryton-backed household workflows.",
"start_url": "/#/",
"display": "standalone",
"background_color": "#f4f7fb",
"theme_color": "#1f4b99",
"icons": [
{
"src": "/icons/icon.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "/icons/icon-mask.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "maskable"
}
]
}
+43
View File
@@ -0,0 +1,43 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Lonc Offline</title>
<style>
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Avenir Next", "Segoe UI", sans-serif;
color: #1f2740;
background:
radial-gradient(circle at top left, rgba(90, 169, 255, 0.22), transparent 22%),
linear-gradient(180deg, #f8fbff 0%, #f4f7fb 42%, #eef2f8 100%);
}
main {
max-width: 28rem;
margin: 1.5rem;
padding: 2rem;
border-radius: 1.5rem;
background: rgba(255, 255, 255, 0.92);
box-shadow: 0 24px 48px rgba(24, 42, 79, 0.08);
}
h1 {
margin-top: 0;
}
</style>
</head>
<body>
<main>
<h1>You are offline</h1>
<p>
Lonc can still open its cached shell, but Tryton-backed data and save actions need the network.
</p>
<p>Reconnect and reload when you are ready to continue.</p>
</main>
</body>
</html>
+55
View File
@@ -0,0 +1,55 @@
const CACHE_NAME = 'lonc-shell-v1';
const APP_SHELL = ['/', '/index.html', '/manifest.webmanifest', '/offline.html', '/icons/icon.svg', '/icons/icon-mask.svg'];
self.addEventListener('install', (event) => {
event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL)));
self.skipWaiting();
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) =>
Promise.all(
keys
.filter((key) => key !== CACHE_NAME)
.map((key) => caches.delete(key)),
),
),
);
self.clients.claim();
});
self.addEventListener('fetch', (event) => {
if (event.request.method !== 'GET') {
return;
}
const requestUrl = new URL(event.request.url);
if (requestUrl.origin !== self.location.origin) {
return;
}
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(async () => {
const shell = await caches.match('/index.html');
return shell || caches.match('/offline.html');
}),
);
return;
}
event.respondWith(
caches.match(event.request).then((response) => {
return (
response ||
fetch(event.request).then((networkResponse) => {
const clone = networkResponse.clone();
caches.open(CACHE_NAME).then((cache) => cache.put(event.request, clone));
return networkResponse;
})
);
}),
);
});