bug fixes
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"tailwindcss": "^4.1.12",
|
"tailwindcss": "^4.1.12",
|
||||||
|
"use-debounce": "^10.0.6",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
@@ -1135,6 +1136,8 @@
|
|||||||
|
|
||||||
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
"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=="],
|
"utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="],
|
||||||
|
|
||||||
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|||||||
+17
@@ -64,6 +64,15 @@
|
|||||||
div[data-ktkz-loading] img {
|
div[data-ktkz-loading] img {
|
||||||
animation: ktkz-preloader-pulse 3s var(--animate-ease) infinite;
|
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 {
|
@keyframes ktkz-preloader-spin {
|
||||||
to {
|
to {
|
||||||
@@ -74,9 +83,11 @@
|
|||||||
from,
|
from,
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
transform: scale(100%);
|
||||||
}
|
}
|
||||||
50% {
|
50% {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
|
transform: scale(98%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@keyframes ktkz-preloader-show {
|
@keyframes ktkz-preloader-show {
|
||||||
@@ -93,6 +104,12 @@
|
|||||||
<div class="cont">
|
<div class="cont">
|
||||||
<img src="./src/assets/logo.svg" width="150" alt="" />
|
<img src="./src/assets/logo.svg" width="150" alt="" />
|
||||||
<div class="spinner" aria-hidden="true"></div>
|
<div class="spinner" aria-hidden="true"></div>
|
||||||
|
<p>
|
||||||
|
если не работает попробуйте
|
||||||
|
<a href="#" onclick="event.preventDefault();location.reload()"
|
||||||
|
>перезагрузить</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+2
-1
@@ -20,7 +20,8 @@
|
|||||||
"react": "^19.1.1",
|
"react": "^19.1.1",
|
||||||
"react-dom": "^19.1.1",
|
"react-dom": "^19.1.1",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"tailwindcss": "^4.1.12"
|
"tailwindcss": "^4.1.12",
|
||||||
|
"use-debounce": "^10.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.33.0",
|
"@eslint/js": "^9.33.0",
|
||||||
|
|||||||
+186
-162
@@ -19,7 +19,7 @@ import {
|
|||||||
classUserFRequest,
|
classUserFRequest,
|
||||||
RaspGet,
|
RaspGet,
|
||||||
} from "../trash/req_mgr";
|
} from "../trash/req_mgr";
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, LayoutGroup, motion } from "motion/react";
|
||||||
|
|
||||||
import { apiFormatDate, isTimeBeforeNow } from "../trash/dengi";
|
import { apiFormatDate, isTimeBeforeNow } from "../trash/dengi";
|
||||||
import { useAtom } from "jotai";
|
import { useAtom } from "jotai";
|
||||||
@@ -90,7 +90,6 @@ export function DX4App({
|
|||||||
class: false,
|
class: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [classLinkCopied, setClassLinkCopied] = useState(false);
|
|
||||||
const lessonsEndedTriggered = useRef(false);
|
const lessonsEndedTriggered = useRef(false);
|
||||||
|
|
||||||
//TODO: Auto change day v2
|
//TODO: Auto change day v2
|
||||||
@@ -151,6 +150,37 @@ export function DX4App({
|
|||||||
})();
|
})();
|
||||||
}, [classId, adminId]);
|
}, [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 === "") {
|
if (classId === "") {
|
||||||
setsetRoute(setRoute, "/");
|
setsetRoute(setRoute, "/");
|
||||||
}
|
}
|
||||||
@@ -167,7 +197,6 @@ export function DX4App({
|
|||||||
"flex items-center w-full justify-between px-5" +
|
"flex items-center w-full justify-between px-5" +
|
||||||
ifstyle(openUserSettings, " pt-5")
|
ifstyle(openUserSettings, " pt-5")
|
||||||
}
|
}
|
||||||
layout="position"
|
|
||||||
>
|
>
|
||||||
<motion.img
|
<motion.img
|
||||||
src={Logo}
|
src={Logo}
|
||||||
@@ -214,125 +243,53 @@ export function DX4App({
|
|||||||
/>
|
/>
|
||||||
</motion.span>
|
</motion.span>
|
||||||
<AnimatePresence mode="popLayout">
|
<AnimatePresence mode="popLayout">
|
||||||
{openUserSettings && (
|
<UserSettings
|
||||||
<motion.div
|
{...{
|
||||||
className="flex flex-col bg-grain gap-2 bg-zinc-700/20 p-2 rounded-2xl"
|
openUserSettings,
|
||||||
variants={{
|
userFrNames,
|
||||||
hidden: { opacity: 0, y: 10, filter: "blur(2px)" },
|
setUserId,
|
||||||
show: { opacity: 1, y: 0, filter: "blur(0)" },
|
setsetRoute,
|
||||||
}}
|
setRoute,
|
||||||
initial="hidden"
|
adminId,
|
||||||
animate="show"
|
classId,
|
||||||
exit="hidden"
|
pickmeMode,
|
||||||
>
|
}}
|
||||||
{[
|
/>
|
||||||
// icon
|
|
||||||
// text
|
|
||||||
// onclick
|
|
||||||
// condition
|
|
||||||
[
|
|
||||||
<BiExit />,
|
|
||||||
"выход",
|
|
||||||
() => {
|
|
||||||
setUserId("");
|
|
||||||
setsetRoute(setRoute, "/");
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
],
|
|
||||||
// [
|
|
||||||
// <BiStar />,
|
|
||||||
// "пикми режим",
|
|
||||||
// () => {
|
|
||||||
// setPickmeMode(!pickmeMode);
|
|
||||||
// },
|
|
||||||
// true,
|
|
||||||
// ],
|
|
||||||
[
|
|
||||||
<BiSolidUser />,
|
|
||||||
`админ ${
|
|
||||||
userFrNames["admin"] ? userFrNames["admin"] : adminId
|
|
||||||
}`,
|
|
||||||
() => {},
|
|
||||||
adminId != "",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
<BiLink />,
|
|
||||||
classLinkCopied ? "скопированно" : "коп. ссылку",
|
|
||||||
() => {
|
|
||||||
copyToClipboard(
|
|
||||||
location.href.substring(
|
|
||||||
0,
|
|
||||||
location.href.search("#")
|
|
||||||
) +
|
|
||||||
"#//" +
|
|
||||||
classId
|
|
||||||
).then((a) => {
|
|
||||||
if (a) {
|
|
||||||
setClassLinkCopied(true);
|
|
||||||
setTimeout(() => {
|
|
||||||
setClassLinkCopied(false);
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
classId != "",
|
|
||||||
],
|
|
||||||
].map(
|
|
||||||
(item, i) =>
|
|
||||||
item[3] && (
|
|
||||||
<div
|
|
||||||
key={i}
|
|
||||||
className={
|
|
||||||
"flex gap-2 items-center justify-center transition-colors " +
|
|
||||||
(pickmeMode
|
|
||||||
? "lg:hover:bg-pink-400"
|
|
||||||
: "lg:hover:bg-white lg:hover:text-black") +
|
|
||||||
" p-1 rounded-xl cursor-pointer"
|
|
||||||
}
|
|
||||||
onClick={item[2]}
|
|
||||||
>
|
|
||||||
{item[0]} {item[1]}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</motion.div>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</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
|
<motion.div
|
||||||
layout="position"
|
layout="position"
|
||||||
className="flex flex-col gap-5 w-full not-md:px-4"
|
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
|
<DatePicker
|
||||||
date={selectedDate}
|
date={selectedDate}
|
||||||
setDate={setSelectedDate}
|
setDate={setSelectedDate}
|
||||||
indicator={typeof rasp[2] == "number" && [1, 2].includes(rasp[2])}
|
indicator={typeof rasp[2] == "number" && [1, 2].includes(rasp[2])}
|
||||||
/>
|
/>
|
||||||
<RaspView {...{ rasp, pickmeMode, selectedDate }} />
|
<div className="relative">
|
||||||
<AnimatePresence mode="popLayout">
|
<LayoutGroup>
|
||||||
|
<RaspView {...{ rasp, pickmeMode, selectedDate }} />
|
||||||
|
</LayoutGroup>
|
||||||
{!rasp[0] && (
|
{!rasp[0] && (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="w-full flex justify-center"
|
className="w-full flex justify-center"
|
||||||
initial="hid"
|
initial="hid"
|
||||||
animate="show"
|
animate="show"
|
||||||
exit="hid"
|
|
||||||
variants={{
|
variants={{
|
||||||
show: { opacity: 1, scale: 1 },
|
show: { opacity: 1, scale: 1 },
|
||||||
hid: { opacity: 0, scale: 0 },
|
hid: { opacity: 0, scale: 0 },
|
||||||
@@ -341,27 +298,24 @@ export function DX4App({
|
|||||||
<LoadingSpinner size={25} />
|
<LoadingSpinner size={25} />
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
{/* <CoolMouseBg /> */}
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
<CoolMainBg {...{ pickmeMode }} />
|
<CoolMainBg {...{ pickmeMode }} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function CoolMainBg({ pickmeMode }) {
|
const CoolMainBg = React.memo(({ pickmeMode }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<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
|
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"}`}
|
${pickmeMode ? "from-pink-400/10" : "from-white/2"}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|
||||||
const [tableColHover, setTableColHover] = useState(-1);
|
|
||||||
|
|
||||||
|
export const RaspView = React.memo(({ rasp, pickmeMode, selectedDate }) => {
|
||||||
return (
|
return (
|
||||||
<AnimatePresence mode="popLayout">
|
<AnimatePresence mode="popLayout">
|
||||||
{rasp[0] && typeof rasp[1] == "object" && (
|
{rasp[0] && typeof rasp[1] == "object" && (
|
||||||
@@ -388,48 +342,24 @@ export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|||||||
className="max-w-10"
|
className="max-w-10"
|
||||||
//layout="position"
|
//layout="position"
|
||||||
//layoutId="table-num-h"
|
//layoutId="table-num-h"
|
||||||
onMouseEnter={() => {
|
|
||||||
setTableColHover(0);
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setTableColHover(-1);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
n урока
|
n урока
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
//layout="position"
|
//layout="position"
|
||||||
//layoutId="table-subj-h"
|
//layoutId="table-subj-h"
|
||||||
onMouseEnter={() => {
|
|
||||||
setTableColHover(1);
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setTableColHover(-1);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
предмет
|
предмет
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
//layout="position"
|
//layout="position"
|
||||||
//layoutId="table-cab-h"
|
//layoutId="table-cab-h"
|
||||||
onMouseEnter={() => {
|
|
||||||
setTableColHover(2);
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setTableColHover(-1);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
каб
|
каб
|
||||||
</th>
|
</th>
|
||||||
<th
|
<th
|
||||||
//layout="position"
|
//layout="position"
|
||||||
//layoutId="table-t-h"
|
//layoutId="table-t-h"
|
||||||
onMouseEnter={() => {
|
|
||||||
setTableColHover(3);
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
setTableColHover(-1);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
{rasp[2] == 2 && (
|
{rasp[2] == 2 && (
|
||||||
@@ -449,19 +379,14 @@ export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|||||||
//rasp-key={"rasp_key_" + i + Array(d).join()}
|
//rasp-key={"rasp_key_" + i + Array(d).join()}
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
className={
|
//layout="position"
|
||||||
(tableColHover == 0 ? "lg:bg-zinc-300/15" : "") +
|
//layoutId={`table-num-${i}`}
|
||||||
" font-bold"
|
|
||||||
}
|
|
||||||
//layout="position"
|
|
||||||
//layoutId={`table-num-${i}`}
|
|
||||||
>
|
>
|
||||||
{d["num"]}
|
{d["num"]}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
className={tableColHover == 1 ? "lg:bg-zinc-300/15" : ""}
|
//layout="position"
|
||||||
//layout="position"
|
//layoutId={`table-subj-${i}`}
|
||||||
//layoutId={`table-subj-${i}`}
|
|
||||||
>
|
>
|
||||||
{d.subject
|
{d.subject
|
||||||
.toString()
|
.toString()
|
||||||
@@ -474,9 +399,8 @@ export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|||||||
)) || d.subject}
|
)) || d.subject}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
//layout="position"
|
//layout="position"
|
||||||
//layoutId={`table-cab-${i}`}
|
//layoutId={`table-cab-${i}`}
|
||||||
className={tableColHover == 2 ? "lg:bg-zinc-300/15" : ""}
|
|
||||||
>
|
>
|
||||||
{d.cabinet
|
{d.cabinet
|
||||||
.toString()
|
.toString()
|
||||||
@@ -488,7 +412,7 @@ export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)) || d.cabinet}
|
)) || d.cabinet}
|
||||||
</td>
|
</td>
|
||||||
<td className={tableColHover == 3 ? "lg:bg-zinc-300/15" : ""}>
|
<td>
|
||||||
<div
|
<div
|
||||||
//layout="position"
|
//layout="position"
|
||||||
//layoutId={`table-time-${i}`}
|
//layoutId={`table-time-${i}`}
|
||||||
@@ -510,18 +434,18 @@ export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|||||||
{typeof rasp[1] == "number" && rasp[1] === -322 && (
|
{typeof rasp[1] == "number" && rasp[1] === -322 && (
|
||||||
<motion.div
|
<motion.div
|
||||||
className="w-full flex justify-center"
|
className="w-full flex justify-center"
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0, x: 10 }}
|
exit={{ opacity: 0 }}
|
||||||
>
|
>
|
||||||
<span className="text-2xl font-bold">нет уроков</span>
|
<span className="text-2xl font-bold">нет уроков</span>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
{typeof rasp[1] == "string" && rasp[1].startsWith("ошибка") && (
|
{typeof rasp[1] == "string" && rasp[1].startsWith("ошибка") && (
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1 }}
|
||||||
exit={{ opacity: 0, x: 10 }}
|
exit={{ opacity: 0 }}
|
||||||
className="w-full flex justify-center"
|
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">
|
<span className="text-xl text-center text-transparent bg-clip-text bg-gradient-to-r from-red-300 to-red-500">
|
||||||
@@ -531,4 +455,104 @@ export function RaspView({ rasp, pickmeMode, selectedDate }) {
|
|||||||
)}
|
)}
|
||||||
</AnimatePresence>
|
</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"
|
||||||
|
variants={{
|
||||||
|
hidden: { opacity: 0, y: 10, filter: "blur(2px)" },
|
||||||
|
show: { opacity: 1, y: 0, filter: "blur(0)" },
|
||||||
|
}}
|
||||||
|
initial="hidden"
|
||||||
|
animate="show"
|
||||||
|
exit="hidden"
|
||||||
|
>
|
||||||
|
{[
|
||||||
|
// icon
|
||||||
|
// text
|
||||||
|
// onclick
|
||||||
|
// condition
|
||||||
|
[
|
||||||
|
<BiExit />,
|
||||||
|
"выход",
|
||||||
|
() => {
|
||||||
|
setUserId("");
|
||||||
|
setsetRoute(setRoute, "/");
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
// [
|
||||||
|
// <BiStar />,
|
||||||
|
// "пикми режим",
|
||||||
|
// () => {
|
||||||
|
// setPickmeMode(!pickmeMode);
|
||||||
|
// },
|
||||||
|
// true,
|
||||||
|
// ],
|
||||||
|
[
|
||||||
|
<BiSolidUser />,
|
||||||
|
`админ ${
|
||||||
|
userFrNames["admin"] ? userFrNames["admin"] : adminId
|
||||||
|
}`,
|
||||||
|
() => {},
|
||||||
|
adminId != "",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
<BiLink />,
|
||||||
|
classLinkCopied ? "скопированно" : "коп. ссылку",
|
||||||
|
() => {
|
||||||
|
copyToClipboard(
|
||||||
|
location.href.substring(0, location.href.search("#")) +
|
||||||
|
"#//" +
|
||||||
|
classId
|
||||||
|
).then((a) => {
|
||||||
|
if (a) {
|
||||||
|
setClassLinkCopied(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setClassLinkCopied(false);
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
classId != "",
|
||||||
|
],
|
||||||
|
].map(
|
||||||
|
(item, i) =>
|
||||||
|
item[3] && (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className={
|
||||||
|
"flex gap-2 items-center justify-center transition-colors " +
|
||||||
|
(pickmeMode
|
||||||
|
? "lg:hover:bg-pink-400"
|
||||||
|
: "lg:hover:bg-white lg:hover:text-black") +
|
||||||
|
" p-1 rounded-xl cursor-pointer"
|
||||||
|
}
|
||||||
|
onClick={item[2]}
|
||||||
|
>
|
||||||
|
{item[0]} {item[1]}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|||||||
@@ -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 { BiCheck, BiLeftArrowAlt, BiRightArrowAlt, BiX } from "react-icons/bi";
|
||||||
import { formatDate, getDateTags } from "./dengi.js";
|
import { formatDate, getDateTags } from "./dengi.js";
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, motion, LayoutGroup } from "motion/react";
|
||||||
|
|
||||||
export function Switch({
|
export function Switch({
|
||||||
checked,
|
checked,
|
||||||
@@ -105,69 +105,71 @@ function DatePickerButton({ next = false, date, setDate }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DatePicker(props) {
|
export const DatePicker = React.memo((props) => {
|
||||||
const dateTag = getDateTags(props.date);
|
const dateTag = getDateTags(props.date);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between px-2 py-1 w-full bg-grain border-zinc-800/40 border rounded-2xl">
|
<LayoutGroup>
|
||||||
<DatePickerButton date={props.date} setDate={props.setDate} />
|
<div className="flex items-center justify-between px-2 py-1 w-full bg-grain border-zinc-800/40 border rounded-2xl relative">
|
||||||
<AnimatePresence mode="popLayout">
|
<DatePickerButton date={props.date} setDate={props.setDate} />
|
||||||
<motion.span
|
<AnimatePresence mode="popLayout">
|
||||||
key={formatDate(props.date)}
|
|
||||||
className="cursor-pointer flex items-center gap-1 justify-center w-[80%] text-zinc-300 lg:hover:text-black *:transition-colors transition-colors p-1 rounded-3xl lg:hover:bg-white px-3 overflow-hidden lg:hover:*:text-black"
|
|
||||||
variants={{
|
|
||||||
a: { opacity: 0, filter: "blur(1px)" },
|
|
||||||
b: { opacity: 1, filter: "blur(0px)" },
|
|
||||||
}}
|
|
||||||
initial="a"
|
|
||||||
animate="b"
|
|
||||||
exit="a"
|
|
||||||
onClick={() => {
|
|
||||||
props.setDate(new Date());
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<motion.span
|
<motion.span
|
||||||
className={
|
key={formatDate(props.date)}
|
||||||
"block min-w-2 min-h-2 rounded-full mx-1 transition-colors" +
|
className="cursor-pointer flex items-center gap-1 justify-center w-[80%] text-zinc-300 lg:hover:text-black *:transition-colors transition-colors p-1 rounded-3xl lg:hover:bg-white px-3 overflow-hidden lg:hover:*:text-black"
|
||||||
(props.indicator
|
variants={{
|
||||||
? " bg-zinc-300 animate-pulse"
|
a: { opacity: 0, filter: "blur(1px)" },
|
||||||
: " bg-transparent")
|
b: { opacity: 1, filter: "blur(0px)" },
|
||||||
}
|
}}
|
||||||
layoutId="datepicker_indicator"
|
initial="a"
|
||||||
layout="position"
|
animate="b"
|
||||||
/>
|
exit="a"
|
||||||
<motion.span
|
onClick={() => {
|
||||||
layoutId="datepicker_date"
|
props.setDate(new Date());
|
||||||
layout="position"
|
}}
|
||||||
className="font-semibold"
|
|
||||||
>
|
>
|
||||||
{formatDate(props.date)}
|
<motion.span
|
||||||
|
className={
|
||||||
|
"block min-w-2 min-h-2 rounded-full mx-1 transition-colors" +
|
||||||
|
(props.indicator
|
||||||
|
? " bg-zinc-300 animate-pulse"
|
||||||
|
: " bg-transparent")
|
||||||
|
}
|
||||||
|
layoutId="datepicker_indicator"
|
||||||
|
layout="position"
|
||||||
|
/>
|
||||||
|
<motion.span
|
||||||
|
layoutId="datepicker_date"
|
||||||
|
layout="position"
|
||||||
|
className="font-semibold"
|
||||||
|
>
|
||||||
|
{formatDate(props.date)}
|
||||||
|
</motion.span>
|
||||||
|
{dateTag.length > 0 && (
|
||||||
|
<>
|
||||||
|
<motion.div
|
||||||
|
className="flex"
|
||||||
|
layoutId="datepicker_date_div"
|
||||||
|
layout="position"
|
||||||
|
>
|
||||||
|
<span className="h-[1px] -rotate-50 bg-zinc-800 w-[20px] " />
|
||||||
|
</motion.div>
|
||||||
|
<motion.span
|
||||||
|
initial={{ x: 10, opacity: 0 }}
|
||||||
|
transition={{ delay: 0.1 }}
|
||||||
|
animate={{ x: 0, opacity: 1 }}
|
||||||
|
className="text-zinc-600 italic"
|
||||||
|
>
|
||||||
|
{dateTag}
|
||||||
|
</motion.span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</motion.span>
|
</motion.span>
|
||||||
{dateTag.length > 0 && (
|
</AnimatePresence>
|
||||||
<>
|
<DatePickerButton next date={props.date} setDate={props.setDate} />
|
||||||
<motion.div
|
</div>
|
||||||
className="flex"
|
</LayoutGroup>
|
||||||
layoutId="datepicker_date_div"
|
|
||||||
layout="position"
|
|
||||||
>
|
|
||||||
<span className="h-[1px] -rotate-50 bg-zinc-800 w-[20px] " />
|
|
||||||
</motion.div>
|
|
||||||
<motion.span
|
|
||||||
initial={{ x: 10, opacity: 0 }}
|
|
||||||
transition={{ delay: 0.1 }}
|
|
||||||
animate={{ x: 0, opacity: 1 }}
|
|
||||||
className="text-zinc-600 italic"
|
|
||||||
>
|
|
||||||
{dateTag}
|
|
||||||
</motion.span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</motion.span>
|
|
||||||
</AnimatePresence>
|
|
||||||
<DatePickerButton next date={props.date} setDate={props.setDate} />
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export function DengiButton({
|
export function DengiButton({
|
||||||
onClick,
|
onClick,
|
||||||
|
|||||||
+4
-4
@@ -5,17 +5,17 @@ import { VitePWA } from "vite-plugin-pwa";
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
base:"/dx4/",
|
base: "/dx4/",
|
||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: "autoUpdate",
|
registerType: "autoUpdate",
|
||||||
manifest: {
|
manifest: {
|
||||||
name: "dnevnik-x 4",
|
name: "dx 4",
|
||||||
short_name: "dx4",
|
short_name: "dx4",
|
||||||
description: "",
|
description: "dnevnik-x app",
|
||||||
theme_color: "#000",
|
theme_color: "#eee",
|
||||||
background_color: "#000",
|
background_color: "#000",
|
||||||
display: "standalone",
|
display: "standalone",
|
||||||
scope: "/dx4/",
|
scope: "/dx4/",
|
||||||
|
|||||||
Reference in New Issue
Block a user