bug fixes

This commit is contained in:
unknown
2025-11-29 20:53:09 +03:00
parent 641a12bb0f
commit 61674fbc6f
6 changed files with 272 additions and 225 deletions
+3
View File
@@ -15,6 +15,7 @@
"react-dom": "^19.1.1",
"react-icons": "^5.5.0",
"tailwindcss": "^4.1.12",
"use-debounce": "^10.0.6",
},
"devDependencies": {
"@eslint/js": "^9.33.0",
@@ -1135,6 +1136,8 @@
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"use-debounce": ["use-debounce@10.0.6", "", { "peerDependencies": { "react": "*" } }, "sha512-C5OtPyhAZgVoteO9heXMTdW7v/IbFI+8bSVKYCJrSmiWWCLsbUxiBSp4t9v0hNBTGY97bT72ydDIDyGSFWfwXg=="],
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
+17
View File
@@ -64,6 +64,15 @@
div[data-ktkz-loading] img {
animation: ktkz-preloader-pulse 3s var(--animate-ease) infinite;
}
div[data-ktkz-loading] p {
font-family: "Segoe UI", sans-serif;
color: #eef;
opacity: 0;
animation: ktkz-preloader-show 2s linear 2s forwards;
}
div[data-ktkz-loading] p a {
color: #aaf;
}
@keyframes ktkz-preloader-spin {
to {
@@ -74,9 +83,11 @@
from,
to {
opacity: 1;
transform: scale(100%);
}
50% {
opacity: 0.3;
transform: scale(98%);
}
}
@keyframes ktkz-preloader-show {
@@ -93,6 +104,12 @@
<div class="cont">
<img src="./src/assets/logo.svg" width="150" alt="" />
<div class="spinner" aria-hidden="true"></div>
<p>
если не работает попробуйте
<a href="#" onclick="event.preventDefault();location.reload()"
>перезагрузить</a
>
</p>
</div>
</div>
</div>
+2 -1
View File
@@ -20,7 +20,8 @@
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-icons": "^5.5.0",
"tailwindcss": "^4.1.12"
"tailwindcss": "^4.1.12",
"use-debounce": "^10.0.6"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
+263 -239
View File
@@ -19,7 +19,7 @@ import {
classUserFRequest,
RaspGet,
} from "../trash/req_mgr";
import { AnimatePresence, motion } from "motion/react";
import { AnimatePresence, LayoutGroup, motion } from "motion/react";
import { apiFormatDate, isTimeBeforeNow } from "../trash/dengi";
import { useAtom } from "jotai";
@@ -90,7 +90,6 @@ export function DX4App({
class: false,
});
const [classLinkCopied, setClassLinkCopied] = useState(false);
const lessonsEndedTriggered = useRef(false);
//TODO: Auto change day v2
@@ -151,6 +150,37 @@ export function DX4App({
})();
}, [classId, adminId]);
const handleKeyPress = (event) => {
switch (event.key) {
case "a":
case "ArrowLeft":
setSelectedDate((prevDate) => {
const newDate = new Date(prevDate);
newDate.setDate(newDate.getDate() - 1);
return newDate;
});
break;
case "d":
case "ArrowRight":
setSelectedDate((prevDate) => {
const newDate = new Date(prevDate);
newDate.setDate(newDate.getDate() + 1);
return newDate;
});
break;
default:
break;
}
};
useEffect(() => {
window.addEventListener("keydown", handleKeyPress);
return () => {
window.removeEventListener("keydown", handleKeyPress);
};
}, []);
if (classId === "") {
setsetRoute(setRoute, "/");
}
@@ -167,7 +197,6 @@ export function DX4App({
"flex items-center w-full justify-between px-5" +
ifstyle(openUserSettings, " pt-5")
}
layout="position"
>
<motion.img
src={Logo}
@@ -214,6 +243,235 @@ export function DX4App({
/>
</motion.span>
<AnimatePresence mode="popLayout">
<UserSettings
{...{
openUserSettings,
userFrNames,
setUserId,
setsetRoute,
setRoute,
adminId,
classId,
pickmeMode,
}}
/>
</AnimatePresence>
</motion.div>
</motion.div>
<motion.div
layout="position"
className="flex flex-col gap-5 w-full not-md:px-4"
>
{adminId != "" && (
<motion.div className="flex w-full justify-end">
<a
// onClick={() => {
// setsetRoute(setRoute, `/editor/${apiFormatDate(selectedDate)}`);
// }}
href={`#/editor/${apiFormatDate(selectedDate)}`}
className="flex items-center justify-center border p-1 gap-2 px-2 lg:hover:border-white cursor-pointer rounded-xl transition-colors border-zinc-700 text-zinc-400 lg:hover:text-white"
>
<BiPencil /> открыть в редакторе
</a>
</motion.div>
)}
<DatePicker
date={selectedDate}
setDate={setSelectedDate}
indicator={typeof rasp[2] == "number" && [1, 2].includes(rasp[2])}
/>
<div className="relative">
<LayoutGroup>
<RaspView {...{ rasp, pickmeMode, selectedDate }} />
</LayoutGroup>
{!rasp[0] && (
<motion.div
className="w-full flex justify-center"
initial="hid"
animate="show"
variants={{
show: { opacity: 1, scale: 1 },
hid: { opacity: 0, scale: 0 },
}}
>
<LoadingSpinner size={25} />
</motion.div>
)}
</div>
</motion.div>
</motion.div>
</motion.div>
<CoolMainBg {...{ pickmeMode }} />
</>
);
}
const CoolMainBg = React.memo(({ pickmeMode }) => {
return (
<div
className={`fixed top-0 left-0 w-full h-full -z-5 overflow-hidden bg-gradient-to-br to-black to-50% bg-fixed
${pickmeMode ? "from-pink-400/10" : "from-white/2"}`}
/>
);
});
export const RaspView = React.memo(({ rasp, pickmeMode, selectedDate }) => {
return (
<AnimatePresence mode="popLayout">
{rasp[0] && typeof rasp[1] == "object" && (
<motion.table
//layoutId="schedule_table"
//layout="position"
key={selectedDate}
className={
"w-full border-collapse border-spacing-x-0 border-spacing-y-[10px] bg-gradient-to-br backdrop-blur-xl mb-10 " +
(pickmeMode ? "from-pink-400/30" : "from-zinc-800/40") +
" to-transparent rounded-2xl selectable"
}
variants={{
hid: { opacity: 0 },
show: { opacity: 1 },
}}
initial="hid"
animate="show"
exit="hid"
>
<thead className="">
<tr className=" *:text-center text-zinc-400 *:py-2 border-b *:my-5 *:min-w-15 *:lg:hover:text-zinc-200 *:transition-colors *:font-light">
<th
className="max-w-10"
//layout="position"
//layoutId="table-num-h"
>
n урока
</th>
<th
//layout="position"
//layoutId="table-subj-h"
>
предмет
</th>
<th
//layout="position"
//layoutId="table-cab-h"
>
каб
</th>
<th
//layout="position"
//layoutId="table-t-h"
>
<div className="flex items-center justify-center gap-2">
{rasp[2] == 2 && (
<span className="w-2 h-2 animate-pulse rounded-full bg-zinc-300 block" />
)}
время
</div>
</th>
</tr>
</thead>
<tbody className="*:*:text-center *:*:py-2 *:not-last:border-b *:not-last:border-zinc-800 text-white">
{rasp[1].map((d, i) => (
<tr
//layout="position"
key={`table-header-${i}`}
className="transition-colors *:transition-colors lg:hover:bg-zinc-300/15"
//rasp-key={"rasp_key_" + i + Array(d).join()}
>
<td
//layout="position"
//layoutId={`table-num-${i}`}
>
{d["num"]}
</td>
<td
//layout="position"
//layoutId={`table-subj-${i}`}
>
{d.subject
.toString()
.split("\n")
.map((line, i, array) => (
<React.Fragment key={i}>
{line}
{i < array.length - 1 && <br />}
</React.Fragment>
)) || d.subject}
</td>
<td
//layout="position"
//layoutId={`table-cab-${i}`}
>
{d.cabinet
.toString()
.split("\n")
.map((line, i, array) => (
<React.Fragment key={i}>
{line}
{i < array.length - 1 && <br />}
</React.Fragment>
)) || d.cabinet}
</td>
<td>
<div
//layout="position"
//layoutId={`table-time-${i}`}
className="flex items-center justify-center min-h-9"
>
<div className="flex gap-0.5 flex-col *:block w-[70%] *:font-light">
<span className="text-left">
{d["t-begin"]}&nbsp;&nbsp;-
</span>
<span className="text-right">{d["t-end"]}</span>
</div>
</div>
</td>
</tr>
))}
</tbody>
</motion.table>
)}
{typeof rasp[1] == "number" && rasp[1] === -322 && (
<motion.div
className="w-full flex justify-center"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
<span className="text-2xl font-bold">нет уроков</span>
</motion.div>
)}
{typeof rasp[1] == "string" && rasp[1].startsWith("ошибка") && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="w-full flex justify-center"
>
<span className="text-xl text-center text-transparent bg-clip-text bg-gradient-to-r from-red-300 to-red-500">
{rasp[1]}
</span>
</motion.div>
)}
</AnimatePresence>
);
});
const UserSettings = React.memo(
({
openUserSettings,
userFrNames,
setUserId,
setsetRoute,
setRoute,
adminId,
classId,
pickmeMode,
}) => {
const [classLinkCopied, setClassLinkCopied] = useState(false);
return (
<>
{openUserSettings && (
<motion.div
className="flex flex-col bg-grain gap-2 bg-zinc-700/20 p-2 rounded-2xl"
@@ -260,10 +518,7 @@ export function DX4App({
classLinkCopied ? "скопированно" : "коп. ссылку",
() => {
copyToClipboard(
location.href.substring(
0,
location.href.search("#")
) +
location.href.substring(0, location.href.search("#")) +
"#//" +
classId
).then((a) => {
@@ -297,238 +552,7 @@ export function DX4App({
)}
</motion.div>
)}
</AnimatePresence>
</motion.div>
</motion.div>
{adminId != "" && (
<motion.div
layout="position"
className="flex w-full justify-end px-5"
>
<a
// onClick={() => {
// setsetRoute(setRoute, `/editor/${apiFormatDate(selectedDate)}`);
// }}
href={`#/editor/${apiFormatDate(selectedDate)}`}
className="flex items-center justify-center border p-1 gap-2 px-2 lg:hover:border-white cursor-pointer rounded-xl transition-colors border-zinc-700 text-zinc-400 lg:hover:text-white"
>
<BiPencil /> открыть в редакторе
</a>
</motion.div>
)}
<motion.div
layout="position"
className="flex flex-col gap-5 w-full not-md:px-4"
>
<DatePicker
date={selectedDate}
setDate={setSelectedDate}
indicator={typeof rasp[2] == "number" && [1, 2].includes(rasp[2])}
/>
<RaspView {...{ rasp, pickmeMode, selectedDate }} />
<AnimatePresence mode="popLayout">
{!rasp[0] && (
<motion.div
className="w-full flex justify-center"
initial="hid"
animate="show"
exit="hid"
variants={{
show: { opacity: 1, scale: 1 },
hid: { opacity: 0, scale: 0 },
}}
>
<LoadingSpinner size={25} />
</motion.div>
)}
</AnimatePresence>
</motion.div>
</motion.div>
{/* <CoolMouseBg /> */}
</motion.div>
<CoolMainBg {...{ pickmeMode }} />
</>
);
}
function CoolMainBg({ pickmeMode }) {
return (
<div
className={`fixed top-0 left-0 w-full h-full -z-5 overflow-hidden bg-gradient-to-br to-black to-50% bg-fixed
${pickmeMode ? "from-pink-400/10" : "from-white/2"}`}
/>
);
}
export function RaspView({ rasp, pickmeMode, selectedDate }) {
const [tableColHover, setTableColHover] = useState(-1);
return (
<AnimatePresence mode="popLayout">
{rasp[0] && typeof rasp[1] == "object" && (
<motion.table
//layoutId="schedule_table"
//layout="position"
key={selectedDate}
className={
"w-full border-collapse border-spacing-x-0 border-spacing-y-[10px] bg-gradient-to-br backdrop-blur-xl mb-10 " +
(pickmeMode ? "from-pink-400/30" : "from-zinc-800/40") +
" to-transparent rounded-2xl selectable"
}
variants={{
hid: { opacity: 0 },
show: { opacity: 1 },
}}
initial="hid"
animate="show"
exit="hid"
>
<thead className="">
<tr className=" *:text-center text-zinc-400 *:py-2 border-b *:my-5 *:min-w-15 *:lg:hover:text-zinc-200 *:transition-colors *:font-light">
<th
className="max-w-10"
//layout="position"
//layoutId="table-num-h"
onMouseEnter={() => {
setTableColHover(0);
}}
onMouseLeave={() => {
setTableColHover(-1);
}}
>
n урока
</th>
<th
//layout="position"
//layoutId="table-subj-h"
onMouseEnter={() => {
setTableColHover(1);
}}
onMouseLeave={() => {
setTableColHover(-1);
}}
>
предмет
</th>
<th
//layout="position"
//layoutId="table-cab-h"
onMouseEnter={() => {
setTableColHover(2);
}}
onMouseLeave={() => {
setTableColHover(-1);
}}
>
каб
</th>
<th
//layout="position"
//layoutId="table-t-h"
onMouseEnter={() => {
setTableColHover(3);
}}
onMouseLeave={() => {
setTableColHover(-1);
}}
>
<div className="flex items-center justify-center gap-2">
{rasp[2] == 2 && (
<span className="w-2 h-2 animate-pulse rounded-full bg-zinc-300 block" />
)}
время
</div>
</th>
</tr>
</thead>
<tbody className="*:*:text-center *:*:py-2 *:not-last:border-b *:not-last:border-zinc-800 text-white">
{rasp[1].map((d, i) => (
<tr
//layout="position"
key={`table-header-${i}`}
className="transition-colors *:transition-colors lg:hover:bg-zinc-300/15"
//rasp-key={"rasp_key_" + i + Array(d).join()}
>
<td
className={
(tableColHover == 0 ? "lg:bg-zinc-300/15" : "") +
" font-bold"
}
//layout="position"
//layoutId={`table-num-${i}`}
>
{d["num"]}
</td>
<td
className={tableColHover == 1 ? "lg:bg-zinc-300/15" : ""}
//layout="position"
//layoutId={`table-subj-${i}`}
>
{d.subject
.toString()
.split("\n")
.map((line, i, array) => (
<React.Fragment key={i}>
{line}
{i < array.length - 1 && <br />}
</React.Fragment>
)) || d.subject}
</td>
<td
//layout="position"
//layoutId={`table-cab-${i}`}
className={tableColHover == 2 ? "lg:bg-zinc-300/15" : ""}
>
{d.cabinet
.toString()
.split("\n")
.map((line, i, array) => (
<React.Fragment key={i}>
{line}
{i < array.length - 1 && <br />}
</React.Fragment>
)) || d.cabinet}
</td>
<td className={tableColHover == 3 ? "lg:bg-zinc-300/15" : ""}>
<div
//layout="position"
//layoutId={`table-time-${i}`}
className="flex items-center justify-center min-h-9"
>
<div className="flex gap-0.5 flex-col *:block w-[70%] *:font-light">
<span className="text-left">
{d["t-begin"]}&nbsp;&nbsp;-
</span>
<span className="text-right">{d["t-end"]}</span>
</div>
</div>
</td>
</tr>
))}
</tbody>
</motion.table>
)}
{typeof rasp[1] == "number" && rasp[1] === -322 && (
<motion.div
className="w-full flex justify-center"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, x: 10 }}
>
<span className="text-2xl font-bold">нет уроков</span>
</motion.div>
)}
{typeof rasp[1] == "string" && rasp[1].startsWith("ошибка") && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, x: 10 }}
className="w-full flex justify-center"
>
<span className="text-xl text-center text-transparent bg-clip-text bg-gradient-to-r from-red-300 to-red-500">
{rasp[1]}
</span>
</motion.div>
)}
</AnimatePresence>
);
}
);
+7 -5
View File
@@ -1,7 +1,7 @@
import { useEffect, useState } from "react";
import React, { useEffect, useState } from "react";
import { BiCheck, BiLeftArrowAlt, BiRightArrowAlt, BiX } from "react-icons/bi";
import { formatDate, getDateTags } from "./dengi.js";
import { AnimatePresence, motion } from "motion/react";
import { AnimatePresence, motion, LayoutGroup } from "motion/react";
export function Switch({
checked,
@@ -105,11 +105,12 @@ function DatePickerButton({ next = false, date, setDate }) {
);
}
export function DatePicker(props) {
export const DatePicker = React.memo((props) => {
const dateTag = getDateTags(props.date);
return (
<div className="flex items-center justify-between px-2 py-1 w-full bg-grain border-zinc-800/40 border rounded-2xl">
<LayoutGroup>
<div className="flex items-center justify-between px-2 py-1 w-full bg-grain border-zinc-800/40 border rounded-2xl relative">
<DatePickerButton date={props.date} setDate={props.setDate} />
<AnimatePresence mode="popLayout">
<motion.span
@@ -166,8 +167,9 @@ export function DatePicker(props) {
</AnimatePresence>
<DatePickerButton next date={props.date} setDate={props.setDate} />
</div>
</LayoutGroup>
);
}
});
export function DengiButton({
onClick,
+4 -4
View File
@@ -5,17 +5,17 @@ import { VitePWA } from "vite-plugin-pwa";
// https://vite.dev/config/
export default defineConfig({
base:"/dx4/",
base: "/dx4/",
plugins: [
react(),
tailwindcss(),
VitePWA({
registerType: "autoUpdate",
manifest: {
name: "dnevnik-x 4",
name: "dx 4",
short_name: "dx4",
description: "",
theme_color: "#000",
description: "dnevnik-x app",
theme_color: "#eee",
background_color: "#000",
display: "standalone",
scope: "/dx4/",