import React, { useState, useEffect, useMemo } from 'react'; import { Shuffle, RefreshCw, Languages, Settings, ChevronRight, Check, X, ArrowLeftRight } from 'lucide-react'; // ========================================== // DATA - HER KAN DU LEGGE TIL FLERE ORD // ========================================== const vocabularyData = [ { id: 'hilsener', name: 'Hilsener & Uttrykk (Привітання)', color: 'bg-blue-100 border-blue-300', words: [ { no: "Hei / Hallo", ua: "Привіт (Pryvit)" }, { no: "God morgen", ua: "Доброго ранку (Dobroho ranku)" }, { no: "God dag", ua: "Добрий день (Dobryi den)" }, { no: "God kveld", ua: "Добрий вечір (Dobryi vechir)" }, { no: "God natt", ua: "На добраніч (Na dobranich)" }, { no: "Ha det bra", ua: "До побачення (Do pobachennya)" }, { no: "Takk", ua: "Дякую (Dyakuyu)" }, { no: "Vær så snill", ua: "Будь ласка (Bud laska)" }, { no: "Unnskyld", ua: "Вибачте (Vybachte)" }, { no: "Hvordan går det?", ua: "Як справи? (Yak spravy?)" }, { no: "Det går bra", ua: "Все добре (Vse dobre)" }, { no: "Hva heter du?", ua: "Як тебе звати? (Yak tebe zvaty?)" }, { no: "Jeg heter...", ua: "Мене звати... (Mene zvaty...)" }, { no: "Hyggelig å møte deg", ua: "Приємно познайомитися (Pryiemno poznayomytysya)" }, { no: "Jeg forstår ikke", ua: "Я не розумію (Ya ne rozumiyu)" }, { no: "Ja", ua: "Так (Tak)" }, { no: "Nei", ua: "Ні (Ni)" }, { no: "Kanskje", ua: "Можливо (Mozhlyvo)" }, { no: "Hjelp!", ua: "Допоможіть! (Dopomozhit!)" }, { no: "Snakker du engelsk?", ua: "Ви розмовляєте англійською? (Vy rozmovlyayete anhliyskoyu?)" } ] }, { id: 'familie', name: 'Familie (Сім\'я)', color: 'bg-red-100 border-red-300', words: [ { no: "Familie", ua: "Сім'я (Simya)" }, { no: "Mor / Mamma", ua: "Мати / Мама (Maty / Mama)" }, { no: "Far / Pappa", ua: "Батько / Тато (Batko / Tato)" }, { no: "Søster", ua: "Сестра (Sestra)" }, { no: "Bror", ua: "Брат (Brat)" }, { no: "Datter", ua: "Дочка (Dochka)" }, { no: "Sønn", ua: "Син (Syn)" }, { no: "Bestemor", ua: "Бабуся (Babusya)" }, { no: "Bestefar", ua: "Дідусь (Didus)" }, { no: "Tante", ua: "Тітка (Titka)" }, { no: "Onkel", ua: "Дядько (Dyadko)" }, { no: "Barn", ua: "Дитина (Dytyna)" }, { no: "Foreldre", ua: "Батьки (Batky)" }, { no: "Ektemann", ua: "Чоловік (Cholovik)" }, { no: "Kone", ua: "Дружина (Druzhyna)" }, { no: "Søskenbarn", ua: "Кузен / Кузина (Kuzen / Kuzyna)" }, { no: "Venn", ua: "Друг (Druh)" }, { no: "Venninne", ua: "Подруга (Podruha)" }, { no: "Baby", ua: "Немовля (Nemovlya)" }, { no: "Tvillinger", ua: "Близнюки (Blyznyuky)" } ] }, { id: 'mat', name: 'Mat & Drikke (Їжа та напої)', color: 'bg-green-100 border-green-300', words: [ { no: "Mat", ua: "Їжа (Yizha)" }, { no: "Drikke", ua: "Напій (Napiy)" }, { no: "Vann", ua: "Вода (Voda)" }, { no: "Brød", ua: "Хліб (Khlib)" }, { no: "Melk", ua: "Молоко (Moloko)" }, { no: "Kaffe", ua: "Кава (Kava)" }, { no: "Te", ua: "Чай (Chai)" }, { no: "Kjøtt", ua: "М'ясо (Myaso)" }, { no: "Kylling", ua: "Курка (Kurka)" }, { no: "Fisk", ua: "Риба (Ryba)" }, { no: "Egg", ua: "Яйце (Yaytse)" }, { no: "Ost", ua: "Сир (Syr)" }, { no: "Frukt", ua: "Фрукти (Frukty)" }, { no: "Grønnsaker", ua: "Овочі (Ovochi)" }, { no: "Eple", ua: "Яблуко (Yabluko)" }, { no: "Potet", ua: "Картопля (Kartoplya)" }, { no: "Suppe", ua: "Суп (Sup)" }, { no: "Frokost", ua: "Сніданок (Snidanok)" }, { no: "Lunsj", ua: "Обід (Obid)" }, { no: "Middag", ua: "Вечеря (Vecherya)" }, { no: "Skål!", ua: "Будьмо! (Budmo!)" }, { no: "Jeg er sulten", ua: "Я голодний (Ya holodnyi)" }, { no: "Jeg er tørst", ua: "Я хочу пити (Ya khochu pyty)" } ] }, { id: 'dyr', name: 'Dyr (Тварини)', color: 'bg-yellow-100 border-yellow-300', words: [ { no: "Hund", ua: "Собака (Sobaka)" }, { no: "Katt", ua: "Кіт (Kit)" }, { no: "Fugl", ua: "Птах (Ptakh)" }, { no: "Hest", ua: "Кінь (Kin)" }, { no: "Ku", ua: "Корова (Korova)" }, { no: "Gris", ua: "Свиня (Svynya)" }, { no: "Sau", ua: "Вівця (Vivtsya)" }, { no: "Ulv", ua: "Вовк (Vovk)" }, { no: "Bjørn", ua: "Ведмідь (Vedmid)" }, { no: "Mus", ua: "Миша (Mysha)" }, { no: "Fisk (dyr)", ua: "Риба (Ryba)" }, { no: "Edderkopp", ua: "Павук (Pavuk)" }, { no: "Slange", ua: "Змія (Zmiya)" }, { no: "Kanin", ua: "Кролик (Krolyk)" }, { no: "Kjæledyr", ua: "Домашня тварина (Domashnya tvaryna)" } ] }, { id: 'tid', name: 'Tid & Tall (Час та Числа)', color: 'bg-purple-100 border-purple-300', words: [ { no: "Tid", ua: "Час (Chas)" }, { no: "Nå", ua: "Зараз (Zaraz)" }, { no: "Senere", ua: "Пізніше (Piznishe)" }, { no: "I dag", ua: "Сьогодні (Sohodni)" }, { no: "I morgen", ua: "Завтра (Zavtra)" }, { no: "I går", ua: "Вчора (Vchora)" }, { no: "Uke", ua: "Тиждень (Tyzhden)" }, { no: "Måned", ua: "Місяць (Misyats)" }, { no: "År", ua: "Рік (Rik)" }, { no: "Klokke / Ur", ua: "Годинник (Hodynnyk)" }, { no: "En", ua: "Один (Odyn)" }, { no: "To", ua: "Два (Dva)" }, { no: "Tre", ua: "Три (Try)" }, { no: "Fire", ua: "Чотири (Chotyry)" }, { no: "Fem", ua: "П'ять (Pyat)" }, { no: "Seks", ua: "Шість (Shist)" }, { no: "Syv", ua: "Сім (Sim)" }, { no: "Åtte", ua: "Вісім (Visim)" }, { no: "Ni", ua: "Дев'ять (Devyat)" }, { no: "Ti", ua: "Десять (Desyat)" }, { no: "Mandag", ua: "Понеділок (Ponedilok)" }, { no: "Tirsdag", ua: "Вівторок (Vivtorok)" }, { no: "Lørdag", ua: "Субота (Subota)" }, { no: "Søndag", ua: "Неділя (Nedilya)" } ] }, { id: 'steder', name: 'Steder (Місця)', color: 'bg-indigo-100 border-indigo-300', words: [ { no: "Hjem", ua: "Дім (Dim)" }, { no: "Skole", ua: "Школа (Shkola)" }, { no: "Jobb", ua: "Робота (Robota)" }, { no: "Butikk", ua: "Магазин (Mahazyn)" }, { no: "Sykehus", ua: "Лікарня (Likarnya)" }, { no: "Park", ua: "Парк (Park)" }, { no: "By", ua: "Місто (Misto)" }, { no: "Land", ua: "Країна (Krayina)" }, { no: "Gate", ua: "Вулиця (Vulytsya)" }, { no: "Skog", ua: "Ліс (Lis)" }, { no: "Hav", ua: "Море (More)" }, { no: "Fjell", ua: "Гора (Hora)" }, { no: "Toalett", ua: "Туалет (Tualet)" }, { no: "Restaurant", ua: "Ресторан (Restoran)" }, { no: "Flyplass", ua: "Аеропорт (Aeroport)" }, { no: "Hotell", ua: "Готель (Hotel)" } ] }, { id: 'hobby', name: 'Hobby & Fritid (Хобі)', color: 'bg-pink-100 border-pink-300', words: [ { no: "Musikk", ua: "Музика (Muzyka)" }, { no: "Sport", ua: "Спорт (Sport)" }, { no: "Lese", ua: "Читання (Chytannya)" }, { no: "Reise", ua: "Подорож (Podorozh)" }, { no: "Fotball", ua: "Футбол (Futbol)" }, { no: "Dans", ua: "Танці (Tantsi)" }, { no: "Synge", ua: "Співати (Spivaty)" }, { no: "Tegne", ua: "Малювати (Malyuvaty)" }, { no: "Kino", ua: "Кіно (Kino)" }, { no: "Spille spill", ua: "Грати в ігри (Hraty v ihry)" }, { no: "Svømme", ua: "Плавати (Plavaty)" }, { no: "Gå tur", ua: "Гуляти (Hulyaty)" } ] }, { id: 'objekter', name: 'Objekter (Предмети)', color: 'bg-gray-100 border-gray-300', words: [ { no: "Bord", ua: "Стіл (Stil)" }, { no: "Stol", ua: "Стілець (Stilets)" }, { no: "Seng", ua: "Ліжко (Lizhko)" }, { no: "Dør", ua: "Двері (Dveri)" }, { no: "Vindu", ua: "Вікно (Vikno)" }, { no: "Bil", ua: "Автомобіль (Avtomobil)" }, { no: "Buss", ua: "Автобус (Avtobus)" }, { no: "Telefon", ua: "Телефон (Telefon)" }, { no: "Datamaskin", ua: "Комп'ютер (Kompyuter)" }, { no: "Bok", ua: "Книга (Knyha)" }, { no: "Penn", ua: "Ручка (Ruchka)" }, { no: "Nøkkel", ua: "Ключ (Klyuch)" }, { no: "Penger", ua: "Гроші (Hroshi)" }, { no: "Veske", ua: "Сумка (Sumka)" }, { no: "Klær", ua: "Одяг (Odyah)" } ] }, { id: 'dagen', name: 'Beskrive dagen (Опис дня)', color: 'bg-orange-100 border-orange-300', words: [ { no: "Våkne", ua: "Прокидатися (Prokydatysya)" }, { no: "Spise", ua: "Їсти (Yisty)" }, { no: "Drikke", ua: "Пити (Pyty)" }, { no: "Gå", ua: "Йти (Yty)" }, { no: "Kjøre", ua: "Їхати (Yikhaty)" }, { no: "Jobbe", ua: "Працювати (Pratsyuvaty)" }, { no: "Lære / Studere", ua: "Вчитися (Vchytysya)" }, { no: "Sove", ua: "Спати (Spaty)" }, { no: "Lage mat", ua: "Готувати (Hotuvaty)" }, { no: "Vaske", ua: "Мити (Myty)" }, { no: "Slappe av", ua: "Відпочивати (Vidpochyvaty)" }, { no: "Jeg er trøtt", ua: "Я втомився (Ya vtomyvsya)" }, { no: "Jeg er glad", ua: "Я щасливий (Ya shchaslyvyi)" }, { no: "Det er travelt", ua: "Це зайнято (Tse zaynyato)" } ] } ]; // ========================================== // APP LOGIC // ========================================== export default function LanguageApp() { const [selectedCategories, setSelectedCategories] = useState(vocabularyData.map(c => c.id)); const [cards, setCards] = useState([]); const [currentIndex, setCurrentIndex] = useState(0); const [isFlipped, setIsFlipped] = useState(false); const [direction, setDirection] = useState<'no_ua' | 'ua_no' | 'mixed'>('mixed'); const [currentCardSide, setCurrentCardSide] = useState<'no' | 'ua'>('no'); // Tracks the front side of the *current* card const [showSettings, setShowSettings] = useState(false); // Initialize and shuffle cards based on selected categories const initializeDeck = useMemo(() => { let deck: any[] = []; vocabularyData.forEach(cat => { if (selectedCategories.includes(cat.id)) { // Add category info to each card for styling const cardsWithMeta = cat.words.map(word => ({ ...word, categoryName: cat.name, color: cat.color })); deck = [...deck, ...cardsWithMeta]; } }); // Fisher-Yates shuffle for (let i = deck.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [deck[i], deck[j]] = [deck[j], deck[i]]; } return deck; }, [selectedCategories]); // Determine starting side based on direction mode const getNextSide = (mode: string) => { if (mode === 'no_ua') return 'no'; if (mode === 'ua_no') return 'ua'; // Mixed: 50/50 chance return Math.random() > 0.5 ? 'no' : 'ua'; }; // Reset when deck changes useEffect(() => { setCards(initializeDeck); setCurrentIndex(0); setIsFlipped(false); setCurrentCardSide(getNextSide(direction)); }, [initializeDeck]); // Handle Mode Change immediately (for current card) useEffect(() => { setCurrentCardSide(getNextSide(direction)); }, [direction]); const handleNext = () => { setIsFlipped(false); setTimeout(() => { setCurrentIndex((prev) => (prev + 1) % cards.length); // Determine the side for the NEXT card setCurrentCardSide(getNextSide(direction)); }, 200); }; const handleFlip = () => { setIsFlipped(!isFlipped); }; const toggleCategory = (id: string) => { setSelectedCategories(prev => prev.includes(id) ? prev.filter(c => c !== id) : [...prev, id] ); }; const toggleAllCategories = () => { if (selectedCategories.length === vocabularyData.length) { setSelectedCategories([]); } else { setSelectedCategories(vocabularyData.map(c => c.id)); } }; const currentCard = cards[currentIndex]; if (!currentCard) { return (

