mirror of
https://github.com/Leado123/Leado123.github.io.git
synced 2026-10-01 00:32:59 +00:00
wef
This commit is contained in:
+35
-26
@@ -1,38 +1,26 @@
|
||||
import isMobile from "is-mobile";
|
||||
import Marquee from "react-fast-marquee";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { isMobile } from "is-mobile";
|
||||
import { useState } from "react";
|
||||
|
||||
|
||||
interface BlogPosts {
|
||||
title: string;
|
||||
icon: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export const blogPosts: BlogPosts[] = [{ title: "What is 𝐒𝐡𝐚𝐫𝐞 𝐌𝐲 𝐒𝐲𝐥𝐥𝐚𝐛𝐮𝐬 & why is it 𝖇𝖊𝖙𝖙𝖊𝖗 than ℝ𝕒𝕥𝕖 𝕄𝕪 ℙ𝕣𝕠𝕗𝕖𝕤𝕤𝕠𝕣?", icon: "star", link: "/useful_resources" }, { title: "🆄🆂🅴🅵🆄🅻 resources to not miss out for highschool & college students!", icon: "bolt", link: "/useful_resources" }]
|
||||
|
||||
|
||||
|
||||
function Layout({ children }: { children: React.ReactNode }) {
|
||||
const navigate = useNavigate();
|
||||
|
||||
console.log('Layout rendering'); // Add this line
|
||||
|
||||
const [marqueeSpeed, setMarqueeSpeed] = useState(15);
|
||||
|
||||
const uploadSyllabi = () => {
|
||||
navigate('/upload')
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-[#fcfffd] text-[#051008] w-full h-full">
|
||||
<div className={`w-full text-left p-1 flex place-items-center justify-center border-b border-gray-300 `}>
|
||||
<div className="flex-1 gap-4 place-items-center sticky grid grid-cols-3">
|
||||
<text onClick={(e) => navigate("/")} className="text-xl text-[#29a847] cursor-pointer hover:drop-shadow-md font-extrabold flex-1 font-bol">📚 Share My Syllabus <span className="font-light text-purple-600">beta</span></text>
|
||||
<div className="flex-1 flex place-items-center text-center">
|
||||
<span className="material-symbols-rounded p-1 text-black">web_traffic</span>
|
||||
<button onClick={(e) => navigate("/upload")} className="p-1 rounded-full anim-enter-width hover:drop-shadow-xl hover:bg-slate-950 font-[Parkinsans] pl-2 pr-2 font-bold bg-black">
|
||||
<Marquee className="anim-enter-blur w-40" delay={1} gradient={true} gradientWidth="10%" gradientColor="black" speed={marqueeSpeed}>
|
||||
<div className={`flex-1 gap-4 place-items-center sticky ${!isMobile() ? "grid grid-cols-3" : "flex"}`}>
|
||||
{isMobile() ?
|
||||
<button onClick={() => navigate("/upload")} className="p-1 flex-1 rounded-full hover:drop-shadow-xl hover:bg-slate-950 font-[Parkinsans] pl-2 pr-2 font-bold bg-black">
|
||||
<Marquee className="anim-enter-blur max-w-screen" delay={1} gradient={true} gradientWidth="10%" gradientColor="black" speed={15}>
|
||||
<div className="flex gap-1">
|
||||
<span className="bg-blue-800 pl-2 gap-2 pr-2 rounded-md flex">
|
||||
<span className="text-white font-sans">Click to Share A Syllabus!</span>
|
||||
@@ -45,13 +33,34 @@ function Layout({ children }: { children: React.ReactNode }) {
|
||||
<span className="material-symbols-rounded pr-1 text-white">web_traffic</span>
|
||||
</div>
|
||||
</Marquee>
|
||||
</button>
|
||||
<span className="material-symbols-rounded p-1 text-black">add</span>
|
||||
</div>
|
||||
<div className="flex gap-4 font-light text-gray-600">
|
||||
<Link to="/moderator" className=" text-gray-600">Moderator Panel</Link>
|
||||
<Link to="/blog" className="text-gray-600">Blog</Link>
|
||||
</div>
|
||||
</button> :
|
||||
<div>
|
||||
<text onClick={() => navigate("/")} className="text-xl text-[#29a847] cursor-pointer hover:drop-shadow-md font-extrabold flex-1 font-bol">📚 Share My Syllabus <span className="font-light text-purple-600">beta</span></text>
|
||||
<div className="flex-1 flex place-items-center text-center">
|
||||
<span className="material-symbols-rounded p-1 text-black">web_traffic</span>
|
||||
<button onClick={() => navigate("/upload")} className="p-1 rounded-full anim-enter-width hover:drop-shadow-xl hover:bg-slate-950 font-[Parkinsans] pl-2 pr-2 font-bold bg-black">
|
||||
<Marquee className="anim-enter-blur w-40" delay={1} gradient={true} gradientWidth="10%" gradientColor="black" speed={15}>
|
||||
<div className="flex gap-1">
|
||||
<span className="bg-blue-800 pl-2 gap-2 pr-2 rounded-md flex">
|
||||
<span className="text-white font-sans">Click to Share A Syllabus!</span>
|
||||
|
||||
</span>
|
||||
<span className="material-symbols-rounded text-white">web_traffic</span>
|
||||
<span className="bg-purple-700 pl-2 gap-2 pr-2 place-items-center rounded-md flex">
|
||||
<span className="text-white font-bold font-sans">Sharying a syllabus awards 2 volunteer hours</span>
|
||||
</span>
|
||||
<span className="material-symbols-rounded pr-1 text-white">web_traffic</span>
|
||||
</div>
|
||||
</Marquee>
|
||||
</button>
|
||||
<span className="material-symbols-rounded p-1 text-black">add</span>
|
||||
</div>
|
||||
<div className="flex gap-4 font-light text-gray-600">
|
||||
<Link to="/moderator" className=" text-gray-600">Moderator Panel</Link>
|
||||
<Link to="/blog" className="text-gray-600">Blog</Link>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
|
||||
+2
-53
@@ -1,16 +1,14 @@
|
||||
import { useEffect, useState, useCallback } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import './App.css'
|
||||
|
||||
import SyllabusListing, { ClassListing } from '../components/syllabus_comp';
|
||||
|
||||
import { Accordion, FileInput, } from "flowbite-react";
|
||||
|
||||
import server from '../main'
|
||||
|
||||
import Select from "react-select"
|
||||
import AsyncSelect from "react-select/async";
|
||||
|
||||
import { Tab, TabList, TabPanel, Tabs } from "react-tabs";
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import { isMobile } from "is-mobile";
|
||||
import { useParams } from 'react-router-dom';
|
||||
@@ -25,15 +23,10 @@ interface Filter {
|
||||
|
||||
function App() {
|
||||
const navigate = useNavigate();
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const [email, setEmail] = useState('');
|
||||
const [name, setName] = useState('');
|
||||
const [accordionOpen, setAccordionOpen] = useState(false);
|
||||
const [tempFileId, setTempFileId] = useState<string>("");
|
||||
|
||||
|
||||
const [querying, setQuerying] = useState(false);
|
||||
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
|
||||
const [filter, setFilter] = useState<Filter>({});
|
||||
|
||||
@@ -99,46 +92,8 @@ function App() {
|
||||
}
|
||||
}
|
||||
|
||||
function onCloseModal() {
|
||||
setOpenModal(false);
|
||||
setEmail('');
|
||||
setName('');
|
||||
setFile(null);
|
||||
setAccordionOpen(false);
|
||||
}
|
||||
|
||||
function uploadFile() {
|
||||
let formdata = new FormData();
|
||||
|
||||
if (file === null) {
|
||||
alert("File not uploaded");
|
||||
throw new Error("File not uploaded");
|
||||
}
|
||||
formdata.append("upload", file);
|
||||
formdata.append("email", email);
|
||||
formdata.append("name", name);
|
||||
fetch(`${server}/create`, {
|
||||
method: 'POST',
|
||||
body: formdata,
|
||||
})
|
||||
.then(async (response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`Server error: ${response.statusText}`);
|
||||
}
|
||||
setAccordionOpen(true);
|
||||
let data = await response.json();
|
||||
setTempFileId(data.fileId);
|
||||
setOpenModal(false);
|
||||
alert("Upload successful! You will receive an email with your volunteer hours within 3 days.");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Upload failed:", error);
|
||||
alert("Upload failed: " + error.message);
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
}, [tempFileId])
|
||||
|
||||
const location = useLocation();
|
||||
|
||||
@@ -160,13 +115,7 @@ function App() {
|
||||
},
|
||||
[location])
|
||||
|
||||
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.files === null) return
|
||||
if (e.target.files[0] === null) return
|
||||
|
||||
setFile(e.target.files[0]);
|
||||
setAccordionOpen(true);
|
||||
}
|
||||
|
||||
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
|
||||
if (e.key === "Enter") {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import mime from "mime-types";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ClassListing } from "./components/syllabus_comp";
|
||||
import { ClassListing } from "../components/syllabus_comp";
|
||||
import server from "../main";
|
||||
|
||||
export interface SyllabusReport {
|
||||
id: string;
|
||||
|
||||
@@ -2,13 +2,10 @@ import { useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { ClassListing } from "../components/syllabus_comp";
|
||||
import FileView from "../components/FileView";
|
||||
import { MarkdownView } from "../components/MarkdownView";
|
||||
import { G4F } from "g4f"
|
||||
|
||||
import server from '../main'
|
||||
|
||||
|
||||
import { MDXEditor } from '@mdxeditor/editor'
|
||||
import { headingsPlugin } from '@mdxeditor/editor'
|
||||
|
||||
function Syllabus() {
|
||||
const { id } = useParams();
|
||||
@@ -39,7 +36,7 @@ function Syllabus() {
|
||||
</div>
|
||||
<div className="relative flex-1 h-full">
|
||||
<div className="relative z-10 flex-1 h-full">
|
||||
<MDXEditor className="flex-1 h-full text-3xl text-black font-bold font-[Parkinsans] text-center" markdown={`${syllabus?.content}`} plugins={[headingsPlugin()]} readOnly></MDXEditor>
|
||||
<text>quick overview feature added soon</text>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import server from "../main";
|
||||
|
||||
export interface Class {
|
||||
id: number;
|
||||
|
||||
+96
-84
@@ -6,6 +6,7 @@ import Select from "react-select";
|
||||
import AsyncSelect from "react-select/async";
|
||||
import server from "./main";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import isMobile from "is-mobile";
|
||||
|
||||
export interface AmbiguousClass extends Class {
|
||||
school: School;
|
||||
@@ -102,97 +103,108 @@ function Welcome() {
|
||||
}, [selectedCollege, selectedProfessor, selectedClass, shouldNavigate, navigate]);
|
||||
|
||||
return (
|
||||
<div className="w-full text-left h-full bg-[#fafdfb] gap-2 text-[#051008] place-items-center p-32 flex flex-col">
|
||||
<h1 className="font-[Parkinsans] text-5xl w-2/3 font-extrabold">📚 Enter your <span className="text-[#47c068]"> School District, Course Name, or Professor's Name, </span> to begin!</h1>
|
||||
<div className={`w-full text-left h-full bg-[#fafdfb] gap-2 text-[#051008] place-items-center ${!isMobile() ? "p-32" : "p-4"} flex flex-col`}>
|
||||
|
||||
<Select
|
||||
className="p-1 text-lg bg-[#fafdfb] w-2/3 rounded-md border-gray-300"
|
||||
placeholder="School District: i.e. RCCD, Chaffey, SBVC, etc."
|
||||
options={collegeOptions}
|
||||
getOptionLabel={(option: School) => option.name}
|
||||
getOptionValue={(option: School) => option.name}
|
||||
onChange={(selectedOption: School | null) => {
|
||||
if (selectedOption) {
|
||||
setSelectedCollege(selectedOption.name);
|
||||
setShouldNavigate(true);
|
||||
}
|
||||
}}
|
||||
isSearchable={true}
|
||||
/>
|
||||
{!isMobile() &&
|
||||
<div>
|
||||
<h1 className="font-[Parkinsans] text-5xl w-2/3 font-extrabold">📚 Enter your <span className="text-[#47c068]"> School District, Course Name, or Professor's Name, </span> to begin!</h1>
|
||||
|
||||
<AsyncSelect
|
||||
className="p-1 text-lg bg-[#fafdfb] w-2/3 rounded-md border-gray-300"
|
||||
placeholder="Course Name: ENG-1A, General Psych, etc."
|
||||
loadOptions={async (inputValue) => {
|
||||
if (!inputValue) {
|
||||
inputValue = "A";
|
||||
console.log('inputValue', inputValue);
|
||||
}
|
||||
const responses = await Promise.all(
|
||||
collegeOptions.map(async (college) => {
|
||||
const res = await fetch(`${server}/search/class/?q=${inputValue}&s=${college.name}`, {
|
||||
method: "POST",
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.map((item: AmbiguousClass) => ({
|
||||
...item,
|
||||
school: college,
|
||||
}));
|
||||
})
|
||||
);
|
||||
return responses.flat();
|
||||
}}
|
||||
defaultOptions={defaultClassOptions}
|
||||
formatOptionLabel={(option: AmbiguousClass) => (
|
||||
<div>
|
||||
<div>{option.className}</div>
|
||||
<div style={{ fontSize: '0.8em', color: '#888' }}>{option.school.name}</div>
|
||||
</div>
|
||||
)}
|
||||
getOptionValue={(option: AmbiguousClass) => option.className}
|
||||
onChange={(selectedOption: AmbiguousClass | null) => {
|
||||
if (selectedOption) {
|
||||
setSelectedClass(selectedOption.className);
|
||||
setShouldNavigate(true);
|
||||
}
|
||||
}}
|
||||
isSearchable={true}
|
||||
cacheOptions
|
||||
<Select
|
||||
className="p-1 text-lg bg-[#fafdfb] w-2/3 rounded-md border-gray-300"
|
||||
placeholder="School District: i.e. RCCD, Chaffey, SBVC, etc."
|
||||
options={collegeOptions}
|
||||
getOptionLabel={(option: School) => option.name}
|
||||
getOptionValue={(option: School) => option.name}
|
||||
onChange={(selectedOption: School | null) => {
|
||||
if (selectedOption) {
|
||||
setSelectedCollege(selectedOption.name);
|
||||
setShouldNavigate(true);
|
||||
}
|
||||
}}
|
||||
isSearchable={true}
|
||||
/>
|
||||
|
||||
/>
|
||||
<AsyncSelect
|
||||
className="p-1 text-lg bg-[#fafdfb] w-2/3 rounded-md border-gray-300"
|
||||
placeholder="Course Name: ENG-1A, General Psych, etc."
|
||||
loadOptions={async (inputValue) => {
|
||||
if (!inputValue) {
|
||||
inputValue = "A";
|
||||
console.log('inputValue', inputValue);
|
||||
}
|
||||
const responses = await Promise.all(
|
||||
collegeOptions.map(async (college) => {
|
||||
const res = await fetch(`${server}/search/class/?q=${inputValue}&s=${college.name}`, {
|
||||
method: "POST",
|
||||
});
|
||||
const data = await res.json();
|
||||
return data.map((item: AmbiguousClass) => ({
|
||||
...item,
|
||||
school: college,
|
||||
}));
|
||||
})
|
||||
);
|
||||
return responses.flat();
|
||||
}}
|
||||
defaultOptions={defaultClassOptions}
|
||||
formatOptionLabel={(option: AmbiguousClass) => (
|
||||
<div>
|
||||
<div>{option.className}</div>
|
||||
<div style={{ fontSize: '0.8em', color: '#888' }}>{option.school.name}</div>
|
||||
</div>
|
||||
)}
|
||||
getOptionValue={(option: AmbiguousClass) => option.className}
|
||||
onChange={(selectedOption: AmbiguousClass | null) => {
|
||||
if (selectedOption) {
|
||||
setSelectedClass(selectedOption.className);
|
||||
setShouldNavigate(true);
|
||||
}
|
||||
}}
|
||||
isSearchable={true}
|
||||
cacheOptions
|
||||
|
||||
<AsyncSelect
|
||||
className="p-1 text-lg bg-[#fafdfb] w-2/3 rounded-md border-gray-300"
|
||||
placeholder="Professor Name: John Doe, Jane Smith, etc."
|
||||
loadOptions={async (inputValue) => {
|
||||
const responses = await Promise.all(
|
||||
collegeOptions.map(async (college) => {
|
||||
const res = await fetch(`${server}/search/professor/?q=${inputValue}&s=${college.name}`, {
|
||||
method: "POST",
|
||||
});
|
||||
const data = await res.json();
|
||||
return data;
|
||||
})
|
||||
);
|
||||
return responses.flat();
|
||||
}}
|
||||
defaultOptions={defaultProfessorOptions}
|
||||
getOptionLabel={(option: Professor) => option.name}
|
||||
getOptionValue={(option: Professor) => option.name}
|
||||
onChange={(selectedOption: Professor | null) => {
|
||||
if (selectedOption) {
|
||||
setSelectedProfessor(selectedOption.name);
|
||||
setShouldNavigate(true);
|
||||
}
|
||||
}}
|
||||
isSearchable={true}
|
||||
cacheOptions
|
||||
/>
|
||||
|
||||
/>
|
||||
<AsyncSelect
|
||||
className="p-1 text-lg bg-[#fafdfb] w-2/3 rounded-md border-gray-300"
|
||||
placeholder="Professor Name: John Doe, Jane Smith, etc."
|
||||
loadOptions={async (inputValue) => {
|
||||
const responses = await Promise.all(
|
||||
collegeOptions.map(async (college) => {
|
||||
const res = await fetch(`${server}/search/professor/?q=${inputValue}&s=${college.name}`, {
|
||||
method: "POST",
|
||||
});
|
||||
const data = await res.json();
|
||||
return data;
|
||||
})
|
||||
);
|
||||
return responses.flat();
|
||||
}}
|
||||
defaultOptions={defaultProfessorOptions}
|
||||
getOptionLabel={(option: Professor) => option.name}
|
||||
getOptionValue={(option: Professor) => option.name}
|
||||
onChange={(selectedOption: Professor | null) => {
|
||||
if (selectedOption) {
|
||||
setSelectedProfessor(selectedOption.name);
|
||||
setShouldNavigate(true);
|
||||
}
|
||||
}}
|
||||
isSearchable={true}
|
||||
cacheOptions
|
||||
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{isMobile() &&
|
||||
<div className="text-center flex place-items-center flex-col gap-4 pt-4">
|
||||
<img className="w-1/2 text-center" src="https://akns-images.eonline.com/eol_images/Entire_Site/201363/rs_600x600-130703124143-600.Gru.mh.070313.jpg?fit=around%7C1080:1080&output-quality=90&crop=1080:1080;center,top"></img>
|
||||
<h1 className="font-sans font-black text-2xl text-blue-600">Search Syllabuses in Your School!</h1>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* Search button as fallback */}
|
||||
<div className="flex flex-col text-center gap-2">
|
||||
<text className="relative">or </text>
|
||||
{!isMobile() && <text className="relative">or </text>}
|
||||
<button
|
||||
className="p-2 px-4 bg-black text-white rounded-xl drop-shadow-md hover:drop-shadow-xl cursor-pointer transition-colors"
|
||||
onClick={() => setShouldNavigate(true)}
|
||||
@@ -201,7 +213,7 @@ function Welcome() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex-1"></div>
|
||||
{!isMobile() ? <div className="flex-1"></div> : <div className="h-1/3"></div>}
|
||||
<div className="relative w-full overflow-hidden">
|
||||
<div className="absolute top-0 bottom-0 left-0 w-8 bg-gradient-to-r from-[#fafdfb] to-transparent z-10"></div>
|
||||
<div className="absolute top-0 bottom-0 right-0 w-8 bg-gradient-to-l from-[#fafdfb] to-transparent z-10"></div>
|
||||
|
||||
Reference in New Issue
Block a user