[dyad] SchulOS markalama kabul kriterlerini doğrulama

This commit is contained in:
[dyad] committed 2026-08-02 01:55:22 +02:00
1 parent 0b0481a4d0
commit 5e66bae15b
57 files changed
+195 -191

No files matched your search

+1 -29
View File
@@ -1,29 +1 @@
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
<defs>
<style type="text/css">
.st194{fill:#2D2D2D;stroke:#FFFFFF;stroke-width:0.6317;stroke-miterlimit:10;}
.st23{fill:#FFFFFF;}
.z-breathe {
animation: breathe 2.5s ease-in-out infinite;
}
@keyframes breathe {
0%, 100% { opacity: 0.7; }
50% { opacity: 1; }
}
</style>
</defs>
<g>
<path class="st194" d="M24.51,28.51H5.49c-2.21,0-4-1.79-4-4V5.49c0-2.21,1.79-4,4-4h19.03c2.21,0,4,1.79,4,4v19.03
C28.51,26.72,26.72,28.51,24.51,28.51z"/>
<g class="z-breathe">
<path class="st23" d="M15.47,7.1l-1.3,1.85c-0.2,0.29-0.54,0.47-0.9,0.47h-7.1V7.09C6.16,7.1,15.47,7.1,15.47,7.1z"/>
<polygon class="st23" points="24.3,7.1 13.14,22.91 5.7,22.91 16.86,7.1"/>
<path class="st23" d="M14.53,22.91l1.31-1.86c0.2-0.29,0.54-0.47,0.9-0.47h7.09v2.33H14.53z"/>
</g>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" role="img" aria-labelledby="title"><title>SchulOS</title><rect width="48" height="48" rx="12" fill="#059669"/><path fill="#fff" d="M13 14.5c0-2.5 2-4.5 4.5-4.5h13A4.5 4.5 0 0 1 35 14.5v19c0 2.5-2 4.5-4.5 4.5h-13a4.5 4.5 0 0 1-4.5-4.5v-19Zm5 0v19h12v-19H18Zm3 4h6v3h-6v-3Zm0 6h6v3h-6v-3Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 355 B

+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "CompetenceTrack",
"short_name": "CompTrack",
"name": "SchulOS",
"short_name": "SchulOS",
"description": "Kompetenz- und Benotungsplattform für Schulen",
"start_url": "/",
"display": "standalone",
+64 -32
View File
@@ -1,8 +1,12 @@
// CompetenceTrack — Service Worker for PWA Offline Support
const CACHE_NAME = 'competencetrack-v3';
const STATIC_CACHE = 'competencetrack-static-v3';
const DATA_CACHE = 'competencetrack-data-v3';
const OFFLINE_CACHE = 'competencetrack-offline-v3';
// SchulOS — Service Worker for PWA Offline Support
const CACHE_NAME = 'schulos-v3';
const STATIC_CACHE = 'schulos-static-v3';
const DATA_CACHE = 'schulos-data-v3';
const OFFLINE_CACHE = 'schulos-offline-v3';
const SYNC_TAG = 'schulos-sync';
const LEGACY_SYNC_TAG = 'competencetrack-sync';
const SYNC_DB = 'schulos-sync-db';
const LEGACY_SYNC_DB = 'competencetrack-sync-db';
// Static assets to cache on install
const STATIC_ASSETS = [
@@ -33,19 +37,17 @@ self.addEventListener('install', (event) => {
);
});
// Activate event — clean up old caches
// Activate event — migrate queued writes before clearing legacy caches.
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((keys) => {
return Promise.all(
migrateLegacyPendingRequests()
.then(() => caches.keys())
.then((keys) => Promise.all(
keys
.filter((key) => key !== CACHE_NAME && key !== STATIC_CACHE && key !== DATA_CACHE && key !== OFFLINE_CACHE)
.map((key) => caches.delete(key))
);
}).then(() => {
console.log('[SW] Activated and old caches cleaned');
return self.clients.claim();
})
))
.then(() => self.clients.claim())
);
});
@@ -191,7 +193,7 @@ async function networkFirstWithOfflineFallback(request) {
// Store failed requests for background sync
async function storeRequestForSync(request) {
const db = await openIndexedDB();
const db = await openIndexedDB(SYNC_DB);
const tx = db.transaction('pending-requests', 'readwrite');
const store = tx.objectStore('pending-requests');
const requestData = {
@@ -202,16 +204,13 @@ async function storeRequestForSync(request) {
timestamp: Date.now(),
};
store.add(requestData);
await tx.done;
// Register for background sync
self.registration.sync.register('competencetrack-sync');
await transactionDone(tx);
self.registration.sync.register(SYNC_TAG);
}
// Open IndexedDB for storing pending requests
function openIndexedDB() {
function openIndexedDB(name) {
return new Promise((resolve, reject) => {
const request = indexedDB.open('competencetrack-sync-db', 1);
const request = indexedDB.open(name, 1);
request.onupgradeneeded = () => {
const db = request.result;
if (!db.objectStoreNames.contains('pending-requests')) {
@@ -223,18 +222,54 @@ function openIndexedDB() {
});
}
// Background sync event — replay queued requests when back online
function transactionDone(tx) {
return new Promise((resolve, reject) => {
tx.oncomplete = () => resolve();
tx.onerror = () => reject(tx.error);
tx.onabort = () => reject(tx.error);
});
}
async function migrateLegacyPendingRequests() {
const legacyDb = await openIndexedDB(LEGACY_SYNC_DB);
const legacyTx = legacyDb.transaction('pending-requests', 'readonly');
const legacyStore = legacyTx.objectStore('pending-requests');
const requests = await new Promise((resolve, reject) => {
const request = legacyStore.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
await transactionDone(legacyTx);
if (!requests.length) return;
const currentDb = await openIndexedDB(SYNC_DB);
const currentTx = currentDb.transaction('pending-requests', 'readwrite');
const currentStore = currentTx.objectStore('pending-requests');
for (const request of requests) currentStore.put(request);
await transactionDone(currentTx);
const deleteTx = legacyDb.transaction('pending-requests', 'readwrite');
deleteTx.objectStore('pending-requests').clear();
await transactionDone(deleteTx);
}
// Background sync event — replay queues from both brand generations.
self.addEventListener('sync', (event) => {
if (event.tag === 'competencetrack-sync') {
event.waitUntil(replayPendingRequests());
if (event.tag === SYNC_TAG || event.tag === LEGACY_SYNC_TAG) {
event.waitUntil(migrateLegacyPendingRequests().then(replayPendingRequests));
}
});
async function replayPendingRequests() {
const db = await openIndexedDB();
const db = await openIndexedDB(SYNC_DB);
const tx = db.transaction('pending-requests', 'readwrite');
const store = tx.objectStore('pending-requests');
const allRequests = await store.getAll();
const allRequests = await new Promise((resolve, reject) => {
const request = store.getAll();
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.error);
});
for (const reqData of allRequests) {
try {
@@ -244,15 +279,12 @@ async function replayPendingRequests() {
headers,
body: reqData.method !== 'GET' ? reqData.body : undefined,
});
if (response.ok) {
store.delete(reqData.timestamp);
}
if (response.ok) store.delete(reqData.timestamp);
} catch (error) {
console.warn('[SW] Failed to replay request:', error);
// Keep the request in the store for next sync attempt
}
}
await tx.done;
await transactionDone(tx);
}
// Push event — show notification (if push notifications are configured)
@@ -269,7 +301,7 @@ self.addEventListener('push', (event) => {
},
};
event.waitUntil(
self.registration.showNotification(data.title || 'CompetenceTrack', options)
self.registration.showNotification(data.title || 'SchulOS', options)
);
});