feat: slicing page ranking
This commit is contained in:
parent
1c1e828315
commit
ae17e2d0ba
|
@ -16,6 +16,7 @@
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^5.3.0",
|
"react-icons": "^5.3.0",
|
||||||
|
"react-nice-avatar": "^1.5.0",
|
||||||
"react-router-dom": "^6.26.1",
|
"react-router-dom": "^6.26.1",
|
||||||
"react-virtualized-auto-sizer": "^1.0.24",
|
"react-virtualized-auto-sizer": "^1.0.24",
|
||||||
"react-window": "^1.8.10",
|
"react-window": "^1.8.10",
|
||||||
|
@ -2069,6 +2070,12 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chroma-js": {
|
||||||
|
"version": "2.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.6.0.tgz",
|
||||||
|
"integrity": "sha512-BLHvCB9s8Z1EV4ethr6xnkl/P2YRFOGqfgvuMG/MyCbZPrTA+NeiByY6XvgF0zP4/2deU2CXnWyMa3zu1LqQ3A==",
|
||||||
|
"license": "(BSD-3-Clause AND Apache-2.0)"
|
||||||
|
},
|
||||||
"node_modules/cliui": {
|
"node_modules/cliui": {
|
||||||
"version": "7.0.4",
|
"version": "7.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||||
|
@ -3475,7 +3482,6 @@
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
@ -3809,6 +3815,17 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prop-types": {
|
||||||
|
"version": "15.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"object-assign": "^4.1.1",
|
||||||
|
"react-is": "^16.13.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/punycode": {
|
"node_modules/punycode": {
|
||||||
"version": "2.3.1",
|
"version": "2.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
|
@ -3869,6 +3886,26 @@
|
||||||
"react": "*"
|
"react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-is": {
|
||||||
|
"version": "16.13.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/react-nice-avatar": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-nice-avatar/-/react-nice-avatar-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-sGusqbgWIA4Il6Y0zHEfs4XF+a06etNljhwFYiHIGATDmVVf53Nez7U7GY5EwEz5/xGuUhs6uel5AC5NN/2UPg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.14.3",
|
||||||
|
"chroma-js": "^2.1.2",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-refresh": {
|
"node_modules/react-refresh": {
|
||||||
"version": "0.14.2",
|
"version": "0.14.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-icons": "^5.3.0",
|
"react-icons": "^5.3.0",
|
||||||
|
"react-nice-avatar": "^1.5.0",
|
||||||
"react-router-dom": "^6.26.1",
|
"react-router-dom": "^6.26.1",
|
||||||
"react-virtualized-auto-sizer": "^1.0.24",
|
"react-virtualized-auto-sizer": "^1.0.24",
|
||||||
"react-window": "^1.8.10",
|
"react-window": "^1.8.10",
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
|
||||||
|
const slides = [
|
||||||
|
{
|
||||||
|
title: "Nama",
|
||||||
|
description:
|
||||||
|
"Masukkan nama Anda untuk memulai. Nama Anda akan digunakan untuk personalisasi pengalaman Anda selama menggunakan aplikasi ini.",
|
||||||
|
image: "/assets/images/susun_1.svg",
|
||||||
|
button: "Next",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Tebak Huruf",
|
||||||
|
description:
|
||||||
|
"Tebak huruf sesuai soal yang ditampilkan. Ini adalah latihan untuk meningkatkan keterampilan kognitif dan kecepatan berpikir Anda.",
|
||||||
|
image: "/assets/images/susun_2.svg",
|
||||||
|
button: "Next",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Proses Jawaban",
|
||||||
|
description:
|
||||||
|
"Tahan tangan Anda di depan kamera sampai proses selesai dan tampil dialog benar atau tidaknya jawaban.",
|
||||||
|
image: "/assets/images/susun_3.svg",
|
||||||
|
button: "Next",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Score",
|
||||||
|
description:
|
||||||
|
"Raih skor tertinggimu dengan menyelesaikan tugas dengan cepat dan tepat. Skor Anda akan dibandingkan dengan pengguna lain di papan peringkat.",
|
||||||
|
image: "/assets/images/susun_4.svg",
|
||||||
|
button: "Get Started",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function Carousel() {
|
||||||
|
const [current, setCurrent] = useState(0);
|
||||||
|
|
||||||
|
const nextSlide = () => {
|
||||||
|
setCurrent((prev) => (prev === slides.length - 1 ? 0 : prev + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
const prevSlide = () => {
|
||||||
|
setCurrent((prev) => (prev === 0 ? slides.length - 1 : prev - 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-full max-w-lg mx-auto p-6 pb-20 bg-white rounded-xl shadow-lg">
|
||||||
|
<AnimatePresence mode="wait">
|
||||||
|
{slides.map(
|
||||||
|
(slide, index) =>
|
||||||
|
index === current && (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
className="flex flex-col items-center text-center"
|
||||||
|
initial={{ opacity: 0, y: 20 }}
|
||||||
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
exit={{ opacity: 0, y: -20 }}
|
||||||
|
transition={{ duration: 0.5 }}
|
||||||
|
>
|
||||||
|
<img src={slide.image} alt={slide.title} className="h-60" />
|
||||||
|
{/* <h2 className="mt-4 text-xl font-bold">{slide.title}</h2> */}
|
||||||
|
<p className="mt-8 text-gray-500 text-sm">
|
||||||
|
{slide.description}
|
||||||
|
</p>
|
||||||
|
{/* <button
|
||||||
|
onClick={nextSlide}
|
||||||
|
className="mt-4 bg-blue-500 text-white py-2 px-4 rounded-full shadow-md"
|
||||||
|
>
|
||||||
|
{slide.button}
|
||||||
|
</button> */}
|
||||||
|
</motion.div>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2">
|
||||||
|
{slides.map((_, index) => (
|
||||||
|
<button
|
||||||
|
key={index}
|
||||||
|
onClick={() => setCurrent(index)}
|
||||||
|
className={`h-2 w-2 rounded-full ${
|
||||||
|
index === current ? "bg-blue-500" : "bg-gray-300"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={prevSlide}
|
||||||
|
className="absolute left-0 top-1/2 -translate-y-1/2 bg-base-100 text-gray-600 p-1 rounded-full"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="h-4 w-4"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M15 19l-7-7 7-7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={nextSlide}
|
||||||
|
className="absolute right-0 top-1/2 -translate-y-1/2 bg-base-100 text-gray-600 p-1 rounded-full"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className="h-4 w-4"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M9 5l7 7-7 7"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,7 +4,11 @@ const FooterPage = () => {
|
||||||
<div className="flex flex-row justify-center py-2 bg-white">
|
<div className="flex flex-row justify-center py-2 bg-white">
|
||||||
<p className="text-xs text-center">
|
<p className="text-xs text-center">
|
||||||
© 2024 <span className="font-medium">Kedai Susu Tuli</span> &
|
© 2024 <span className="font-medium">Kedai Susu Tuli</span> &
|
||||||
Developed by <span className="font-medium">Mphstar</span> ❤️
|
Developed by{" "}
|
||||||
|
<a href="https://mphstar.me" target="_blank" rel="noopener noreferrer">
|
||||||
|
<span className="underline font-semibold">Mphstar</span>
|
||||||
|
</a>{" "}
|
||||||
|
❤️
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
|
@ -22,7 +22,7 @@ const HeaderPage = () => {
|
||||||
</div>
|
</div>
|
||||||
<ul
|
<ul
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex md:flex-row flex-col items-center justify-center fixed md:static min-h-svh md:min-h-0 w-full md:w-fit bg-white/50 md:bg-transparent md:backdrop-blur-none backdrop-blur-md z-[999] top-0 left-0",
|
"flex md:flex-row flex-col items-center justify-center fixed md:static min-h-svh md:min-h-0 w-full md:w-fit bg-white/50 md:bg-transparent z-[999] top-0 left-0",
|
||||||
navStore.isOpen ? "translate-y-0" : "-translate-y-full",
|
navStore.isOpen ? "translate-y-0" : "-translate-y-full",
|
||||||
"duration-300 ease-in-out md:translate-y-0"
|
"duration-300 ease-in-out md:translate-y-0"
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -19,15 +19,29 @@ const Kamus = () => {
|
||||||
<h1 className="font-semibold">Kamus SIBI</h1>
|
<h1 className="font-semibold">Kamus SIBI</h1>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 mt-6">
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-6 mt-6">
|
||||||
{constantKamus.map((item, index) => (
|
{constantKamus.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
key={index}
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
delay: index * 0.1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<CardKamus
|
<CardKamus
|
||||||
handleClick={() => {
|
handleClick={() => {
|
||||||
setSelectedKamus(item);
|
setSelectedKamus(item);
|
||||||
setShowDialog(true);
|
setShowDialog(true);
|
||||||
}}
|
}}
|
||||||
key={index}
|
|
||||||
title={`Abjad ${item.abjad.toUpperCase()}`}
|
title={`Abjad ${item.abjad.toUpperCase()}`}
|
||||||
image={`/assets/kamus/${item.abjad}.jpg`}
|
image={`/assets/kamus/${item.abjad}.jpg`}
|
||||||
/>
|
/>
|
||||||
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import LayoutPage from "@/components/templates/LayoutPage";
|
||||||
import useNavbarStore from "@/stores/NavbarStore";
|
import useNavbarStore from "@/stores/NavbarStore";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
const Kuis = () => {
|
const Kuis = () => {
|
||||||
const store = useNavbarStore();
|
const store = useNavbarStore();
|
||||||
|
@ -16,7 +17,20 @@ const Kuis = () => {
|
||||||
<p>Be the first!</p>
|
<p>Be the first!</p>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-24 md:gap-6 mt-24 md:mt-52 h-full mb-12">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-24 md:gap-6 mt-24 md:mt-52 h-full mb-12">
|
||||||
<Link to="/kuis/tebak-huruf">
|
<Link to="/kuis/tebak-huruf">
|
||||||
<div className="relative ">
|
<motion.div
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
delay: 0.1,
|
||||||
|
}}
|
||||||
|
className="relative "
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
className="absolute w-24 -top-12 left-4 md:left-12"
|
className="absolute w-24 -top-12 left-4 md:left-12"
|
||||||
src="/assets/images/tebak-huruf.png"
|
src="/assets/images/tebak-huruf.png"
|
||||||
|
@ -28,10 +42,23 @@ const Kuis = () => {
|
||||||
</h1>
|
</h1>
|
||||||
<p>Tebak huruf dan coba simulasikan</p>
|
<p>Tebak huruf dan coba simulasikan</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="/kuis/menyusun-huruf">
|
<Link to="/kuis/menyusun-huruf">
|
||||||
<div className="relative ">
|
<motion.div
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
delay: 0.2,
|
||||||
|
}}
|
||||||
|
className="relative "
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
className="absolute w-42 -top-12 left-4 md:left-12"
|
className="absolute w-42 -top-12 left-4 md:left-12"
|
||||||
src="/assets/images/menyusun-huruf.png"
|
src="/assets/images/menyusun-huruf.png"
|
||||||
|
@ -43,7 +70,7 @@ const Kuis = () => {
|
||||||
</h1>
|
</h1>
|
||||||
<p>Susun huruf jadi kata yang tepat</p>
|
<p>Susun huruf jadi kata yang tepat</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</motion.div>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import Carousel from "@/components/organisms/Carousel";
|
import Carousel from "@/components/organisms/CarouselSusunHuruf";
|
||||||
import LayoutPage from "@/components/templates/LayoutPage";
|
import LayoutPage from "@/components/templates/LayoutPage";
|
||||||
import useMenyusunHurufStore from "@/stores/MenyusunHurufStore";
|
import useMenyusunHurufStore from "@/stores/MenyusunHurufStore";
|
||||||
import useNavbarStore from "@/stores/NavbarStore";
|
import useNavbarStore from "@/stores/NavbarStore";
|
||||||
import { AnimatePresence, motion } from "motion/react";
|
import { AnimatePresence, motion } from "motion/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { HiOutlineHome } from "react-icons/hi";
|
||||||
import { IoCloseOutline } from "react-icons/io5";
|
import { IoCloseOutline } from "react-icons/io5";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
@ -121,7 +122,10 @@ const MenyusunHuruf = () => {
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
<div className="flex flex-col flex-1 py-4 relative">
|
<div className="flex flex-col flex-1 py-4 relative">
|
||||||
<ul className="flex gap-3 mt-4">
|
<ul className="flex gap-3 mt-4">
|
||||||
<li className="hover:text-primary cursor-default">Home</li>
|
<li className="hover:text-primary cursor-default flex gap-2 items-center">
|
||||||
|
<HiOutlineHome />
|
||||||
|
<p>Home</p>
|
||||||
|
</li>
|
||||||
<li>{">"}</li>
|
<li>{">"}</li>
|
||||||
<Link to="/kuis" className="hover:text-primary">
|
<Link to="/kuis" className="hover:text-primary">
|
||||||
Kuis
|
Kuis
|
||||||
|
@ -131,10 +135,33 @@ const MenyusunHuruf = () => {
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className="flex-1 flex flex-col mt-12 md:mt-24 w-full md:w-[500px]">
|
<div className="flex-1 flex flex-col mt-12 md:mt-24 w-full md:w-[500px]">
|
||||||
<h1 className="text-5xl font-semibold">
|
<motion.h1
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
delay: 0.2,
|
||||||
|
}}
|
||||||
|
className="text-4xl md:text-5xl font-semibold"
|
||||||
|
>
|
||||||
Start Your <span className="text-primary">Quiz!</span>
|
Start Your <span className="text-primary">Quiz!</span>
|
||||||
</h1>
|
</motion.h1>
|
||||||
<div className="flex flex-col gap-3 w-full mt-24 md:mt-36">
|
<motion.div
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
className="flex flex-col gap-3 w-full mt-24 md:mt-36"
|
||||||
|
>
|
||||||
<h1 className="font-semibold text-xl">Masukkan Nama</h1>
|
<h1 className="font-semibold text-xl">Masukkan Nama</h1>
|
||||||
<div className="bg-[#F2F2F2] rounded-full pr-4 flex py-2 items-center">
|
<div className="bg-[#F2F2F2] rounded-full pr-4 flex py-2 items-center">
|
||||||
<input
|
<input
|
||||||
|
@ -154,13 +181,22 @@ const MenyusunHuruf = () => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span onClick={() => {
|
<span
|
||||||
|
onClick={() => {
|
||||||
setShowDialog(true);
|
setShowDialog(true);
|
||||||
}} className="text-primary btn btn-link px-0">Cara Bermain</span>
|
}}
|
||||||
|
className="text-primary btn btn-link px-0"
|
||||||
|
>
|
||||||
|
Cara Bermain
|
||||||
|
</span>
|
||||||
<span className="text-gray-400">|</span>
|
<span className="text-gray-400">|</span>
|
||||||
<span className="text-primary btn btn-link px-0">Lihat Ranking</span>
|
<Link to="/kuis/ranking" className="text-primary">
|
||||||
</div>
|
<span className="text-primary btn btn-link px-0">
|
||||||
|
Lihat Ranking
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
className="absolute right-0 md:top-36 bottom-0 pointer-events-none"
|
className="absolute right-0 md:top-36 bottom-0 pointer-events-none"
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
import LayoutPage from "@/components/templates/LayoutPage";
|
import LayoutPage from "@/components/templates/LayoutPage";
|
||||||
import useNavbarStore from "@/stores/NavbarStore";
|
import useNavbarStore from "@/stores/NavbarStore";
|
||||||
import useTebakHurufStore from "@/stores/TebakHurufStore";
|
import useTebakHurufStore from "@/stores/TebakHurufStore";
|
||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { HiOutlineHome } from "react-icons/hi";
|
||||||
import { Link, useNavigate } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import Swal from "sweetalert2";
|
import Swal from "sweetalert2";
|
||||||
|
import { AnimatePresence, motion } from "framer-motion";
|
||||||
|
import Carousel from "@/components/organisms/CarouselTebakHuruf";
|
||||||
|
import { IoCloseOutline } from "react-icons/io5";
|
||||||
|
|
||||||
const TebakHuruf = () => {
|
const TebakHuruf = () => {
|
||||||
const quizStore = useTebakHurufStore();
|
const quizStore = useTebakHurufStore();
|
||||||
|
@ -123,11 +127,53 @@ const TebakHuruf = () => {
|
||||||
};
|
};
|
||||||
}, [quizStore.isFinish]);
|
}, [quizStore.isFinish]);
|
||||||
|
|
||||||
|
const [showDialog, setShowDialog] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutPage>
|
<LayoutPage>
|
||||||
|
<AnimatePresence>
|
||||||
|
{showDialog && (
|
||||||
|
<motion.div
|
||||||
|
className="fixed inset-0 bg-black bg-opacity-50 flex items-center z-[999] justify-center"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (e.target === e.currentTarget) {
|
||||||
|
setShowDialog(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<motion.div
|
||||||
|
className="bg-white max-h-[90%] px-8 py-6 rounded-md flex flex-col max-w-[90%] md:min-w-[400px] md:max-w-[400px] w-full"
|
||||||
|
initial={{ scale: 0.5 }}
|
||||||
|
animate={{ scale: 1 }}
|
||||||
|
exit={{ scale: 0.8 }}
|
||||||
|
>
|
||||||
|
<div className="flex gap-2 justify-between items-center pb-8">
|
||||||
|
<h1 className="font-semibold">Cara Bermain</h1>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowDialog(false)}
|
||||||
|
className="hover:bg-base-100 p-3 rounded-md"
|
||||||
|
>
|
||||||
|
<IoCloseOutline />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-col md:flex-row gap-6 overflow-y-auto flex-1">
|
||||||
|
<Carousel />
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
|
</AnimatePresence>
|
||||||
|
|
||||||
<div className="flex flex-col flex-1 py-4 relative">
|
<div className="flex flex-col flex-1 py-4 relative">
|
||||||
<ul className="flex gap-3 mt-4">
|
<ul className="flex gap-3 mt-4">
|
||||||
<li className="hover:text-primary cursor-default">Home</li>
|
<li className="hover:text-primary cursor-default flex gap-2 items-center">
|
||||||
|
<HiOutlineHome />
|
||||||
|
<p>Home</p>
|
||||||
|
</li>
|
||||||
<li>{">"}</li>
|
<li>{">"}</li>
|
||||||
<Link to="/kuis" className="hover:text-primary">
|
<Link to="/kuis" className="hover:text-primary">
|
||||||
Kuis
|
Kuis
|
||||||
|
@ -137,10 +183,33 @@ const TebakHuruf = () => {
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className="flex-1 flex flex-col mt-12 md:mt-24 w-full md:w-[500px]">
|
<div className="flex-1 flex flex-col mt-12 md:mt-24 w-full md:w-[500px]">
|
||||||
<h1 className="text-5xl font-semibold">
|
<motion.h1
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
delay: 0.2,
|
||||||
|
}}
|
||||||
|
className="text-4xl md:text-5xl font-semibold"
|
||||||
|
>
|
||||||
Start Your <span className="text-primary">Quiz!</span>
|
Start Your <span className="text-primary">Quiz!</span>
|
||||||
</h1>
|
</motion.h1>
|
||||||
<div className="flex flex-col gap-3 w-full mt-24 md:mt-36">
|
<motion.div
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
className="flex flex-col gap-3 w-full mt-24 md:mt-36"
|
||||||
|
>
|
||||||
<h1 className="font-semibold text-xl">Masukkan Nama</h1>
|
<h1 className="font-semibold text-xl">Masukkan Nama</h1>
|
||||||
<div className="bg-[#F2F2F2] rounded-full pr-4 flex py-2 items-center">
|
<div className="bg-[#F2F2F2] rounded-full pr-4 flex py-2 items-center">
|
||||||
<input
|
<input
|
||||||
|
@ -159,8 +228,23 @@ const TebakHuruf = () => {
|
||||||
Mulai Kuis
|
Mulai Kuis
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-primary">Lihat Ranking</span>
|
<div className="flex items-center gap-2">
|
||||||
|
<span
|
||||||
|
onClick={() => {
|
||||||
|
setShowDialog(true);
|
||||||
|
}}
|
||||||
|
className="text-primary btn btn-link px-0"
|
||||||
|
>
|
||||||
|
Cara Bermain
|
||||||
|
</span>
|
||||||
|
<span className="text-gray-400">|</span>
|
||||||
|
<Link to="/kuis/ranking" className="text-primary">
|
||||||
|
<span className="text-primary btn btn-link px-0">
|
||||||
|
Lihat Ranking
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
className="absolute right-0 md:top-36 bottom-0 pointer-events-none"
|
className="absolute right-0 md:top-36 bottom-0 pointer-events-none"
|
||||||
|
|
|
@ -0,0 +1,174 @@
|
||||||
|
import LayoutPage from "@/components/templates/LayoutPage";
|
||||||
|
import useNavbarStore from "@/stores/NavbarStore";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { HiOutlineHome } from "react-icons/hi";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "Asep",
|
||||||
|
score: 100,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "Budi",
|
||||||
|
score: 90,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "Cecep",
|
||||||
|
score: 80,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "Dedi",
|
||||||
|
score: 70,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "Euis",
|
||||||
|
score: 60,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "Fafa",
|
||||||
|
score: 50,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "Gaga",
|
||||||
|
score: 40,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: "Haha",
|
||||||
|
score: 30,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: "Ii",
|
||||||
|
score: 20,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
name: "Jaja",
|
||||||
|
score: 10,
|
||||||
|
time: "15-08-2021 12:40",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const Ranking = () => {
|
||||||
|
const store = useNavbarStore();
|
||||||
|
|
||||||
|
const [tabSelected, setTabSelected] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
store.setNavSelected("kuis");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LayoutPage>
|
||||||
|
<div className="flex flex-col flex-1 py-4 relative items-center">
|
||||||
|
<ul className="flex gap-3 mt-4 w-full">
|
||||||
|
<li className="hover:text-primary cursor-default flex gap-2 items-center">
|
||||||
|
<HiOutlineHome />
|
||||||
|
<p>Home</p>
|
||||||
|
</li>
|
||||||
|
<li>{">"}</li>
|
||||||
|
<Link to="/kuis" className="hover:text-primary">
|
||||||
|
Kuis
|
||||||
|
</Link>
|
||||||
|
<li>{">"}</li>
|
||||||
|
<li className="font-medium text-gray-500">Ranking</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div className="md:max-w-[500px] w-full flex flex-col mt-6 items-center">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<button
|
||||||
|
onClick={() => setTabSelected(0)}
|
||||||
|
className={`btn btn-link ${
|
||||||
|
tabSelected === 0 ? "" : "no-underline text-gray-500"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Tebak Huruf
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setTabSelected(1)}
|
||||||
|
className={`btn btn-link ${
|
||||||
|
tabSelected === 1 ? "" : "no-underline text-gray-500"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
Menyusun Huruf
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label className="input input-bordered flex items-center gap-2 w-full mt-6 mb-4">
|
||||||
|
<input type="text" className="grow" placeholder="Search" />
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="currentColor"
|
||||||
|
className="h-4 w-4 opacity-70"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"
|
||||||
|
clipRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{data.map((item, index) => (
|
||||||
|
<motion.div
|
||||||
|
initial={{
|
||||||
|
scale: 0,
|
||||||
|
opacity: 0,
|
||||||
|
}}
|
||||||
|
whileInView={{
|
||||||
|
scale: 1,
|
||||||
|
opacity: 1,
|
||||||
|
transition: { duration: 0.1, delay: index * 0.1 },
|
||||||
|
}}
|
||||||
|
key={item.id}
|
||||||
|
className="flex justify-between mt-4 bg-base-100 hover:bg-base-200 duration-300 ease-in-out px-6 py-4 rounded-md w-full items-center gap-4"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
className="bg-green-400 rounded-full h-14 w-14 object-cover"
|
||||||
|
src={`https://api.dicebear.com/9.x/miniavs/svg?seed=${item.name}&backgroundColor=b6e3f4,c0aede,d1d4f9`}
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<div className="flex flex-col flex-1">
|
||||||
|
<p className="font-semibold">{item.name}</p>
|
||||||
|
<p>{item.score} Poin</p>
|
||||||
|
<p className="text-xs text-gray-500">{item.time}</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`w-6 h-6 rounded-full flex justify-center items-center p-5 `}
|
||||||
|
style={{
|
||||||
|
backgroundColor: ["#b6e3f4", "#c0aede", "#d1d4f9"][
|
||||||
|
Math.floor(Math.random() * 3)
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{index + 1}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LayoutPage>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ranking;
|
|
@ -36,6 +36,11 @@ const myRoute = [
|
||||||
path: "/kuis/menyusun-huruf/app",
|
path: "/kuis/menyusun-huruf/app",
|
||||||
component: lazy(() => import("@/pages/Kuis/MenyusunHuruf/Quiz")),
|
component: lazy(() => import("@/pages/Kuis/MenyusunHuruf/Quiz")),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Ranking",
|
||||||
|
path: "/kuis/ranking",
|
||||||
|
component: lazy(() => import("@/pages/Ranking/Ranking")),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default myRoute;
|
export default myRoute;
|
||||||
|
|
Loading…
Reference in New Issue