Bump deps

Moved button to class
This commit is contained in:
Jakob Kordež 2023-09-20 11:34:12 +02:00
parent 06329fbacc
commit 0cc1664fee
17 changed files with 932 additions and 2579 deletions

View File

@ -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"
}
}

View File

@ -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"
}
}

View File

@ -1,4 +1,4 @@
module.exports = {
plugins: [require('prettier-plugin-tailwindcss')],
plugins: ['prettier-plugin-tailwindcss'],
singleQuote: true,
}

View File

@ -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>

View File

@ -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>

View File

@ -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>
);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>
);
}

View File

@ -73,7 +73,7 @@ export default function Header() {
</Link>
))}
</Dropdown>
)
),
)}
</nav>
</div>

View File

@ -10,7 +10,7 @@ const akosCsv =
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
res: NextApiResponse,
) {
const now = new Date();

View File

@ -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;
}

View File

@ -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', '-.-.'],

View File

@ -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];

View File

@ -19,7 +19,7 @@ module.exports = {
},
container: {
center: true,
padding: "1.2rem",
padding: "2rem",
screens: {
sm: "640px",
md: "768px",

3267
yarn.lock

File diff suppressed because it is too large Load Diff