beauty cards
This commit is contained in:
parent
4157cd574b
commit
5debb1ebe9
82
package-lock.json
generated
82
package-lock.json
generated
@ -2894,12 +2894,12 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.13.14",
|
"version": "22.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz",
|
||||||
"integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==",
|
"integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~6.20.0"
|
"undici-types": "~6.21.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/parse-json": {
|
"node_modules/@types/parse-json": {
|
||||||
@ -2925,9 +2925,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "18.3.5",
|
"version": "18.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.6.tgz",
|
||||||
"integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==",
|
"integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^18.0.0"
|
"@types/react": "^18.0.0"
|
||||||
@ -4024,9 +4024,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001707",
|
"version": "1.0.30001709",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001709.tgz",
|
||||||
"integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==",
|
"integrity": "sha512-NgL3vUTnDrPCZ3zTahp4fsugQ4dc7EKTSzwQDPEel6DMoMnfH2jhry9n2Zm8onbSR+f/QtKHFOA+iAQu4kbtWA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -4943,9 +4943,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.128",
|
"version": "1.5.130",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.128.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.130.tgz",
|
||||||
"integrity": "sha512-bo1A4HH/NS522Ws0QNFIzyPcyUUNV/yyy70Ho1xqfGYzPUme2F/xr4tlEOuM6/A538U1vDA7a4XfCd1CKRegKQ==",
|
"integrity": "sha512-Ou2u7L9j2XLZbhqzyX0jWDj6gA8D3jIfVzt4rikLf3cGBa0VdReuFimBKS9tQJA4+XpeCxj1NoWlfBXzbMa9IA==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
@ -5255,9 +5255,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-react": {
|
"node_modules/eslint-plugin-react": {
|
||||||
"version": "7.37.4",
|
"version": "7.37.5",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.4.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
|
||||||
"integrity": "sha512-BGP0jRmfYyvOyvMoRX/uoUeW+GqNj9y16bPQzqAHf3AYII/tDs+jMN0dBVkl88/OZwNGwrVFxE7riHsXVfy/LQ==",
|
"integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -5271,7 +5271,7 @@
|
|||||||
"hasown": "^2.0.2",
|
"hasown": "^2.0.2",
|
||||||
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
|
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
|
||||||
"minimatch": "^3.1.2",
|
"minimatch": "^3.1.2",
|
||||||
"object.entries": "^1.1.8",
|
"object.entries": "^1.1.9",
|
||||||
"object.fromentries": "^2.0.8",
|
"object.fromentries": "^2.0.8",
|
||||||
"object.values": "^1.2.1",
|
"object.values": "^1.2.1",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
@ -6134,14 +6134,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/framer-motion": {
|
"node_modules/framer-motion": {
|
||||||
"version": "12.6.2",
|
"version": "12.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.6.3.tgz",
|
||||||
"integrity": "sha512-7LgPRlPs5aG8UxeZiMCMZz8firC53+2+9TnWV22tuSi38D3IFRxHRUqOREKckAkt6ztX+Dn6weLcatQilJTMcg==",
|
"integrity": "sha512-2hsqknz23aloK85bzMc9nSR2/JP+fValQ459ZTVElFQ0xgwR2YqNjYSuDZdFBPOwVCt4Q9jgyTt6hg6sVOALzw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"motion-dom": "^12.6.1",
|
"motion-dom": "^12.6.3",
|
||||||
"motion-utils": "^12.5.0",
|
"motion-utils": "^12.6.3",
|
||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@ -6677,9 +6677,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/html-entities": {
|
"node_modules/html-entities": {
|
||||||
"version": "2.5.3",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz",
|
||||||
"integrity": "sha512-D3AfvN7SjhTgBSA8L1BN4FpPzuEd06uy4lHwSoRWr0lndi9BKaNzPLKGOWZ2ocSGguozr08TTb2jhCLHaemruw==",
|
"integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@ -7856,19 +7856,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/motion-dom": {
|
"node_modules/motion-dom": {
|
||||||
"version": "12.6.1",
|
"version": "12.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.6.3.tgz",
|
||||||
"integrity": "sha512-8XVsriTUEVOepoIDgE/LDGdg7qaKXWdt+wQA/8z0p8YzJDLYL8gbimZ3YkCLlj7bB2i/4UBD/g+VO7y9ZY0zHQ==",
|
"integrity": "sha512-gRY08RjcnzgFYLemUZ1lo/e9RkBxR+6d4BRvoeZDSeArG4XQXERSPapKl3LNQRu22Sndjf1h+iavgY0O4NrYqA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"motion-utils": "^12.5.0"
|
"motion-utils": "^12.6.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/motion-utils": {
|
"node_modules/motion-utils": {
|
||||||
"version": "12.5.0",
|
"version": "12.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.6.3.tgz",
|
||||||
"integrity": "sha512-+hFFzvimn0sBMP9iPxBa9OtRX35ZQ3py0UHnb8U29VD+d8lQ8zH3dTygJWqK7av2v6yhg7scj9iZuvTS0f4+SA==",
|
"integrity": "sha512-R/b3Ia2VxtTNZ4LTEO5pKYau1OUNHOuUfxuP0WFCTDYdHkeTBR9UtxR1cc8mDmKr8PEhmmfnTKGz3rSMjNRoRg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
@ -8929,9 +8929,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-hook-form": {
|
"node_modules/react-hook-form": {
|
||||||
"version": "7.54.2",
|
"version": "7.55.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.54.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.55.0.tgz",
|
||||||
"integrity": "sha512-eHpAUgUjWbZocoQYUHposymRb4ZP6d0uwUnooL2uOybA9/3tPUvoAKqEWK1WaSiTxxOfTpffNZP7QwlnM3/gEg==",
|
"integrity": "sha512-XRnjsH3GVMQz1moZTW53MxfoWN7aDpUg/GpVNc4A3eXRVNdGXfbzJ4vM4aLQ8g6XCUh1nIbx70aaNCl7kxnjog==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
@ -10534,9 +10534,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "6.20.0",
|
"version": "6.21.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||||
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
|
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/unicode-canonical-property-names-ecmascript": {
|
"node_modules/unicode-canonical-property-names-ecmascript": {
|
||||||
@ -10694,9 +10694,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/use-sync-external-store": {
|
"node_modules/use-sync-external-store": {
|
||||||
"version": "1.4.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
|
||||||
"integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==",
|
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
|
@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { User } from '../../__data__/model'
|
import { User } from '../../__data__/model'
|
||||||
import { AddMissedButton } from './sstyle'
|
import { AddMissedButton } from './sstyle'
|
||||||
import { AddIcon } from '@chakra-ui/icons'
|
import { AddIcon } from '@chakra-ui/icons'
|
||||||
|
import { UserCard } from '../user-card'
|
||||||
|
|
||||||
interface StudentCardBackProps {
|
interface StudentCardBackProps {
|
||||||
student: User & { present?: boolean; recentlyPresent?: boolean }
|
student: User & { present?: boolean; recentlyPresent?: boolean }
|
||||||
@ -14,139 +15,33 @@ export const StudentCardBack: React.FC<StudentCardBackProps> = ({ student, onAdd
|
|||||||
const { colorMode } = useColorMode()
|
const { colorMode } = useColorMode()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
// Determine attendance level based on student data
|
// Веселые градиентные цвета
|
||||||
// We simulate different battery levels based on student presence
|
const colors = {
|
||||||
const getAttendanceLevel = () => {
|
gradient: colorMode === 'light'
|
||||||
// Using a scale of 0-5 for battery levels (6 segments total)
|
? 'linear-gradient(135deg, #F6FFDE, #E3F2C1, #C9DBB2)'
|
||||||
// In a real scenario, you would calculate this based on attendance history
|
: 'linear-gradient(135deg, #0D1282, #2F58CD, #3795BD)',
|
||||||
|
text: colorMode === 'light' ? "#2E7D32" : "#81C784"
|
||||||
// If student is present, show higher battery level
|
|
||||||
if (student.present) {
|
|
||||||
return student.recentlyPresent ? 4 : 5; // Full or almost full if present
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For absent students, randomly assign a lower battery level (0-3)
|
// Is the student marked as present?
|
||||||
// In a real implementation, this would come from attendance history
|
const isPresent = !!student.present;
|
||||||
|
|
||||||
|
// Функция для генерации случайного, но стабильного положения пузырьков для каждого студента
|
||||||
|
const getBubbleStyle = (index: number) => {
|
||||||
|
// Используем ID студента для получения стабильных, но уникальных чисел
|
||||||
const id = student.sub || '';
|
const id = student.sub || '';
|
||||||
// Use the student ID hash to deterministically assign a battery level
|
const charSum = id.split('').reduce((sum, char, i) => sum + char.charCodeAt(0) * (i + 1), 0);
|
||||||
// This creates a pseudo-random but consistent level for each student
|
|
||||||
const idSum = id.split('').reduce((sum, char) => sum + char.charCodeAt(0), 0);
|
|
||||||
return Math.min(3, Math.floor((idSum % 100) / 25));
|
|
||||||
}
|
|
||||||
|
|
||||||
const batteryLevel = getAttendanceLevel();
|
// Разные значения для разных пузырей
|
||||||
|
const seed = (charSum + index * 137) % 100;
|
||||||
|
|
||||||
// Check if student recently joined the class
|
return {
|
||||||
const isRecentlyJoined = !!student.recentlyPresent;
|
left: `${(seed % 80) + 10}%`,
|
||||||
|
top: `${((seed * 1.5) % 80) + 10}%`,
|
||||||
// Get color scheme based on battery level
|
size: `${(seed % 15) + 10}px`,
|
||||||
const getBatteryColors = () => {
|
duration: `${(seed % 4) + 8}s`
|
||||||
// Colors for different battery levels
|
};
|
||||||
const colorSchemes = [
|
};
|
||||||
// Empty (0)
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
primary: "#E53E3E", // red.500
|
|
||||||
secondary: "#FED7D7", // red.100
|
|
||||||
accent: "#C53030", // red.700
|
|
||||||
text: "journal.pl.lesson.veryPoorAttendance"
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
primary: "#F56565", // red.400
|
|
||||||
secondary: "#9B2C2C", // red.800
|
|
||||||
accent: "#FEB2B2", // red.200
|
|
||||||
text: "journal.pl.lesson.veryPoorAttendance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Very Low (1)
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
primary: "#DD6B20", // orange.500
|
|
||||||
secondary: "#FEEBC8", // orange.100
|
|
||||||
accent: "#C05621", // orange.700
|
|
||||||
text: "journal.pl.lesson.poorAttendance"
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
primary: "#ED8936", // orange.400
|
|
||||||
secondary: "#9C4221", // orange.800
|
|
||||||
accent: "#FBD38D", // orange.200
|
|
||||||
text: "journal.pl.lesson.poorAttendance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Low (2)
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
primary: "#D69E2E", // yellow.500
|
|
||||||
secondary: "#FEFCBF", // yellow.100
|
|
||||||
accent: "#B7791F", // yellow.700
|
|
||||||
text: "journal.pl.lesson.lowAttendance"
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
primary: "#ECC94B", // yellow.400
|
|
||||||
secondary: "#975A16", // yellow.800
|
|
||||||
accent: "#F6E05E", // yellow.200
|
|
||||||
text: "journal.pl.lesson.lowAttendance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Medium (3)
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
primary: "#38B2AC", // teal.500
|
|
||||||
secondary: "#B2F5EA", // teal.100
|
|
||||||
accent: "#285E61", // teal.700
|
|
||||||
text: "journal.pl.lesson.mediumAttendance"
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
primary: "#4FD1C5", // teal.400
|
|
||||||
secondary: "#234E52", // teal.800
|
|
||||||
accent: "#81E6D9", // teal.200
|
|
||||||
text: "journal.pl.lesson.mediumAttendance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Good (4)
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
primary: "#3182CE", // blue.500
|
|
||||||
secondary: "#BEE3F8", // blue.100
|
|
||||||
accent: "#2C5282", // blue.700
|
|
||||||
text: "journal.pl.lesson.goodAttendance"
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
primary: "#4299E1", // blue.400
|
|
||||||
secondary: "#2A4365", // blue.800
|
|
||||||
accent: "#90CDF4", // blue.200
|
|
||||||
text: "journal.pl.lesson.goodAttendance"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// Excellent (5)
|
|
||||||
{
|
|
||||||
light: {
|
|
||||||
primary: "#38A169", // green.500
|
|
||||||
secondary: "#C6F6D5", // green.100
|
|
||||||
accent: "#276749", // green.700
|
|
||||||
text: "journal.pl.lesson.excellentAttendance"
|
|
||||||
},
|
|
||||||
dark: {
|
|
||||||
primary: "#48BB78", // green.400
|
|
||||||
secondary: "#22543D", // green.800
|
|
||||||
accent: "#9AE6B4", // green.200
|
|
||||||
text: "journal.pl.lesson.excellentAttendance"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const scheme = colorSchemes[batteryLevel];
|
|
||||||
return scheme[colorMode === 'light' ? 'light' : 'dark'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const colors = getBatteryColors();
|
|
||||||
|
|
||||||
// Function to determine which battery segments to fill based on level
|
|
||||||
const getSegmentFill = (segmentIndex: number) => {
|
|
||||||
const isActive = segmentIndex <= batteryLevel;
|
|
||||||
|
|
||||||
return isActive ? colors.primary : 'transparent';
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
@ -168,113 +63,112 @@ export const StudentCardBack: React.FC<StudentCardBackProps> = ({ student, onAdd
|
|||||||
aspectRatio: "1"
|
aspectRatio: "1"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AddMissedButton onClick={() => onAddUser(student)} aria-label={t('journal.pl.common.add')}>
|
{/* Add button */}
|
||||||
|
{!isPresent && (
|
||||||
|
<AddMissedButton
|
||||||
|
onClick={() => onAddUser?.(student)}
|
||||||
|
aria-label={t('journal.pl.common.add')}
|
||||||
|
>
|
||||||
<AddIcon boxSize={3} />
|
<AddIcon boxSize={3} />
|
||||||
</AddMissedButton>
|
</AddMissedButton>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Веселый фон с градиентом */}
|
||||||
<Box
|
<Box
|
||||||
position="absolute"
|
position="absolute"
|
||||||
top="0"
|
top="0"
|
||||||
left="0"
|
left="0"
|
||||||
right="0"
|
right="0"
|
||||||
bottom="0"
|
bottom="0"
|
||||||
opacity="0.15"
|
background={colors.gradient}
|
||||||
className="animated-bg"
|
opacity="0.2"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Декоративные пузырьки */}
|
||||||
|
{[...Array(6)].map((_, i) => {
|
||||||
|
const style = getBubbleStyle(i);
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
key={i}
|
||||||
|
position="absolute"
|
||||||
|
left={style.left}
|
||||||
|
top={style.top}
|
||||||
|
width={style.size}
|
||||||
|
height={style.size}
|
||||||
|
borderRadius="full"
|
||||||
|
background={colors.gradient}
|
||||||
|
opacity="0.4"
|
||||||
sx={{
|
sx={{
|
||||||
background: `linear-gradient(135deg,
|
animation: `float ${style.duration} ease-in-out infinite`,
|
||||||
${colors.secondary}, ${colors.primary}, ${colors.accent})`,
|
"@keyframes float": {
|
||||||
backgroundSize: "400% 400%",
|
"0%, 100%": { transform: "translateY(0px)" },
|
||||||
animation: "gradientAnimation 8s ease infinite",
|
"50%": { transform: "translateY(-10px)" }
|
||||||
"@keyframes gradientAnimation": {
|
|
||||||
"0%": { backgroundPosition: "0% 50%" },
|
|
||||||
"50%": { backgroundPosition: "100% 50%" },
|
|
||||||
"100%": { backgroundPosition: "0% 50%" }
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Box
|
);
|
||||||
position="relative"
|
})}
|
||||||
textAlign="center"
|
|
||||||
|
{/* Content */}
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
width="100%"
|
||||||
zIndex="1"
|
zIndex="1"
|
||||||
>
|
>
|
||||||
|
{/* Gravatar с весёлой анимацией */}
|
||||||
<Box
|
<Box
|
||||||
width="70px"
|
|
||||||
height="70px"
|
|
||||||
mx="auto"
|
|
||||||
mb={3}
|
|
||||||
position="relative"
|
position="relative"
|
||||||
|
width="80px"
|
||||||
|
height="80px"
|
||||||
|
borderRadius="full"
|
||||||
|
overflow="hidden"
|
||||||
|
mb={4}
|
||||||
|
boxShadow="0 0 15px rgba(255, 255, 255, 0.4)"
|
||||||
>
|
>
|
||||||
{isRecentlyJoined && (
|
{/* Using the UserCard for gravatar */}
|
||||||
<Box
|
<Box
|
||||||
position="absolute"
|
position="absolute"
|
||||||
top="-5px"
|
top="0"
|
||||||
left="-5px"
|
left="0"
|
||||||
right="-5px"
|
right="0"
|
||||||
bottom="-5px"
|
bottom="0"
|
||||||
borderRadius="full"
|
zIndex="1"
|
||||||
zIndex="0"
|
overflow="hidden"
|
||||||
sx={{
|
>
|
||||||
animation: "pulse 2s infinite",
|
<UserCard
|
||||||
background: `radial-gradient(circle, ${colors.accent} 0%, transparent 70%)`,
|
wrapperAS="div"
|
||||||
"@keyframes pulse": {
|
student={student}
|
||||||
"0%": { opacity: 0.7, transform: "scale(0.95)" },
|
present={false}
|
||||||
"70%": { opacity: 0, transform: "scale(1.2)" },
|
width="100%"
|
||||||
"100%": { opacity: 0, transform: "scale(1.5)" }
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
{/* Battery icon with 6 segments */}
|
|
||||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
{/* Battery outline */}
|
|
||||||
<rect
|
|
||||||
x="2"
|
|
||||||
y="6"
|
|
||||||
width="18"
|
|
||||||
height="12"
|
|
||||||
rx="2"
|
|
||||||
stroke={colors.primary}
|
|
||||||
strokeWidth="1.5"
|
|
||||||
fill="transparent"
|
|
||||||
/>
|
|
||||||
{/* Battery cap */}
|
|
||||||
<path
|
|
||||||
d="M20 10H22V14H20V10Z"
|
|
||||||
fill={colors.primary}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Battery segments - from lowest to highest */}
|
|
||||||
<rect x="4" y="8" width="2.3" height="8" rx="1" fill={getSegmentFill(0)} />
|
|
||||||
<rect x="7" y="8" width="2.3" height="8" rx="1" fill={getSegmentFill(1)} />
|
|
||||||
<rect x="10" y="8" width="2.3" height="8" rx="1" fill={getSegmentFill(2)} />
|
|
||||||
<rect x="13" y="8" width="2.3" height="8" rx="1" fill={getSegmentFill(3)} />
|
|
||||||
<rect x="16" y="8" width="2.3" height="8" rx="1" fill={getSegmentFill(4)} />
|
|
||||||
|
|
||||||
{/* Lightning icon if recently joined or fully charged */}
|
|
||||||
{(isRecentlyJoined || batteryLevel === 5) && (
|
|
||||||
<path
|
|
||||||
d="M11.5 7.5L8 12H11L9.5 16.5L13 12H10L11.5 7.5Z"
|
|
||||||
fill={colors.accent}
|
|
||||||
stroke={colors.primary}
|
|
||||||
strokeWidth="0.3"
|
|
||||||
opacity="0.9"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</svg>
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box fontSize="sm" fontWeight="medium" color={colorMode === "light" ? "gray.800" : "white"}>
|
</Box>
|
||||||
|
|
||||||
|
{/* Student name */}
|
||||||
|
<Box
|
||||||
|
fontSize="sm"
|
||||||
|
fontWeight="medium"
|
||||||
|
textAlign="center"
|
||||||
|
color={colorMode === "light" ? "gray.800" : "white"}
|
||||||
|
mb={1}
|
||||||
|
>
|
||||||
{student.name || student.preferred_username}
|
{student.name || student.preferred_username}
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
{/* Status с эмодзи */}
|
||||||
<Box
|
<Box
|
||||||
fontSize="xs"
|
fontSize="xs"
|
||||||
mt={1}
|
color={colors.text}
|
||||||
color={colors.primary}
|
|
||||||
fontWeight="medium"
|
fontWeight="medium"
|
||||||
|
display="flex"
|
||||||
|
alignItems="center"
|
||||||
>
|
>
|
||||||
{isRecentlyJoined
|
<Box as="span" mr="1" fontSize="sm">🔔</Box>
|
||||||
? t('journal.pl.lesson.recentlyJoined')
|
{t('journal.pl.lesson.notMarked')}
|
||||||
: t(colors.text || 'journal.pl.lesson.attendance')}
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -109,7 +109,7 @@ export const Wrapper = styled.div<{ warn?: boolean; width?: string | number; pos
|
|||||||
props.warn
|
props.warn
|
||||||
? css`
|
? css`
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
filter: grayscale(0.8);
|
filter: grayscale(0.3);
|
||||||
`
|
`
|
||||||
: ''}
|
: ''}
|
||||||
`
|
`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user