Ingen kategorier valgt

Velg minst én kategori for å starte øvingen.

); } // Logic to determine what text to show based on `currentCardSide` state // If currentCardSide is 'no', Front is NO, Back is UA. // If currentCardSide is 'ua', Front is UA, Back is NO. const getFrontContent = () => currentCardSide === 'no' ? currentCard.no : currentCard.ua; const getBackContent = () => currentCardSide === 'no' ? currentCard.ua : currentCard.no; const getFrontLang = () => currentCardSide === 'no' ? "Norsk 🇳🇴" : "Ukrainsk 🇺🇦"; const getBackLang = () => currentCardSide === 'no' ? "Ukrainsk 🇺🇦" : "Norsk 🇳🇴"; return (
{/* HEADER */}

Språkvenn

Norsk ↔ Ukrainsk

{/* SETTINGS MODAL OVERLAY */} {showSettings && (

Innstillinger

{/* Language Direction */}

Treningsretning

{/* Categories */}

Temaer

{vocabularyData.map((cat) => ( ))}
)} {/* GAME AREA */}
{/* Progress Info */}
{currentCard.categoryName} Kort {currentIndex + 1} / {cards.length}
{/* The Flashcard */}
{/* FRONT SIDE */}
{getFrontLang()}

{getFrontContent()}

Trykk for å se svaret
{/* BACK SIDE */}
{getBackLang()}

{getBackContent()}

{/* CONTROLS */}
{/* CSS for 3D Flip effect */}
); }