mirror of
https://github.com/jakobkordez/s5_practice.git
synced 2025-05-15 16:20:31 +00:00
Bump deps
Moved button to class
This commit is contained in:
parent
06329fbacc
commit
0cc1664fee
@ -1,6 +1,11 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "prettier"],
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"next/core-web-vitals",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"no-unused-vars": "warn"
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error"
|
||||
}
|
||||
}
|
||||
|
36
package.json
36
package.json
@ -14,29 +14,31 @@
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.4.0",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@types/node": "^20.4.1",
|
||||
"@types/react": "^18.2.14",
|
||||
"@types/node": "^20.6.3",
|
||||
"@types/react": "^18.2.22",
|
||||
"@types/react-dom": "^18.2.6",
|
||||
"@vercel/analytics": "^1.0.1",
|
||||
"eslint": "^8.44.0",
|
||||
"eslint-config-next": "^13.4.9",
|
||||
"next": "13.4.9",
|
||||
"next-pwa": "^5.6.0",
|
||||
"node-sass": "^8.0.0",
|
||||
"@vercel/analytics": "^1.0.2",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"eslint": "^8.49.0",
|
||||
"eslint-config-next": "^13.5.1",
|
||||
"next": "^13.5.1",
|
||||
"node-sass": "^9.0.0",
|
||||
"postcss": "^8.4.30",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-katex": "^3.0.1",
|
||||
"typescript": "^5.1.6",
|
||||
"zustand": "^4.3.3"
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.2.2",
|
||||
"zustand": "^4.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-katex": "^3.0.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"postcss": "^8.4.25",
|
||||
"prettier": "^2.8.4",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"sass": "^1.58.3",
|
||||
"tailwindcss": "^3.3.2"
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.2",
|
||||
"@typescript-eslint/parser": "^6.7.2",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier-plugin-tailwindcss": "^0.5.4",
|
||||
"sass": "^1.67.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
module.exports = {
|
||||
plugins: [require('prettier-plugin-tailwindcss')],
|
||||
plugins: ['prettier-plugin-tailwindcss'],
|
||||
singleQuote: true,
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@/components/button';
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface IzpitState {
|
||||
@ -123,14 +122,19 @@ export default function Generator() {
|
||||
/>
|
||||
</div>
|
||||
<div className="control">
|
||||
<Button onClick={randomize}>Premešaj</Button>
|
||||
<button className="button" onClick={randomize}>
|
||||
Premešaj
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="buttons">
|
||||
<Button onClick={updateFrameUrl}>Generiraj</Button>
|
||||
<button className="button" onClick={updateFrameUrl}>
|
||||
Generiraj
|
||||
</button>
|
||||
{frameUrl && (
|
||||
<Button
|
||||
<button
|
||||
className="button"
|
||||
onClick={() =>
|
||||
(
|
||||
document.getElementById('exam-frame') as HTMLIFrameElement
|
||||
@ -138,7 +142,7 @@ export default function Generator() {
|
||||
}
|
||||
>
|
||||
Natisni
|
||||
</Button>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
@ -4,7 +4,6 @@ import { Question } from '@/interfaces/question';
|
||||
import { getExamQuestions } from '@/util/question-util';
|
||||
import { create } from 'zustand';
|
||||
import QuestionCard from '@/components/question_card';
|
||||
import { Button } from '@/components/button';
|
||||
import { scrollToTop } from '@/components/scroll-to-top-button';
|
||||
|
||||
enum QuizState {
|
||||
@ -71,9 +70,9 @@ export default function IzpitQuiz() {
|
||||
<>
|
||||
{state === QuizState.Ready && (
|
||||
<div className="section">
|
||||
<Button className="mx-auto" onClick={load}>
|
||||
<button className="button mx-auto" onClick={load}>
|
||||
Začni
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -102,17 +101,18 @@ export default function IzpitQuiz() {
|
||||
/>
|
||||
))}
|
||||
|
||||
<Button
|
||||
<button
|
||||
className="button"
|
||||
onClick={() =>
|
||||
finish(
|
||||
questions!
|
||||
.map((q, qi) => q.correct === answers![qi][0])
|
||||
.reduce((acc, cur) => acc + (cur ? 1 : 0), 0)
|
||||
.reduce((acc, cur) => acc + (cur ? 1 : 0), 0),
|
||||
)
|
||||
}
|
||||
>
|
||||
Zaključi
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -127,9 +127,9 @@ export default function IzpitQuiz() {
|
||||
{correctCount} / {answers!.length} (
|
||||
{Math.round((correctCount! / answers!.length) * 1000) / 10} %)
|
||||
</p>
|
||||
<Button className="mt-6" onClick={reset}>
|
||||
<button className="button mt-6" onClick={reset}>
|
||||
Nazaj na začetek
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -148,7 +148,7 @@ export default function IzpitQuiz() {
|
||||
reveal={true}
|
||||
selected={[answers![qi][0], question.correct]}
|
||||
/>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,5 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@/components/button';
|
||||
import { robotoMono } from '@/fonts/fonts';
|
||||
import {
|
||||
generateAllCallsigns,
|
||||
@ -92,22 +91,28 @@ export default function CallsignTool() {
|
||||
/>
|
||||
<div className="mt-1 flex flex-row gap-2">
|
||||
{clas ? (
|
||||
<Button className="flex-1" onClick={() => setCallsign(randCall(5))}>
|
||||
<button
|
||||
className="button flex-1"
|
||||
onClick={() => setCallsign(randCall(5))}
|
||||
>
|
||||
Naključen prost 2-črkovni klicni znak
|
||||
</Button>
|
||||
</button>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Button className="flex-1" onClick={() => setCallsign(randCall(6))}>
|
||||
<button
|
||||
className="button flex-1"
|
||||
onClick={() => setCallsign(randCall(6))}
|
||||
>
|
||||
Naključen prost 3-črkovni klicni znak
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col overflow-clip rounded-lg border">
|
||||
{tests
|
||||
.filter((test) =>
|
||||
test.preTest ? test.preTest(clas, callsign) : true
|
||||
test.preTest ? test.preTest(clas, callsign) : true,
|
||||
)
|
||||
.map((test, i) => {
|
||||
const result = test.test(callsign);
|
||||
@ -169,9 +174,9 @@ export default function CallsignTool() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<Button onClick={() => setShowSimilar(true)}>
|
||||
<button className="button" onClick={() => setShowSimilar(true)}>
|
||||
Poišči podobne proste klicne znake
|
||||
</Button>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -2,7 +2,6 @@ import { SubHeader } from '@/components/sub_header';
|
||||
import { Metadata } from 'next';
|
||||
import Link from 'next/link';
|
||||
import RandomCallsign from './random_callsign';
|
||||
import { LinkButton } from '@/components/button';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Radioamatersko dovoljenje',
|
||||
@ -15,21 +14,21 @@ export default function License() {
|
||||
<SubHeader title="Radioamatersko dovoljenje (CEPT licenca)">
|
||||
<p>
|
||||
Radioamaterska dovoljenja izdaja{' '}
|
||||
<a className="link-light" href="https://www.akos-rs.si/">
|
||||
<Link className="link-light" href="https://www.akos-rs.si/">
|
||||
agencija za komunikacijska omrežja in storitve Republike Slovenije
|
||||
(AKOS)
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
Po opravljenem izpitu lahko zaprosiš za radioamatersko dovoljenje, ki
|
||||
ga lahko uporabljaš v vseh{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link-light"
|
||||
href="https://en.wikipedia.org/wiki/European_Conference_of_Postal_and_Telecommunications_Administrations"
|
||||
>
|
||||
državah članicah CEPT
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</SubHeader>
|
||||
@ -38,13 +37,13 @@ export default function License() {
|
||||
<h3>Klicni znak</h3>
|
||||
<p>
|
||||
Klicne znake v Sloveniji določa <strong>6. člen</strong>{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link"
|
||||
href="https://www.uradni-list.si/glasilo-uradni-list-rs/vsebina/2023-01-0256/splosni-akt-o-pogojih-za-uporabo-radijskih-frekvenc-namenjenih-radioamaterski-in-radioamaterski-satelitski-storitvi"
|
||||
>
|
||||
splošnega akta o pogojih za uporabo radijskih frekvenc, namenjenih
|
||||
radioamaterski in radioamaterski satelitski storitvi
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
@ -62,12 +61,12 @@ export default function License() {
|
||||
<h4>Izbira klicnega znaka</h4>
|
||||
<p>
|
||||
Seznam zasedenih klicnih znakov je dostopen v{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link"
|
||||
href="https://www.akos-rs.si/registri/seznam-registrov/radioamaterji"
|
||||
>
|
||||
registru radioamaterjev
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
@ -97,9 +96,9 @@ export default function License() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LinkButton href="/klicni-znak" className="w-full">
|
||||
<Link href="/klicni-znak" className="button w-full">
|
||||
Pomagaj izbrati klicni znak
|
||||
</LinkButton>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="flex bg-light">
|
||||
@ -127,15 +126,15 @@ export default function License() {
|
||||
</p>
|
||||
|
||||
<div className="mt-6 flex flex-col gap-4 text-center md:flex-row">
|
||||
<LinkButton className="flex-1" href="https://evloge.akos-rs.si/">
|
||||
<Link className="button flex-1" href="https://evloge.akos-rs.si/">
|
||||
Elektronska vloga
|
||||
</LinkButton>
|
||||
<LinkButton
|
||||
className="flex-1"
|
||||
</Link>
|
||||
<Link
|
||||
className="button flex-1"
|
||||
href="https://www.akos-rs.si/fileadmin/user_upload/Vloga_za_radioamatersko_dovoljenje.dotx"
|
||||
>
|
||||
Obrazec
|
||||
</LinkButton>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -155,9 +155,9 @@ export default function Home() {
|
||||
</ul>
|
||||
<p>
|
||||
Za točno vsebino, si oglej{' '}
|
||||
<a className="link" href="https://zrs.si/files/kriteriji.pdf">
|
||||
<Link className="link" href="https://zrs.si/files/kriteriji.pdf">
|
||||
kriterij za izpit
|
||||
</a>{' '}
|
||||
</Link>{' '}
|
||||
ali pa si oglej{' '}
|
||||
<Link className="link" href="/zbirka">
|
||||
zbirko vprašanj
|
||||
@ -178,12 +178,12 @@ export default function Home() {
|
||||
<p>
|
||||
Zveza radioamaterjev Slovenije nekajkrat letno organizira izpite za
|
||||
radioamaterje. Izpitni roki so objavljeni na{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link"
|
||||
href="http://www.hamradio.si/index.php?option=com_content&view=article&id=677&Itemid=118"
|
||||
>
|
||||
spletni strani ZRS
|
||||
</a>
|
||||
</Link>
|
||||
. Poleg teh izpitov lahko radioklubi organizirajo izpite za svoje
|
||||
tečajnike.
|
||||
</p>
|
||||
@ -191,20 +191,20 @@ export default function Home() {
|
||||
<h3>Vsebine za pripravo na izpit</h3>
|
||||
<p>
|
||||
Vsa snov, ki se lahko pojavi v izpitnih vprašanjih je vsebovana v{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link"
|
||||
href="http://www.homemade.net/ra/prirocnik_novi.pdf"
|
||||
>
|
||||
Priročniku za radioamaterje (3. izdaja)
|
||||
</a>
|
||||
</Link>
|
||||
. V 3. izdaji je bilo najdenih že nekaj napak in predvsem mankajoče
|
||||
poglavje o detektorjih, zato je bolj priporočljiva{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link"
|
||||
href="https://www.radioamater.si/wp-content/uploads/2016/01/prirocnik-za-radioamaterje_2izd.pdf"
|
||||
>
|
||||
2. izdaja priročnika
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
@ -256,12 +256,12 @@ export default function Home() {
|
||||
</p>
|
||||
<p>
|
||||
Pred začetkom oddajanja pa je priporočljivo prebrati še{' '}
|
||||
<a
|
||||
<Link
|
||||
className="link"
|
||||
href="http://www.hamradio.si/images/dokumenti/publikacije/etika_junij%202021.pdf"
|
||||
>
|
||||
Etiko in operaterske postopke
|
||||
</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
|
||||
|
@ -7,7 +7,6 @@ import { create } from 'zustand';
|
||||
import { Category } from '@/interfaces/category';
|
||||
import QuestionCard from '@/components/question_card';
|
||||
import { SubHeader } from '@/components/sub_header';
|
||||
import { Button } from '@/components/button';
|
||||
|
||||
const qPerPage = 5;
|
||||
|
||||
@ -111,12 +110,13 @@ export default function VajaQuiz() {
|
||||
))}
|
||||
</select>
|
||||
|
||||
<Button
|
||||
<button
|
||||
className="button"
|
||||
disabled={isLoading}
|
||||
onClick={!isLoading ? () => load(selectedCategory) : undefined}
|
||||
>
|
||||
Naloži
|
||||
</Button>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</SubHeader>
|
||||
@ -142,7 +142,9 @@ export default function VajaQuiz() {
|
||||
|
||||
{questions.length > displayed && (
|
||||
<div className="flex flex-row justify-center gap-3">
|
||||
<Button onClick={loadMore}>Naloži več</Button>
|
||||
<button className="button" onClick={loadMore}>
|
||||
Naloži več
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -1,53 +0,0 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
interface ButtonProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function Button({
|
||||
children,
|
||||
className,
|
||||
onClick,
|
||||
disabled,
|
||||
}: ButtonProps) {
|
||||
className ??= '';
|
||||
|
||||
return (
|
||||
<button
|
||||
className={`flex flex-row items-center justify-center rounded-lg bg-primary px-5 py-2 font-semibold text-white shadow-lg transition-colors hover:bg-primary-dark active:bg-primary-darker disabled:opacity-70 ${className}`}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
interface LinkButtonProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
export function LinkButton({ children, className, href }: LinkButtonProps) {
|
||||
className ??= '';
|
||||
|
||||
return href.startsWith('http') ? (
|
||||
<a
|
||||
className={`flex flex-row items-center justify-center rounded-lg bg-primary px-5 py-2 font-semibold text-white shadow-lg transition-colors hover:bg-primary-dark active:bg-primary-darker disabled:opacity-70 ${className}`}
|
||||
href={href}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
className={`flex flex-row items-center justify-center rounded-lg bg-primary px-5 py-2 font-semibold text-white shadow-lg transition-colors hover:bg-primary-dark active:bg-primary-darker disabled:opacity-70 ${className}`}
|
||||
href={href}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
@ -73,7 +73,7 @@ export default function Header() {
|
||||
</Link>
|
||||
))}
|
||||
</Dropdown>
|
||||
)
|
||||
),
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@ const akosCsv =
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const now = new Date();
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
@import 'katex/dist/katex.min.css';
|
||||
|
||||
.button {
|
||||
@apply flex flex-row items-center justify-center rounded-lg bg-primary px-5 py-2 font-semibold text-white shadow-lg transition-colors hover:bg-primary-dark active:bg-primary-darker disabled:opacity-70;
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0084f0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export function generateRandomCallsign(): string {
|
||||
const length = Math.ceil(Math.random() * 3);
|
||||
let callsign = `S5${String.fromCharCode(
|
||||
Math.floor(Math.random() * 10) + 48
|
||||
Math.floor(Math.random() * 10) + 48,
|
||||
)}`;
|
||||
for (let i = 0; i < length; i++) {
|
||||
callsign += String.fromCharCode(Math.floor(Math.random() * 26) + 65);
|
||||
@ -64,7 +64,7 @@ export function levenshteinDistance(from: string, to: string): number {
|
||||
curr[j] = Math.min(
|
||||
prev[j] + removeWeight,
|
||||
curr[j - 1] + addWeight,
|
||||
prev[j - 1] + cost
|
||||
prev[j - 1] + cost,
|
||||
);
|
||||
}
|
||||
|
||||
@ -88,8 +88,8 @@ export function cwWeight(text: string): number {
|
||||
if (!cw) throw new Error(`No cw for ${text[i]}`);
|
||||
|
||||
ret += cw.length - 1;
|
||||
for (const c in cw) {
|
||||
if (cw[c] == '.') ret += 1;
|
||||
for (let i = 0; i < cw.length; i++) {
|
||||
if (cw[i] == '.') ret += 1;
|
||||
else ret += 3;
|
||||
}
|
||||
}
|
||||
@ -97,7 +97,7 @@ export function cwWeight(text: string): number {
|
||||
return ret;
|
||||
}
|
||||
|
||||
const cwMap = new Map<String, String>([
|
||||
const cwMap = new Map<string, string>([
|
||||
['A', '.-'],
|
||||
['B', '-...'],
|
||||
['C', '-.-.'],
|
||||
|
@ -20,7 +20,7 @@ const openFile = async (): Promise<QuestionFile> => {
|
||||
export const getQuestions = async (): Promise<Question[]> => {
|
||||
const file = await openFile();
|
||||
|
||||
return file.questions.map((question: any) => ({
|
||||
return file.questions.map((question) => ({
|
||||
id: question.id,
|
||||
question: question.question,
|
||||
image: question.image,
|
||||
@ -33,16 +33,16 @@ export const getQuestions = async (): Promise<Question[]> => {
|
||||
export const getCategories = async (): Promise<Category[]> => {
|
||||
const file = await openFile();
|
||||
|
||||
return file.categories.map((category: any) => ({
|
||||
return file.categories.map((category) => ({
|
||||
id: category.id,
|
||||
title: category.title,
|
||||
questions: category.questions,
|
||||
// questions: category.questions,
|
||||
}));
|
||||
};
|
||||
|
||||
export const getExamQuestions = async (
|
||||
seed: number,
|
||||
count: number = 60
|
||||
count: number = 60,
|
||||
): Promise<Question[]> => {
|
||||
const rnd = new Random(seed);
|
||||
|
||||
@ -63,7 +63,7 @@ export const getExamQuestions = async (
|
||||
* @param array Array of items to shuffle
|
||||
* @param rnd Random number generator
|
||||
*/
|
||||
const shuffle = (array: any[], rnd: Random) => {
|
||||
const shuffle = (array: unknown[], rnd: Random) => {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = rnd.nextInt() % (i + 1);
|
||||
const temp = array[i];
|
||||
|
@ -19,7 +19,7 @@ module.exports = {
|
||||
},
|
||||
container: {
|
||||
center: true,
|
||||
padding: "1.2rem",
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
sm: "640px",
|
||||
md: "768px",
|
||||
|
Loading…
x
Reference in New Issue
Block a user