Quest: Wyszukiwanie i filtrowanie w MySQL

CREATE TABLE produkty (
    id      INT AUTO_INCREMENT PRIMARY KEY,
    nazwa   VARCHAR(100) NOT NULL,
    waga    DECIMAL(6,2),
    rozmiar INT,
    data    DATE,
    kolor   VARCHAR(30)
);

INSERT INTO produkty (nazwa, waga, rozmiar, data, kolor) VALUES
('Produkt A', 1.25, 38, '2024-01-15', 'czerwony'),
('Produkt B', 0.80, 36, '2024-02-10', 'niebieski'),
('Produkt C', 2.40, 42, '2024-03-05', 'zielony'),
('Produkt D', 1.10, 44, '2024-04-20', 'czarny');

#1
SELECT *
FROM produkty
WHERE rozmiar IN (36, 38, 42);

#2
SELECT *
FROM produkty
WHERE nazwa LIKE 'Produkt%';

#3
SELECT *
FROM produkty
ORDER BY data
LIMIT 2 OFFSET 1;

#4
SELECT *
FROM produkty
WHERE nazwa LIKE 'Produkt%'
  AND waga IS NOT NULL
ORDER BY waga DESC;

#5
SELECT *
FROM produkty
WHERE waga < 2
  AND nazwa NOT LIKE '%C%';

#6
SELECT *
FROM produkty
WHERE rozmiar BETWEEN 36 AND 42
  AND waga > 0.5
ORDER BY kolor ASC, waga DESC;

#7
SELECT
    nazwa,
    waga,
    CASE
        WHEN waga < 1 THEN 'lekki'
        WHEN waga BETWEEN 1 AND 2 THEN 'średni'
        ELSE 'ciężki'
    END AS kategoria_wagi
FROM produkty;


#8
SELECT
    kolor,
    COUNT(*) AS ile
FROM produkty
GROUP BY kolor;

#9
SELECT
    kolor,
    AVG(waga) AS srednia_waga
FROM produkty
GROUP BY kolor
HAVING AVG(waga) > 1;

Co wyświetlą kwerendy 1-9?

Quest: Obiekt, map i useState

Utwórz projekt za pomocą Vite z kodem:

App.jsx

import { WIDOCZKI } from './assets/data';
import { Box } from './components/Box';
import './App.css';

function App() {
  return (
    <>
      <div className="grid">
        { WIDOCZKI.map(item => (
            <Box
              key={item.id}
              nazwa={item.nazwa}
              plik={item.plik}
              opis={item.opis}
            />
          ))
        }
        <div className="box">
          <h3>Ranking</h3>...
        </div>
      </div>
    </>
  );
}
export default App;

App.css

