first commit; dx 1.0 beta
@@ -0,0 +1,24 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# React + Vite
|
||||||
|
|
||||||
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
|
## Expanding the ESLint configuration
|
||||||
|
|
||||||
|
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
todo md
|
||||||
|
<!--
|
||||||
|
- [ ] write changes engine in php
|
||||||
|
- [ ] predict all possible unexpected situation (write here)
|
||||||
|
- lesson starts with
|
||||||
|
- 0
|
||||||
|
- -1
|
||||||
|
- -2
|
||||||
|
- lessons on saturday / sunday 💀💀
|
||||||
|
- missing lesson (like 1,2, 4; also don't forger about this in editor)
|
||||||
|
- [x] start develop editor ui -->
|
||||||
@@ -0,0 +1,370 @@
|
|||||||
|
<?php
|
||||||
|
include 'k-api.php';
|
||||||
|
|
||||||
|
function db()
|
||||||
|
{
|
||||||
|
$pdo = new PDO('sqlite:./data.db');
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
return $pdo;
|
||||||
|
};
|
||||||
|
|
||||||
|
function findClosestDateSort($array, $targetDate)
|
||||||
|
{
|
||||||
|
$targetTimestamp = DateTime::createFromFormat('d-m-y', $targetDate)->getTimestamp();
|
||||||
|
usort($array, function ($a, $b) use ($targetTimestamp) {
|
||||||
|
$aTimestamp = DateTime::createFromFormat('d-m-y', $a['fromDate'])->getTimestamp();
|
||||||
|
$bTimestamp = DateTime::createFromFormat('d-m-y', $b['fromDate'])->getTimestamp();
|
||||||
|
$aDiff = abs($aTimestamp - $targetTimestamp);
|
||||||
|
$bDiff = abs($bTimestamp - $targetTimestamp);
|
||||||
|
return $aDiff - $bDiff;
|
||||||
|
});
|
||||||
|
return $array[0];
|
||||||
|
}
|
||||||
|
function getDayOfWeek(string $date)
|
||||||
|
{
|
||||||
|
$p = explode('-', $date);
|
||||||
|
if (count($p) !== 3) throw new InvalidArgumentException('DD-MM-YY|YYYY');
|
||||||
|
[$d, $m, $y] = $p;
|
||||||
|
if (strlen($y) === 2) $y = '20' . $y;
|
||||||
|
$dt = DateTime::createFromFormat('Y-m-d', "$y-$m-$d");
|
||||||
|
if (!$dt) throw new InvalidArgumentException('Invalid date');
|
||||||
|
return (int)$dt->format('N') - 1; // 0=Mon ... 6=Sun
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinArraysByKey(array $primaryArray, array $secondaryArray, bool $doNotOverwrite = false, string $key = 'num'): array
|
||||||
|
{
|
||||||
|
// Index secondary array once for O(1) lookups
|
||||||
|
$indexedArray = array_column($secondaryArray, null, $key);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
foreach ($primaryArray as $item) {
|
||||||
|
if (!isset($item[$key])) {
|
||||||
|
$result[] = $item;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentKey = $item[$key];
|
||||||
|
|
||||||
|
if (isset($indexedArray[$currentKey])) {
|
||||||
|
// Merge based on $doNotOverwrite flag
|
||||||
|
$result[] = $doNotOverwrite
|
||||||
|
? array_merge($indexedArray[$currentKey], $item) // Primary values take precedence
|
||||||
|
: array_merge($item, $indexedArray[$currentKey]); // Secondary values take precedence
|
||||||
|
} else {
|
||||||
|
$result[] = $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FastDBReq(PDO $db, string $sql, array $params = []): array
|
||||||
|
{
|
||||||
|
// ivan
|
||||||
|
// pickme love
|
||||||
|
// <3 <3 <3 <3
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CreateApi(function ($api) {
|
||||||
|
$api->on('/', 'GET', function () {
|
||||||
|
return 'dengi';
|
||||||
|
});
|
||||||
|
$api->on('/login', 'POST', function ($req) {
|
||||||
|
if (!isset($req->data['classId'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "class is empty";
|
||||||
|
}
|
||||||
|
$classId = substr(strtoupper($req->data['classId']), 0, 10);
|
||||||
|
// according docs (UPPERCASE, MIN 3 MAX 10)
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM classes WHERE classid = ?", [$classId]);
|
||||||
|
$db = null;
|
||||||
|
if (count($results) != 0) {
|
||||||
|
return $results[0];
|
||||||
|
} else {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "класс $classId не найден";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$api->on('/get_class_user_f', 'POST', function ($req) {
|
||||||
|
if (!isset($req->data['classId'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
$classId = substr(strtoupper($req->data['classId']), 0, 10);
|
||||||
|
// according docs (UPPERCASE, MIN 3 MAX 10)
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT userclassname FROM classes WHERE classid = ?", [$classId]);
|
||||||
|
$db = null;
|
||||||
|
|
||||||
|
if (count($results) != 0) {
|
||||||
|
return $results[0];
|
||||||
|
} else {
|
||||||
|
$req->res->code(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$api->on('/get_admin_user_f', 'POST', function ($req) {
|
||||||
|
if (!isset($req->data['adminId'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
$adminId = $req->data['adminId'];
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT adminName FROM admins where adminid = ?", [$adminId]);
|
||||||
|
$db = null;
|
||||||
|
|
||||||
|
if (count($results) != 0) {
|
||||||
|
return $results[0];
|
||||||
|
} else {
|
||||||
|
$req->res->code(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$api->on('/admin_login', 'POST', function ($req) {
|
||||||
|
if (!isset($req->data['adminId'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "admin is empty";
|
||||||
|
}
|
||||||
|
$adminId = $req->data['adminId'];
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM admins WHERE adminid = ?", [$adminId]);
|
||||||
|
$db = null;
|
||||||
|
|
||||||
|
if (count($results) != 0) {
|
||||||
|
return $results[0];
|
||||||
|
} else {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "админ не найден";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$api->on('/req_client_schedule', 'POST', function ($req) {
|
||||||
|
// NOTE: THIS IS SCHEDULE FOR USER (SHOULD BE WITH CHANGES AND CALLS)
|
||||||
|
// types = [0 - default schedule, 1 - with schedule changes, 2 - with schedule and rings]
|
||||||
|
if (!$req->hasData(['classId', 'day'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "net dannih";
|
||||||
|
}
|
||||||
|
$classId = substr(strtoupper($req->data['classId']), 0, 10);
|
||||||
|
$day = $req->data['day'];
|
||||||
|
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM changes WHERE classId = ? AND forDay = ?", [$classId, $day]);
|
||||||
|
|
||||||
|
|
||||||
|
if (count($results) > 0) {
|
||||||
|
// return only changes
|
||||||
|
$content = json_decode($results[0]['content'], true);
|
||||||
|
$has_full_rings = true;
|
||||||
|
foreach ($content as $idx => $item) {
|
||||||
|
if (!isset($item['t-begin']) || !isset($item['t-end'])) {
|
||||||
|
$has_full_rings = false;
|
||||||
|
// optionally record $idx
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($has_full_rings) {
|
||||||
|
$db = null;
|
||||||
|
// with rings
|
||||||
|
return ['data' => $content, 'type' => 2];
|
||||||
|
} else {
|
||||||
|
// without rings
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM RINGS WHERE classId = ?", [$classId]);
|
||||||
|
$rings = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||||||
|
$out = joinArraysByKey($content, $rings, true);
|
||||||
|
$db = null;
|
||||||
|
return ['data' => $out, 'type' => 1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// return shedules + calls
|
||||||
|
$dayOfWeek = getDayOfWeek($day);
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM schedules WHERE classId = ? AND dayOfWeek = ?", [$classId, $dayOfWeek]);
|
||||||
|
if (count($results) > 0) {
|
||||||
|
$out = [];
|
||||||
|
$schedule = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM RINGS WHERE classId = ?", [$classId]);
|
||||||
|
$rings = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||||||
|
$out = joinArraysByKey($schedule, $rings);
|
||||||
|
$db = null;
|
||||||
|
return ['data' => $out, 'type' => 0];
|
||||||
|
} else {
|
||||||
|
$db = null;
|
||||||
|
return ['data' => []];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$api->on('/editor_data', "POST", function ($req) {
|
||||||
|
if (!$req->hasData(['tab', 'day', 'adminId'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "bad data";
|
||||||
|
}
|
||||||
|
$adminId = $req->data['adminId'];
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM admins WHERE adminId=?", [$adminId]);
|
||||||
|
if (count($results) == 0) {
|
||||||
|
$db = null;
|
||||||
|
$req->res->code(400);
|
||||||
|
return "админ не найден";
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
$classId = $results[0]['adminClass'];
|
||||||
|
$day = $req->data['day'];
|
||||||
|
$tab = intval($req->data['tab']);
|
||||||
|
|
||||||
|
$changes = null;
|
||||||
|
$schedule = [];
|
||||||
|
$rings = [];
|
||||||
|
|
||||||
|
if ($tab != 2) {
|
||||||
|
if ($tab == 0) {
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM changes WHERE classId = ? AND forDay = ?", [$classId, $day]);
|
||||||
|
if (count($results) > 0) {
|
||||||
|
$changes = json_decode($results[0]['content'], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dayOfWeek = getDayOfWeek($day);
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM schedules WHERE classId = ? AND dayOfWeek = ?", [$classId, $dayOfWeek]);
|
||||||
|
if (count($results) > 0) {
|
||||||
|
$schedule = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM RINGS WHERE classId = ?", [$classId]);
|
||||||
|
if (count($results) > 0) {
|
||||||
|
$rings = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db = null;
|
||||||
|
|
||||||
|
switch ($tab) {
|
||||||
|
case 0:
|
||||||
|
if ($changes === null) { // type check!!!
|
||||||
|
return $schedule;
|
||||||
|
} else {
|
||||||
|
return $changes;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
return $schedule;
|
||||||
|
case 2:
|
||||||
|
return $rings;
|
||||||
|
default:
|
||||||
|
return "tab not found dengi dengi";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$api->on(
|
||||||
|
"/editor_publish",
|
||||||
|
"POST",
|
||||||
|
function ($req) {
|
||||||
|
if (!$req->hasData(['adminId', 'tab', 'day', 'newData'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "bad data";
|
||||||
|
}
|
||||||
|
$adminId = $req->data['adminId'];
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM admins WHERE adminId=?", [$adminId]);
|
||||||
|
if (count($results) == 0) {
|
||||||
|
$db = null;
|
||||||
|
$req->res->code(400);
|
||||||
|
return "админ не найден";
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
$classId = $results[0]['adminClass'];
|
||||||
|
$day = $req->data['day'];
|
||||||
|
$tab = intval($req->data['tab']);
|
||||||
|
$newDataRaw = $req->data['newData'];
|
||||||
|
$newData = json_decode($newDataRaw, true);
|
||||||
|
|
||||||
|
// im too lazy to close db
|
||||||
|
|
||||||
|
switch ($tab) {
|
||||||
|
case 0: // changes
|
||||||
|
// first get rasp and compare
|
||||||
|
// if no chnages skip, else publish
|
||||||
|
|
||||||
|
$dayOfWeek = getDayOfWeek($day);
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM schedules WHERE classId = ? AND dayOfWeek = ?", [$classId, $dayOfWeek]);
|
||||||
|
$publish = true;
|
||||||
|
if (count($results) > 0) {
|
||||||
|
$schedule = json_decode(findClosestDateSort($results, $day)['content'], true);
|
||||||
|
if ($newData === $schedule) { // position sentensive
|
||||||
|
$publish = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($publish) {
|
||||||
|
// removing changes for today if they are exists
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM changes WHERE classId = ? AND forDay = ?", [$classId, $day]);
|
||||||
|
if (count($results) > 0) {
|
||||||
|
$changes = json_decode($results[0]['content'], true);
|
||||||
|
if ($newData === $changes) {
|
||||||
|
// already present
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
FastDBReq($db, "DELETE FROM changes WHERE forDay = ? AND classId = ?", [$day, $classId]); // SCARY 💀💀💀
|
||||||
|
}
|
||||||
|
// creating new
|
||||||
|
FastDBReq($db, 'INSERT INTO changes VALUES (?, ?, ?)', [$classId, $day, $newDataRaw]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case 1: // rasp
|
||||||
|
$dayOfWeek = getDayOfWeek($day);
|
||||||
|
// FIXME: im to lazy to find if closest rasp are the same
|
||||||
|
FastDBReq($db, 'DELETE FROM schedules WHERE classId=? AND fromDate=?', [$classId, $day]);
|
||||||
|
|
||||||
|
FastDBReq($db, 'INSERT INTO schedules VALUES (?,?,?,?)', [$classId, $day, $dayOfWeek, $newDataRaw]);
|
||||||
|
return true;
|
||||||
|
case 2: // rigns
|
||||||
|
//same
|
||||||
|
FastDBReq($db, 'DELETE FROM rings WHERE classId=? AND fromDate=?', [$classId, $day]);
|
||||||
|
FastDBReq($db, 'INSERT INTO rings VALUES (?,?,?)', [$classId, $day, $newDataRaw]);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return "tab not found dengi dengi";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$api->on('/editor_fullitems_del', "POST", function ($req) {
|
||||||
|
|
||||||
|
// SCARY!!!!!!
|
||||||
|
// LEVEL 10000000
|
||||||
|
// 💀💀💀💀💀
|
||||||
|
|
||||||
|
if (!$req->hasData(['tab', 'day', 'adminId'])) {
|
||||||
|
$req->res->code(400);
|
||||||
|
return "bad data";
|
||||||
|
}
|
||||||
|
$adminId = $req->data['adminId'];
|
||||||
|
$db = db();
|
||||||
|
$results = FastDBReq($db, "SELECT * FROM admins WHERE adminId=?", [$adminId]);
|
||||||
|
if (count($results) == 0) {
|
||||||
|
$db = null;
|
||||||
|
$req->res->code(400);
|
||||||
|
return "админ не найден";
|
||||||
|
# end
|
||||||
|
}
|
||||||
|
$classId = $results[0]['adminClass'];
|
||||||
|
$day = $req->data['day'];
|
||||||
|
$tab = intval($req->data['tab']);
|
||||||
|
|
||||||
|
switch ($tab) {
|
||||||
|
case 0:
|
||||||
|
FastDBReq($db, "DELETE FROM changes WHERE forDay = ? AND classId = ?", [$day, $classId]);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
FastDBReq($db, 'DELETE FROM schedules WHERE classId=? AND fromDate=?', [$classId, $day]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
FastDBReq($db, 'DELETE FROM rings WHERE classId=? AND fromDate=?', [$classId, $day]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "you saved your live because you did'n know what tabs are here";
|
||||||
|
}
|
||||||
|
$db = null;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
# dx4 architecture
|
||||||
|
|
||||||
|
<p align='right'>dengi</p>
|
||||||
|
|
||||||
|
# fundamental types
|
||||||
|
|
||||||
|
## classes
|
||||||
|
|
||||||
|
#### db table
|
||||||
|
|
||||||
|
| name | meaning |
|
||||||
|
| ----------------- | ------------------------------------------------------ |
|
||||||
|
| **classid** | **unique** class id <u>_(uppercase, min 3 max 10)_</u> |
|
||||||
|
| **userclassname** | use friendly name |
|
||||||
|
| **caching** | `0 \| 1` toggles caching |
|
||||||
|
|
||||||
|
#### example
|
||||||
|
|
||||||
|
| classid | userclassname | caching |
|
||||||
|
| ----------- | ------------- | ------- |
|
||||||
|
| `9BPLETNEV` | 9б | `1` |
|
||||||
|
|
||||||
|
## admins
|
||||||
|
|
||||||
|
#### db table
|
||||||
|
|
||||||
|
| name | meaning |
|
||||||
|
| -------------- | ---------------------------------- |
|
||||||
|
| **adminId** | unique admin id, **it's secret** |
|
||||||
|
| **adminName** | user friendly admin name |
|
||||||
|
| **adminClass** | `classid`, that admin belongs to |
|
||||||
|
| **adminPerms** | admin permisions, look table below |
|
||||||
|
|
||||||
|
#### permissions
|
||||||
|
|
||||||
|
| val | meaning |
|
||||||
|
| ---- | ------------------------------------------------ |
|
||||||
|
| `-1` | **unlimited, full access** |
|
||||||
|
| `0` | _**preserved for users**_ |
|
||||||
|
| `1` | allowed to make change for _changes in schedule_ |
|
||||||
|
| `2` | _bells and permament schedule_ |
|
||||||
|
| `3` | _change class profile, and notes_ |
|
||||||
|
| `4` | _create and manage admins_ |
|
||||||
|
|
||||||
|
#### > Requests
|
||||||
|
|
||||||
|
You can **request** a change, if your level is lower, also you can **accept** those changes if your admin level can do this
|
||||||
|
|
||||||
|
#### example
|
||||||
|
|
||||||
|
| adminId | adminName | adminClass | adminPerms |
|
||||||
|
| -------------- | -------------- | ----------- | ---------- |
|
||||||
|
| `ivanpletnev4` | _Ivan Pletnev_ | `9BPLETNEV` | `-1` |
|
||||||
|
|
||||||
|
## schedule _(permanent)_
|
||||||
|
|
||||||
|
#### db table
|
||||||
|
|
||||||
|
| name | meaning |
|
||||||
|
| ------------- | ----------------------------------------- |
|
||||||
|
| **classId** | class belongs to |
|
||||||
|
| **fromDate** | active from date (DD-MM-YY) |
|
||||||
|
| **dayOfWeek** | day of week, _num_ **(**`0` **- monday)** |
|
||||||
|
| **content** | json **list** content, look table below |
|
||||||
|
|
||||||
|
#### json content
|
||||||
|
|
||||||
|
| key | meaning |
|
||||||
|
| ----------- | --------------------------------------- |
|
||||||
|
| **num** | n of lesson in schedule, start with `1` |
|
||||||
|
| **subject** | lesson subject |
|
||||||
|
| **cabinet** | lesson cabinet |
|
||||||
|
|
||||||
|
#### example
|
||||||
|
|
||||||
|
| **classId** | **raspId** | **dayOfWeek** | **content** |
|
||||||
|
| ----------- | ---------- | ------------- | ------------------------------------------------------- |
|
||||||
|
| `9BPLETNEV` | `3` | `0` | `[{"num":1, "subject":'физека🤬', "cabinet", 209},...]` |
|
||||||
|
|
||||||
|
## changes in schedule _(zameni)_
|
||||||
|
|
||||||
|
#### db table
|
||||||
|
|
||||||
|
| name | meaning |
|
||||||
|
| ----------- | ------------------------------------------------------------ |
|
||||||
|
| **classId** | class belongs to |
|
||||||
|
| **forDay** | day date `DD-MM-YY` _(i hope there wouldn't be y3k problem)_ |
|
||||||
|
| **content** | json list content, look table below |
|
||||||
|
|
||||||
|
#### json list content
|
||||||
|
|
||||||
|
| key | meaning |
|
||||||
|
| ------------- | ---------------------------------------------------- |
|
||||||
|
| **num** | n of lesson in schedule, start with `1` |
|
||||||
|
| **subject** | lesson subject, or `$function`, **look table below** |
|
||||||
|
| **cabinet** | lesson cabinet, if unused type `0` |
|
||||||
|
| **t-begin** ? | lesson begin time, if empty same as before |
|
||||||
|
| **t-end** ? | lesson end time, if empty same as before |
|
||||||
|
|
||||||
|
#### changes functions
|
||||||
|
|
||||||
|
| function | meaning |
|
||||||
|
| --------------------- | ---------------------------------------------------------------- |
|
||||||
|
| **`$rm-bef`** | remove all lessons **before**, _including this_, eq. to old `-3` |
|
||||||
|
| **`$rm-aft`** | remove all lessons **after**, _including this_, eq. to old `-2` |
|
||||||
|
| **`$no-lessons`** | permanently sets to no lessons today |
|
||||||
|
| ~~**`$no-changes`**~~ | ~~says that there is no changes today _(when 100% sure)_~~ |
|
||||||
|
|
||||||
|
#### example
|
||||||
|
|
||||||
|
ko v toromu
|
||||||
|
|
||||||
|
| **classId** | **forDay** | **forRaspId** | **content** |
|
||||||
|
| ----------- | ---------- | ------------- | ----------------------------------------------------------- |
|
||||||
|
| `9BPLETNEV` | `20-10-25` | `0` | `[{"num":1, "subject":"`**`$rm-bef`**`", "cabinet":0},...]` |
|
||||||
|
|
||||||
|
## rings _(zvonki)_
|
||||||
|
|
||||||
|
| name | meaning |
|
||||||
|
| ------------ | --------------------------------------- |
|
||||||
|
| **classId** | class belongs to |
|
||||||
|
| **fromDate** | active from date (DD-MM-YY) |
|
||||||
|
| **content** | json **list** content, look table below |
|
||||||
|
|
||||||
|
#### json list content
|
||||||
|
|
||||||
|
| key | meaning |
|
||||||
|
| ----------- | ----------------- |
|
||||||
|
| **num** | n of lesson |
|
||||||
|
| **t-begin** | lesson begin time |
|
||||||
|
| **t-end** | lesson end time |
|
||||||
|
|
||||||
|
#### example
|
||||||
|
|
||||||
|
| **classId** | **fromDay** | **content** |
|
||||||
|
| ----------- | ----------- | ----------------------------------------------- |
|
||||||
|
| `9BPLETNEV` | `20-10-25` | `[{"num":1, "t-begin:"9:00", t-end:"9:40"}...]` |
|
||||||
|
|
||||||
|
# api
|
||||||
|
|
||||||
|
## `/req_schedule` **POST**
|
||||||
|
|
||||||
|
returns ready to show schedule
|
||||||
|
|
||||||
|
#### req
|
||||||
|
|
||||||
|
`classId, date`
|
||||||
|
|
||||||
|
#### res
|
||||||
|
|
||||||
|
`{"num":1, "subject":'физека🤬', "cabinet": 209, "t-begin":"9:00", "t-begin": "9:40"}`
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/** @param callable(_K_Api): void $apiFun */
|
||||||
|
function CreateApi(callable $apiFun)
|
||||||
|
{
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Allow-Headers: Content-Type");
|
||||||
|
|
||||||
|
$api = new _K_Api();
|
||||||
|
$apiFun($api);
|
||||||
|
$api->end();
|
||||||
|
}
|
||||||
|
class _K_Api
|
||||||
|
{
|
||||||
|
private $has_exec = false;
|
||||||
|
/** @param callable(_K_ApiRequest): string|array|int|float|bool $fun */
|
||||||
|
public function on(string $route, string $method, callable $fun)
|
||||||
|
{
|
||||||
|
$request_url = (count($_GET) > 0 ? array_keys($_GET)[0] : '');
|
||||||
|
$r = str_starts_with($route, '/') ? substr($route, 1) : $route;
|
||||||
|
if ($r != $request_url) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$this->has_exec = true;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] != $method) {
|
||||||
|
http_response_code(405);
|
||||||
|
die("ERROR: unsupported method ($method available)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$data = [];
|
||||||
|
if ($method == 'GET' && count($_GET) > 1) {
|
||||||
|
$data = array_slice(array_keys($_GET), 1);
|
||||||
|
} else if ($method == 'POST' && count($_POST) > 0) {
|
||||||
|
$data = $_POST;
|
||||||
|
}
|
||||||
|
$fun = $fun(new _K_ApiRequest($data));
|
||||||
|
if (is_string($fun) || is_numeric($fun)) {
|
||||||
|
if (json_validate($fun) && !is_numeric($fun)) {
|
||||||
|
Header('Content-Type: application/json');
|
||||||
|
}
|
||||||
|
echo $fun;
|
||||||
|
} else if (is_array($fun) || is_bool($fun)) {
|
||||||
|
Header('Content-Type: application/json');
|
||||||
|
echo json_encode($fun);
|
||||||
|
} else {
|
||||||
|
die("ERROR: unknown return type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function end()
|
||||||
|
{
|
||||||
|
if (!$this->has_exec) {
|
||||||
|
http_response_code(404);
|
||||||
|
echo '404';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _K_ApiRequest
|
||||||
|
{
|
||||||
|
public array $data;
|
||||||
|
public _K_ApiResponse $res;
|
||||||
|
|
||||||
|
public function __construct(array $data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
$this->res = new _K_ApiResponse($this);
|
||||||
|
}
|
||||||
|
public function hasData(array $dataArr)
|
||||||
|
{
|
||||||
|
foreach ($dataArr as $i) {
|
||||||
|
if (!isset($this->data[$i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _K_ApiResponse
|
||||||
|
{
|
||||||
|
public function __construct($req) {}
|
||||||
|
public function code(int $httpCode)
|
||||||
|
{
|
||||||
|
http_response_code($httpCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<?php phpinfo();
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import js from "@eslint/js";
|
||||||
|
import globals from "globals";
|
||||||
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
|
import reactRefresh from "eslint-plugin-react-refresh";
|
||||||
|
import { defineConfig, globalIgnores } from "eslint/config";
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
globalIgnores(["dist"]),
|
||||||
|
{
|
||||||
|
files: ["**/*.{js,jsx}"],
|
||||||
|
extends: [
|
||||||
|
js.configs.recommended,
|
||||||
|
reactHooks.configs["recommended-latest"],
|
||||||
|
reactRefresh.configs.vite,
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
globals: globals.browser,
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: "latest",
|
||||||
|
ecmaFeatures: { jsx: true },
|
||||||
|
sourceType: "module",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"no-unused-vars": ["error", { varsIgnorePattern: "^[A-Z_]|^motion$" }],
|
||||||
|
"react-hooks/exhaustive-deps": ["off"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# main ideas
|
||||||
|
|
||||||
|
# editor ideas
|
||||||
|
|
||||||
|
- when typing `n-n` (example `1-5`), automaticly copies everything
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<!-- iOS meta tags -->
|
||||||
|
<meta name="mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="dx4" />
|
||||||
|
|
||||||
|
<!-- iOS icons -->
|
||||||
|
<link rel="apple-touch-icon" href="/icons/ios/180.png" />
|
||||||
|
<link rel="apple-touch-icon" sizes="120x120" href="/icons/ios/120.png" />
|
||||||
|
<link rel="apple-touch-icon" sizes="152x152" href="/icons/ios/152.png" />
|
||||||
|
<link rel="apple-touch-icon" sizes="167x167" href="/icons/ios/167.png" />
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="/icons/ios/180.png" />
|
||||||
|
|
||||||
|
<!-- Windows tiles -->
|
||||||
|
<meta name="msapplication-TileColor" content="#000" />
|
||||||
|
<meta
|
||||||
|
name="msapplication-TileImage"
|
||||||
|
content="/icons/windows11/Square150x150Logo.scale-100.png"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<title>dx 4</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root">
|
||||||
|
<style>
|
||||||
|
div[data-ktkz-loading] {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vw;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #060606;
|
||||||
|
gap: 5px;
|
||||||
|
--animate-ease: ease-in-out;
|
||||||
|
}
|
||||||
|
div[data-ktkz-loading] .cont {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
animation: ktkz-preloader-show 2s linear;
|
||||||
|
}
|
||||||
|
div[data-ktkz-loading] .spinner {
|
||||||
|
--size: 3rem;
|
||||||
|
width: var(--size);
|
||||||
|
margin-top: 5px;
|
||||||
|
height: var(--size);
|
||||||
|
border: 4px solid rgba(255, 255, 255, 0.12);
|
||||||
|
border-top-color: #ffffff;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: ktkz-preloader-spin 1s var(--animate-ease) infinite;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
div[data-ktkz-loading] img {
|
||||||
|
animation: ktkz-preloader-pulse 3s var(--animate-ease) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ktkz-preloader-spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes ktkz-preloader-pulse {
|
||||||
|
from,
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes ktkz-preloader-show {
|
||||||
|
from,
|
||||||
|
50% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div data-ktkz-loading="">
|
||||||
|
<div class="cont">
|
||||||
|
<img src="./src/assets/logo.svg" width="150" alt="" />
|
||||||
|
<div class="spinner" aria-hidden="true"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"name": "dx4",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@dnd-kit/core": "^6.3.1",
|
||||||
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
|
"@fontsource/jost": "^5.2.6",
|
||||||
|
"@tailwindcss/vite": "^4.1.12",
|
||||||
|
"jotai": "^2.13.1",
|
||||||
|
"js-md5": "^0.8.3",
|
||||||
|
"motion": "^12.23.12",
|
||||||
|
"react": "^19.1.1",
|
||||||
|
"react-dom": "^19.1.1",
|
||||||
|
"react-icons": "^5.5.0",
|
||||||
|
"tailwindcss": "^4.1.12"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^9.33.0",
|
||||||
|
"@types/react": "^19.1.10",
|
||||||
|
"@types/react-dom": "^19.1.7",
|
||||||
|
"@vitejs/plugin-react": "^5.0.0",
|
||||||
|
"@vitejs/plugin-react-swc": "^4.2.1",
|
||||||
|
"eslint": "^9.33.0",
|
||||||
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
|
"globals": "^16.3.0",
|
||||||
|
"vite": "^7.1.2",
|
||||||
|
"vite-plugin-pwa": "^1.1.0",
|
||||||
|
"vite-plugin-ssr-ssg": "^1.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<svg width="392" height="392" viewBox="0 0 392 392" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_2037_2)">
|
||||||
|
<rect width="392" height="392" rx="135" fill="url(#paint0_linear_2037_2)"/>
|
||||||
|
<mask id="mask0_2037_2" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="37" y="56" width="325" height="281">
|
||||||
|
<path d="M177.595 319.25L269.333 241.083L177.595 160.853V319.25Z" fill="white"/>
|
||||||
|
<path d="M269.333 241.083L177.595 319.25M269.333 241.083L177.595 160.853M269.333 241.083L350.292 160.853M269.333 241.083L350.292 324.833M177.595 319.25V160.853M177.595 319.25H52.3926C49.8512 319.25 48.4611 316.288 50.0851 314.333L177.595 160.853M177.595 160.853V68" stroke="white" stroke-width="23" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</mask>
|
||||||
|
<g mask="url(#mask0_2037_2)">
|
||||||
|
<rect width="350" height="287" transform="matrix(1 0 0 -1 24 341)" fill="url(#paint1_linear_2037_2)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_2037_2" x1="65.3333" y1="25.5394" x2="365.867" y2="380.121" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop/>
|
||||||
|
<stop offset="1" stop-color="#464646"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_2037_2" x1="-73.3091" y1="366.596" x2="487.371" y2="-46.6548" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white"/>
|
||||||
|
<stop offset="0.528846" stop-color="#9595A1"/>
|
||||||
|
<stop offset="1" stop-color="#545568"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="clip0_2037_2">
|
||||||
|
<rect width="392" height="392" rx="4" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,452 @@
|
|||||||
|
{
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "windows11/SmallTile.scale-100.png",
|
||||||
|
"sizes": "71x71"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SmallTile.scale-125.png",
|
||||||
|
"sizes": "89x89"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SmallTile.scale-150.png",
|
||||||
|
"sizes": "107x107"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SmallTile.scale-200.png",
|
||||||
|
"sizes": "142x142"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SmallTile.scale-400.png",
|
||||||
|
"sizes": "284x284"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square150x150Logo.scale-100.png",
|
||||||
|
"sizes": "150x150"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square150x150Logo.scale-125.png",
|
||||||
|
"sizes": "188x188"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square150x150Logo.scale-150.png",
|
||||||
|
"sizes": "225x225"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square150x150Logo.scale-200.png",
|
||||||
|
"sizes": "300x300"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square150x150Logo.scale-400.png",
|
||||||
|
"sizes": "600x600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Wide310x150Logo.scale-100.png",
|
||||||
|
"sizes": "310x150"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Wide310x150Logo.scale-125.png",
|
||||||
|
"sizes": "388x188"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Wide310x150Logo.scale-150.png",
|
||||||
|
"sizes": "465x225"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Wide310x150Logo.scale-200.png",
|
||||||
|
"sizes": "620x300"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Wide310x150Logo.scale-400.png",
|
||||||
|
"sizes": "1240x600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/LargeTile.scale-100.png",
|
||||||
|
"sizes": "310x310"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/LargeTile.scale-125.png",
|
||||||
|
"sizes": "388x388"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/LargeTile.scale-150.png",
|
||||||
|
"sizes": "465x465"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/LargeTile.scale-200.png",
|
||||||
|
"sizes": "620x620"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/LargeTile.scale-400.png",
|
||||||
|
"sizes": "1240x1240"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.scale-100.png",
|
||||||
|
"sizes": "44x44"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.scale-125.png",
|
||||||
|
"sizes": "55x55"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.scale-150.png",
|
||||||
|
"sizes": "66x66"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.scale-200.png",
|
||||||
|
"sizes": "88x88"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.scale-400.png",
|
||||||
|
"sizes": "176x176"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/StoreLogo.scale-100.png",
|
||||||
|
"sizes": "50x50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/StoreLogo.scale-125.png",
|
||||||
|
"sizes": "63x63"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/StoreLogo.scale-150.png",
|
||||||
|
"sizes": "75x75"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/StoreLogo.scale-200.png",
|
||||||
|
"sizes": "100x100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/StoreLogo.scale-400.png",
|
||||||
|
"sizes": "200x200"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SplashScreen.scale-100.png",
|
||||||
|
"sizes": "620x300"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SplashScreen.scale-125.png",
|
||||||
|
"sizes": "775x375"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SplashScreen.scale-150.png",
|
||||||
|
"sizes": "930x450"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SplashScreen.scale-200.png",
|
||||||
|
"sizes": "1240x600"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/SplashScreen.scale-400.png",
|
||||||
|
"sizes": "2480x1200"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-16.png",
|
||||||
|
"sizes": "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-20.png",
|
||||||
|
"sizes": "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-24.png",
|
||||||
|
"sizes": "24x24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-30.png",
|
||||||
|
"sizes": "30x30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-32.png",
|
||||||
|
"sizes": "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-36.png",
|
||||||
|
"sizes": "36x36"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-40.png",
|
||||||
|
"sizes": "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-44.png",
|
||||||
|
"sizes": "44x44"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-48.png",
|
||||||
|
"sizes": "48x48"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-60.png",
|
||||||
|
"sizes": "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-64.png",
|
||||||
|
"sizes": "64x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-72.png",
|
||||||
|
"sizes": "72x72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-80.png",
|
||||||
|
"sizes": "80x80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-96.png",
|
||||||
|
"sizes": "96x96"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.targetsize-256.png",
|
||||||
|
"sizes": "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-16.png",
|
||||||
|
"sizes": "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-20.png",
|
||||||
|
"sizes": "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-24.png",
|
||||||
|
"sizes": "24x24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-30.png",
|
||||||
|
"sizes": "30x30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-32.png",
|
||||||
|
"sizes": "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-36.png",
|
||||||
|
"sizes": "36x36"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-40.png",
|
||||||
|
"sizes": "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-44.png",
|
||||||
|
"sizes": "44x44"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-48.png",
|
||||||
|
"sizes": "48x48"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-60.png",
|
||||||
|
"sizes": "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-64.png",
|
||||||
|
"sizes": "64x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-72.png",
|
||||||
|
"sizes": "72x72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-80.png",
|
||||||
|
"sizes": "80x80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-96.png",
|
||||||
|
"sizes": "96x96"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-unplated_targetsize-256.png",
|
||||||
|
"sizes": "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-16.png",
|
||||||
|
"sizes": "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-20.png",
|
||||||
|
"sizes": "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-24.png",
|
||||||
|
"sizes": "24x24"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-30.png",
|
||||||
|
"sizes": "30x30"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-32.png",
|
||||||
|
"sizes": "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-36.png",
|
||||||
|
"sizes": "36x36"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-40.png",
|
||||||
|
"sizes": "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-44.png",
|
||||||
|
"sizes": "44x44"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-48.png",
|
||||||
|
"sizes": "48x48"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-60.png",
|
||||||
|
"sizes": "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-64.png",
|
||||||
|
"sizes": "64x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-72.png",
|
||||||
|
"sizes": "72x72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-80.png",
|
||||||
|
"sizes": "80x80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-96.png",
|
||||||
|
"sizes": "96x96"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "windows11/Square44x44Logo.altform-lightunplated_targetsize-256.png",
|
||||||
|
"sizes": "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android/android-launchericon-512-512.png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android/android-launchericon-192-192.png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android/android-launchericon-144-144.png",
|
||||||
|
"sizes": "144x144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android/android-launchericon-96-96.png",
|
||||||
|
"sizes": "96x96"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android/android-launchericon-72-72.png",
|
||||||
|
"sizes": "72x72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "android/android-launchericon-48-48.png",
|
||||||
|
"sizes": "48x48"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/16.png",
|
||||||
|
"sizes": "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/20.png",
|
||||||
|
"sizes": "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/29.png",
|
||||||
|
"sizes": "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/32.png",
|
||||||
|
"sizes": "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/40.png",
|
||||||
|
"sizes": "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/50.png",
|
||||||
|
"sizes": "50x50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/57.png",
|
||||||
|
"sizes": "57x57"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/58.png",
|
||||||
|
"sizes": "58x58"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/60.png",
|
||||||
|
"sizes": "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/64.png",
|
||||||
|
"sizes": "64x64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/72.png",
|
||||||
|
"sizes": "72x72"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/76.png",
|
||||||
|
"sizes": "76x76"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/80.png",
|
||||||
|
"sizes": "80x80"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/87.png",
|
||||||
|
"sizes": "87x87"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/100.png",
|
||||||
|
"sizes": "100x100"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/114.png",
|
||||||
|
"sizes": "114x114"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/120.png",
|
||||||
|
"sizes": "120x120"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/128.png",
|
||||||
|
"sizes": "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/144.png",
|
||||||
|
"sizes": "144x144"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/152.png",
|
||||||
|
"sizes": "152x152"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/167.png",
|
||||||
|
"sizes": "167x167"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/180.png",
|
||||||
|
"sizes": "180x180"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/192.png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/256.png",
|
||||||
|
"sizes": "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/512.png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "ios/1024.png",
|
||||||
|
"sizes": "1024x1024"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 580 B |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 720 B |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 641 B |
|
After Width: | Height: | Size: 795 B |
|
After Width: | Height: | Size: 1021 B |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 641 B |
|
After Width: | Height: | Size: 795 B |
|
After Width: | Height: | Size: 1021 B |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.6 KiB |