body {
  margin: 0;
  font-family: Arial, sans-serif;
  background-color: #eeeeee;
}
.grid {
  padding: 20px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

components/Box.jsx

import './Box.css';

export function Box({ nazwa, plik, opis }) {
  return (
    <div className="box">
      <img src={plik} alt={nazwa} />
      <h3>{nazwa}</h3>
      <p>{opis}</p>
    </div>
  );
}

components/Box.css

.box {
  width: 300px;
  padding: 12px;
  background-color: #ffffff;
  border: 1px solid #cccccc;
}
.box img {
  width: 100%;
  height: 150px;
  object-fit: cover;
  display: block;
}
.box h3 {
  margin: 8px 0 4px;
  font-size: 16px;
}
.box p {
  margin: 0;
  font-size: 14px;
}

assets/data.js

export const WIDOCZKI = [
  {
    id: 1,
    nazwa: 'Górski Poranek',
    plik: 'https://picsum.photos/300?1',
    opis: 'Świt wśród szczytów.',
  },
  {
    id: 2,
    nazwa: 'Morski Spokój',
    plik: 'https://picsum.photos/300?2',
    opis: 'Cicha linia horyzontu.',
  },
  {
    id: 3,
    nazwa: 'Leśna Ścieżka',
    plik: 'https://picsum.photos/300?3',
    opis: 'Zielona głębia ciszy.',
  },
  {
    id: 4,
    nazwa: 'Złote Pola',
    plik: 'https://picsum.photos/300?4',
    opis: 'Ciepło letniego dnia.',
  },
  {
    id: 5,
    nazwa: 'Jeziorne Odbicie',
    plik: 'https://picsum.photos/300?5',
    opis: 'Lustro natury.',
  }
];
  1. W każdym Boxie dodaj przycisk polubienia.
  2. Dodaj posortowany ranking.
  3. Dodaj do projektu Bootstrapa i zastąp nim css

Quest: useState w React

W React komponenty muszą reagować na zmiany danych i aktualizować interfejs użytkownika. Zwykłe zmienne nie powodują ponownego renderowania komponentu po zmianie wartości, dlatego nie nadają się do przechowywania stanu. Hook useState rozwiązuje ten problem, umożliwiając przechowywanie danych, których zmiana automatycznie aktualizuje widok. Pobawmy się tym.

Utwórz projekt za pomocą Vite i dodaj poniższy kod:

App.jsx

import Box from "./components/Box";
import { useState } from "react";

function App() {
  // Deklaracja stanu 'licznik' oraz funkcji aktualizującej ten stan
  // Początkowa wartość licznika wynosi 0
  // Dziwna składnia wynika z użycia destructuringu:
  // useState() zwraca tablicę dwuelementową - dajemy nazwy tym elementom
  const [licznik, setLicznik] = useState(0);

  // funkcja anonimowa strzałkowa przypisana do stałej jest
  // równoważna z zakomentowaną wersją :)
  //
  // function dodaj1() {
  //    setLicznik(licznik + 1);
  //   }
  const dodaj1 = () => {
    setLicznik(licznik + 1)
  };

  return (
    <>
      <h2>Licznik: {licznik}</h2>
      <Box text="Adam" action={dodaj1} />
      <Box text="Ewa" action={dodaj1} />
      <Box text="Stefan" action={dodaj1} />
      <Box text="Edek" action={dodaj1} />
    </>
  );
}

export default App;

components/Box.jsx

import Guzik from "./Guzik";

function Box({ text, action }) {
  return (
    <div>
      <p>Właścicielem tego boxa jest: {text}</p>
      <Guzik akcja={action} napis={text} />
    </div>
  );
}

export default Box;

components/Guzik.jsx

function Guzik({ akcja, napis}) {
  return (
    <button onClick={akcja}>
      {napis} powiększa licznik
    </button>
  );
}

export default Guzik;
  1. Dodaj w Boxach przyciski pomniejszające wspólny licznik.
  2. Dodaj indywidualny licznik do każdego Boxa wraz z dodatkowym przyciskiem powiększającym go. W tym celu przyda się nowa zmienna dla stanu komponentu Box.
  3. Zmień działanie przycisków tak by jeden przycisk powiększał oba liczniki: indywidualny oraz wspólny.

Quest: Grid vs Flex w Bootstrapie

Porównajmy dwa warianty kodu:

Grid

<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8">
  <title>Bootstrap layout – Grid</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
    rel="stylesheet">
</head>
<body>

<div class="container my-4">

  <!-- HEADER -->
  <header class="mb-4 border rounded overflow-hidden">
    <img
      src="https://picsum.photos/1200/300"
      class="img-fluid w-100"
      alt="Nagłówek">
  </header>

  <!-- CONTENT -->
  <div class="row g-4">

    <!-- NAV -->
    <nav class="col-12 col-md-3">
      <ul class="list-group border rounded">
        <li class="list-group-item">Home</li>
        <li class="list-group-item">Oferta</li>
        <li class="list-group-item">O nas</li>
        <li class="list-group-item">Kontakt</li>
      </ul>
    </nav>

    <!-- MAIN -->
    <main class="col-12 col-md-9">
      <ul class="list-group border rounded">
        <li class="list-group-item">Artykuł 1</li>
        <li class="list-group-item">Artykuł 2</li>
        <li class="list-group-item">Artykuł 3</li>
        <li class="list-group-item">Artykuł 4</li>
      </ul>
    </main>
  </div>

  <!-- FOOTER -->
  <footer class="mt-4 p-3 border rounded text-center">
    © 2026 – Przykładowa stopka
  </footer>
</div>

</body>
</html>

Flex

<!DOCTYPE html>
<html lang="pl">
<head>
  <meta charset="UTF-8">
  <title>Bootstrap layout – Flex</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link
    href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
    rel="stylesheet">
</head>
<body>
<div class="container my-4 d-flex flex-column gap-4">

  <!-- HEADER -->
  <header class="border rounded overflow-hidden">
    <img
      src="https://picsum.photos/1200/300"
      class="img-fluid w-100"
      alt="Nagłówek">
  </header>

  <!-- CONTENT -->
  <div class="d-flex flex-column flex-md-row gap-4">

    <!-- NAV -->
    <nav class="flex-shrink-0" style="min-width: 200px;">
      <ul class="list-group border rounded">
        <li class="list-group-item">Home</li>
        <li class="list-group-item">Oferta</li>
        <li class="list-group-item">O nas</li>
        <li class="list-group-item">Kontakt</li>
      </ul>
    </nav>

    <!-- MAIN -->
    <main class="flex-fill">
      <ul class="list-group border rounded">
        <li class="list-group-item">Element 1</li>
        <li class="list-group-item">Element 2</li>
        <li class="list-group-item">Element 3</li>
        <li class="list-group-item">Element 4</li>
      </ul>
    </main>

  </div>
  <!-- FOOTER -->
  <footer class="p-3 border rounded text-center">
    © 2026 – Przykładowa stopka
  </footer>
</div>

</body>
</html>

Wybierz bardziej zrozumiały dla Ciebie wariant i przerób:

  1. Zamień miejscami kolumny
  2. Podziel wąską kolumnę na 2 oddzielne ramki (jedna pod drugą)
  3. Zmień szerokości
  4. Dodaj trzecią kolumnę
  5. Zmień domyślną kolejność bloków podczas wyświetlania na wąskim ekranie

Pomocne prompty:

  • Przygotuj zestawienie klas Bootstrapa związanych z layoutem strony
  • Przygotuj prostą stronę z responsywnym layoutem (nagłówek=obrazek, stopka=tekst, main i nav=lista) opartą wyłącznie na klasach bootstrapa. Ma być tak prosta jak to możliwe, ale w miarę ładna (marginesy, obramowania). Stronę przygotuj na 2 sposoby.
  • Wyjaśnij breakpointy w Bootstrapie 5. Podaj wszystkie dostępne breakpointy wraz z nazwą, prefiksem i minimalną szerokością ekranu. Pokaż przykłady klas z wyjaśnieniami. Wyjaśnij zasadę mobile first. Uwzględnij najczęstsze błędy początkujących.

Quest: CSS vs Bootstrap

Osobiście nie lubię dopracowywać wyglądu stron i aplikacji. Jeśli masz podobnie – może Ci się spodobać Bootstrap.

  1. Przeanalizuj kod poniżej
  2. Możesz też przeanalizować kodziki z questa Bootstrap – start
  3. Dopytaj AI czym jest Bootstrap, ale koniecznie przyznaj się, że uczysz się dopiero HTML i CSS, żeby nie popłynął w funkcjonalność JS. Poproś o wyjaśnienie klas z przykładów albo o wygenerowanie tabeli najpotrzebniejszych klas Bootstrapa
  4. Przerób poniższy kod tak, żeby wyglądał jak sensowna strona internetowa. Przerabiaj samodzielnie traktując AI jako asystenta a nie jako guru!
  5. Powstałą stronę dodaj do portfolio 🙂
<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <title>Bootstrap – Zakładki i Karty</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap 5 CDN -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>

<div class="container my-4">
    <div class="row">

        <!-- GŁÓWNA KOLUMNA -->
        <div class="col-lg-8 mb-4">

            <!-- Zakładki -->
            <ul class="nav nav-tabs" id="myTab" role="tablist">
                <li class="nav-item" role="presentation">
                    <button class="nav-link active" data-bs-toggle="tab" data-bs-target="#tabela" type="button">
                        Tabela
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" data-bs-toggle="tab" data-bs-target="#galeria" type="button">
                        Galeria
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" data-bs-toggle="tab" data-bs-target="#karuzela" type="button">
                        Karuzela
                    </button>
                </li>
            </ul>

            <!-- Zawartość zakładek -->
            <div class="tab-content border border-top-0 p-3">

                <!-- TAB 1: TABELA -->
                <div class="tab-pane fade show active" id="tabela">
                    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a vulputate est. Donec tristique placerat finibus. Praesent arcu sapien, aliquam quis massa ullamcorper, feugiat dignissim libero. In consectetur mauris non finibus sollicitudin. Quisque vitae facilisis urna, vel sodales massa. Cras tortor nunc, pellentesque quis augue ac, euismod scelerisque tellus. Etiam purus tellus, posuere a aliquet nec, posuere et diam.</p>
                    <p>Aliquam posuere dignissim orci, ut venenatis eros sollicitudin id. Morbi pharetra aliquet eleifend. Mauris sollicitudin feugiat quam dignissim bibendum. Integer congue risus hendrerit risus ullamcorper, sed semper ligula sodales. Proin nisl enim, faucibus ut ornare id, varius id nibh. Nulla lorem tortor, tincidunt quis nulla egestas, feugiat egestas sem. Nunc sollicitudin auctor odio, ut luctus elit malesuada eu. Maecenas suscipit augue et libero commodo porta. </p>
                    <table class="table table-striped table-responsive">
                        <thead>
                          <tr><th>#</th><th>Nazwa</th><th>Status</th></tr>
                        </thead>
                        <tbody>
                          <tr><td>1</td><td>Element A</td><td>Aktywny</td></tr>
                          <tr><td>2</td><td>Element B</td><td>Nieaktywny</td></tr>
                          <tr><td>3</td><td>Element C</td><td>Aktywny</td></tr>
                        </tbody>
                    </table>
                    <p>Aliquam posuere dignissim orci, ut venenatis eros sollicitudin id. Morbi pharetra aliquet eleifend. Mauris sollicitudin feugiat quam dignissim bibendum. Integer congue risus hendrerit risus ullamcorper, sed semper ligula sodales. Proin nisl enim, faucibus ut ornare id, varius id nibh. Nulla lorem tortor, tincidunt quis nulla egestas, feugiat egestas sem. Nunc sollicitudin auctor odio, ut luctus elit malesuada eu. Maecenas suscipit augue et libero commodo porta. </p>
                </div>

                <!-- TAB 2: GALERIA -->
                <div class="tab-pane fade" id="galeria">
                    <div class="row g-3">
                        <div class="col-6 col-md-4">
                            <img src="https://picsum.photos/300?1" class="img-fluid rounded">
                            <h6>Lorem</h6>
                        </div>
                        <div class="col-6 col-md-4">
                            <img src="https://picsum.photos/300?2" class="img-fluid rounded">
                            <h6>Dolor</h6>
                        </div>
                        <div class="col-6 col-md-4">
                            <img src="https://picsum.photos/300?3" class="img-fluid rounded">
                            <h6>Ipsum</h6>
                        </div>
                    </div>
                </div>

                <!-- TAB 3: KARUZELA -->
                <div class="tab-pane fade" id="karuzela">
                    <div id="carouselExample" class="carousel slide" data-bs-ride="carousel">
                        <div class="carousel-inner">
                            <div class="carousel-item active">
                                <img src="https://picsum.photos/800/300?4" class="d-block w-100">
                                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a vulputate est. Donec tristique placerat finibus. Praesent arcu sapien, aliquam quis massa ullamcorper, feugiat dignissim libero. In consectetur mauris non finibus sollicitudin. Quisque vitae facilisis urna, vel sodales massa. Cras tortor nunc, pellentesque quis augue ac, euismod scelerisque tellus. Etiam purus tellus, posuere a aliquet nec, posuere et diam.</p>
                            </div>
                            <div class="carousel-item">
                                <img src="https://picsum.photos/800/300?5" class="d-block w-100">
                                <p>Aliquam posuere dignissim orci, ut venenatis eros sollicitudin id. Morbi pharetra aliquet eleifend. Mauris sollicitudin feugiat quam dignissim bibendum. Integer congue risus hendrerit risus ullamcorper, sed semper ligula sodales. Proin nisl enim, faucibus ut ornare id, varius id nibh. Nulla lorem tortor, tincidunt quis nulla egestas, feugiat egestas sem. Nunc sollicitudin auctor odio, ut luctus elit malesuada eu. Maecenas suscipit augue et libero commodo porta. </p>
                            </div>
                            <div class="carousel-item">
                                <img src="https://picsum.photos/800/300?6" class="d-block w-100">
                                <p>Quisque scelerisque rhoncus cursus. Donec in fringilla lorem, eu molestie orci. Praesent diam odio, cursus in elit vitae, suscipit convallis mi. Mauris aliquam purus a tempus lobortis. Maecenas quam mauris, condimentum ac elementum sit amet, finibus id sapien. Vestibulum ac rutrum quam. Phasellus scelerisque varius enim nec euismod. Quisque pretium dolor nec orci condimentum, consectetur porta diam pretium.</p>
                            </div>
                        </div>

                        <button class="carousel-control-prev" type="button" data-bs-target="#carouselExample" data-bs-slide="prev">
                            <span class="carousel-control-prev-icon"></span>
                        </button>
                        <button class="carousel-control-next" type="button" data-bs-target="#carouselExample" data-bs-slide="next">
                            <span class="carousel-control-next-icon"></span>
                        </button>
                    </div>
                </div>

            </div>
        </div>

        <!-- BOCZNA KOLUMNA -->
        <div class="col-lg-4">

            <div class="card mb-3">
                <div class="card-body">
                    <h5 class="card-title">Karta 1</h5>
                    <p class="card-text">Krótki opis pierwszej karty.</p>
                </div>
            </div>

            <div class="card mb-3">
                <div class="card-body">
                    <h5 class="card-title">Karta 2</h5>
                    <p class="card-text">Krótki opis drugiej karty.</p>
                </div>
            </div>

            <div class="card">
                <div class="card-body">
                    <h5 class="card-title">Karta 3</h5>
                    <p class="card-text">Krótki opis trzeciej karty.</p>
                </div>
            </div>

        </div>
    </div>
</div>

<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>