├── style.css ├── .gitignore ├── practice-01 ├── .eslintrc.json ├── app │ ├── favicon.ico │ ├── page.module.scss │ ├── layout.js │ ├── globals.css │ └── page.js ├── jsconfig.json ├── next.config.mjs ├── components │ ├── SwitchTheme │ │ ├── SwitchTheme.module.scss │ │ └── index.js │ ├── JokeNotice │ │ ├── JokeNotice.module.scss │ │ └── index.js │ ├── Comment │ │ ├── Comment.module.scss │ │ └── Comment.js │ ├── RandomQuestionsFrequency │ │ ├── RandomQuestionsFrequency.module.scss │ │ └── index.js │ ├── RandomQuestionsList │ │ ├── RandomQuestionsList.module.scss │ │ └── index.js │ ├── QuestionNotice │ │ └── index.js │ ├── RandomQuestions │ │ ├── RandomQuestions.module.scss │ │ └── index.js │ ├── Timer │ │ └── index.js │ ├── Top5dieFive │ │ ├── Five.module.scss │ │ └── index.js │ ├── QuestionOfTheDay │ │ └── index.js │ └── Questions │ │ ├── Questions.module.scss │ │ └── index.js ├── package.json ├── .gitignore ├── public │ └── icons │ │ └── next.svg ├── README.md └── questions.js ├── lecture02 ├── advanced │ ├── chugaev │ │ └── graph.png │ ├── spesivtsev │ │ └── graph.png │ ├── style.css │ └── index.html └── basic │ ├── trebunskih │ └── Saiky.png │ ├── index.html │ ├── chugaev │ └── index.html │ ├── kuznetsov │ └── index.html │ ├── ankudinova │ └── index.html │ ├── Harin │ └── index.html │ ├── gladkov │ └── index.html │ └── Puchkov │ └── puchkov.html ├── lecture04 ├── basic │ ├── trebunskih │ │ └── graph.png │ ├── kuznetsov │ │ ├── assets │ │ │ └── avatar.png │ │ └── scss │ │ │ ├── style.scss │ │ │ ├── abstracts │ │ │ ├── _common.scss │ │ │ └── _vars.scss │ │ │ ├── components │ │ │ └── _button.scss │ │ │ ├── style.css.map │ │ │ ├── sections │ │ │ └── _graph.scss │ │ │ └── style.css │ ├── style.css │ ├── index.html │ ├── chugaev │ │ └── index.html │ └── lecture.html └── advanced │ └── index.js ├── practice-02 ├── components │ ├── randomQuestionNotice │ │ ├── index.php │ │ └── notifications.js │ ├── questionsOfDay │ │ ├── index.php │ │ └── script.js │ ├── randomQuestionFrequency │ │ ├── index.php │ │ └── script.js │ ├── TextValidator │ │ ├── index.php │ │ └── script.js │ ├── simpleRandom │ │ ├── index.php │ │ └── script.js │ ├── checkEmail │ │ ├── script.js │ │ └── index.php │ ├── questions │ │ ├── index.php │ │ └── script.js │ └── questionsByIds │ │ ├── index.php │ │ └── script.js ├── api │ ├── getQuestionOfDay.php │ ├── getRandomQuestion.php │ ├── getRandomQuestionFrequency.php │ ├── getSimpleRandomQuestionsHistory.php │ ├── getSimpleRandomQuestions.php │ ├── getQuestionsByIds.php │ ├── checkEmail.php │ ├── getQuestions.php │ ├── validateText.php │ └── addQuestion.php ├── services │ ├── SessionManager.php │ ├── RandomSmileService.php │ ├── RenderResultTrait.php │ ├── RandomQuestionService.php │ ├── CheckEmailService.php │ ├── RandomQuestionFrequency.php │ ├── SimpleRandomQuestionsService.php │ ├── QuestionOfDayService.php │ ├── QuestionsByIdsService.php │ └── QuestionsService.php └── index.php ├── lecture03 ├── advanced │ ├── style.css │ ├── index.html │ ├── chugaev │ │ └── index.html │ └── spesivtsev │ │ └── index.html └── basic │ ├── index.html │ ├── chugaev │ └── index.html │ ├── trebunskih │ ├── css │ │ └── style.css │ └── index.html │ ├── Puchkov │ └── index2.html │ ├── kuznetsov │ └── index.html │ ├── Ankudinova-basic-lecture03 │ └── index.html │ ├── gladkov │ └── index.html │ ├── Harin │ └── index.html │ └── britvin │ └── index.html ├── lecture05 └── index.js ├── package.json ├── index.html ├── lecture07 ├── chugaev │ └── index.php └── index.php ├── lecture06 └── index.php ├── script.js └── README.md /style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .DS_Store 3 | 4 | node_modules 5 | package-lock.json -------------------------------------------------------------------------------- /practice-01/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /practice-01/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-chugaev/teach-web/HEAD/practice-01/app/favicon.ico -------------------------------------------------------------------------------- /lecture02/advanced/chugaev/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-chugaev/teach-web/HEAD/lecture02/advanced/chugaev/graph.png -------------------------------------------------------------------------------- /lecture02/basic/trebunskih/Saiky.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-chugaev/teach-web/HEAD/lecture02/basic/trebunskih/Saiky.png -------------------------------------------------------------------------------- /lecture04/basic/trebunskih/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-chugaev/teach-web/HEAD/lecture04/basic/trebunskih/graph.png -------------------------------------------------------------------------------- /practice-01/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /lecture02/advanced/spesivtsev/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-chugaev/teach-web/HEAD/lecture02/advanced/spesivtsev/graph.png -------------------------------------------------------------------------------- /practice-01/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m-chugaev/teach-web/HEAD/lecture04/basic/kuznetsov/assets/avatar.png -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/style.scss: -------------------------------------------------------------------------------- 1 | @import 'abstracts/vars'; 2 | @import 'abstracts/common'; 3 | 4 | @import 'components/button'; 5 | 6 | @import 'sections/graph'; -------------------------------------------------------------------------------- /practice-02/components/randomQuestionNotice/index.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /lecture02/advanced/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: PT Sans, sans-serif; 3 | color: #464646; 4 | background-color: #eee; 5 | padding: 16px; 6 | margin: 0 auto; 7 | width: 100%; 8 | max-width: 1100px; 9 | } -------------------------------------------------------------------------------- /lecture03/advanced/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: PT Sans, sans-serif; 3 | color: #464646; 4 | background-color: #eee; 5 | padding: 16px; 6 | margin: 0 auto; 7 | width: 100%; 8 | max-width: 1100px; 9 | } -------------------------------------------------------------------------------- /lecture04/basic/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: PT Sans, sans-serif; 3 | color: #464646; 4 | background-color: #eee; 5 | padding: 16px; 6 | margin: 0 auto; 7 | width: 100%; 8 | max-width: 1100px; 9 | } -------------------------------------------------------------------------------- /practice-02/api/getQuestionOfDay.php: -------------------------------------------------------------------------------- 1 | getQuestionOfDay(); 7 | $service->renderResult($questionOfDay); 8 | -------------------------------------------------------------------------------- /practice-01/app/page.module.scss: -------------------------------------------------------------------------------- 1 | .main { 2 | width: 100%; 3 | max-width: 1100px; 4 | padding: 16px; 5 | margin: 0 auto; 6 | } 7 | 8 | .icon { 9 | position: fixed; 10 | right: 16px; 11 | bottom: 16px; 12 | z-index: 10; 13 | } -------------------------------------------------------------------------------- /practice-02/api/getRandomQuestion.php: -------------------------------------------------------------------------------- 1 | getRandomQuestion(); 7 | $service->renderResult($question); 8 | 9 | -------------------------------------------------------------------------------- /practice-02/services/SessionManager.php: -------------------------------------------------------------------------------- 1 | 2 |

Вопрос дня (Задание 13)

3 | 4 |
5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /lecture02/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Best 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lecture03/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Best 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lecture05/index.js: -------------------------------------------------------------------------------- 1 | import { Chugaev } from 'chugaev-lecture04' 2 | const chugaev = new Chugaev('Сделал задание 4 лекции.'); 3 | chugaev.checkIn(); 4 | 5 | import { SecondName } from 'spesivtsev' 6 | const person = new SecondName('Спесивцев', 'Привет!'); 7 | person.checkIn(); -------------------------------------------------------------------------------- /practice-02/services/RandomSmileService.php: -------------------------------------------------------------------------------- 1 | getRandomQuestions(); 7 | header('Content-Type: application/json'); 8 | echo json_encode($randomQuestions); -------------------------------------------------------------------------------- /lecture04/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /practice-02/api/getSimpleRandomQuestionsHistory.php: -------------------------------------------------------------------------------- 1 | getRequestsHistory(); 10 | $service->renderResult($history); -------------------------------------------------------------------------------- /practice-02/services/RenderResultTrait.php: -------------------------------------------------------------------------------- 1 | saveRequest(); 10 | $randomQuestions = $service->getRandomQuestions(); 11 | $service->renderResult($randomQuestions); -------------------------------------------------------------------------------- /practice-02/components/randomQuestionFrequency/index.php: -------------------------------------------------------------------------------- 1 |
2 |

Список 5 вопросов с разной частотой выпадения (4 задание)

3 | 4 |
    5 |
    6 | 7 |
    8 | 9 | 10 |
    -------------------------------------------------------------------------------- /practice-02/api/getQuestionsByIds.php: -------------------------------------------------------------------------------- 1 | validateQuery($_GET); 8 | 9 | if (isset($validate['error'])) { 10 | $service->renderResult($validate); 11 | exit; 12 | } 13 | 14 | $result = $service->getQuestionsByIds($validate['ids']); 15 | 16 | $service->renderResult($result); -------------------------------------------------------------------------------- /practice-02/components/TextValidator/index.php: -------------------------------------------------------------------------------- 1 |
    2 |

    Проверка текста

    3 | 4 |
    5 | 6 | 7 |
    8 | 9 |
    10 | 11 | 12 |
    13 | -------------------------------------------------------------------------------- /lecture04/advanced/index.js: -------------------------------------------------------------------------------- 1 | import { Chugaev } from 'chugaev-lecture04' 2 | 3 | const chugaev = new Chugaev('Сделал задание 4 лекции.'); 4 | chugaev.checkIn(); 5 | 6 | // Богатырев 7 | // Сорокин 8 | // Черенева 9 | // Саилов 10 | import { SecondName } from 'spesivtsev' 11 | 12 | const person = new SecondName('Спесивцев', 'Привет!'); 13 | person.checkIn(); 14 | // Булгаков 15 | // Голубчикова 16 | // Михалев 17 | // Рычин 18 | // Пучков 19 | // Помаскин -------------------------------------------------------------------------------- /practice-02/api/checkEmail.php: -------------------------------------------------------------------------------- 1 | save(); 16 | $check = $service->checkEmail(); // Здесь возвращаем итог строчку 17 | $service->renderResult($check); // Сюда передаём итог строчку -------------------------------------------------------------------------------- /practice-02/api/getQuestions.php: -------------------------------------------------------------------------------- 1 | getPaginatedQuestions($page, $pageSize); 13 | 14 | $service->renderResult($result); -------------------------------------------------------------------------------- /practice-02/api/validateText.php: -------------------------------------------------------------------------------- 1 | $isValid]); 12 | } else { 13 | echo json_encode(['error' => 'Недопустимый запрос']); 14 | } 15 | ?> 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "teach-web", 3 | "version": "1.0.0", 4 | "type": "module", 5 | "description": "Репозиторий для изучения web-разработки", 6 | "scripts": { 7 | "lecture04": "node lecture04/advanced/index.js", 8 | "lecture05": "node lecture05/index.js" 9 | }, 10 | "dependencies": { 11 | "chugaev-lecture04": "github:m-chugaev/lecture04-lib", 12 | "spesivtsev": "github:AfordiumSX/lecture4" 13 | }, 14 | "license": "ISC" 15 | } 16 | -------------------------------------------------------------------------------- /practice-02/components/simpleRandom/index.php: -------------------------------------------------------------------------------- 1 |
    2 |

    Простой список случайных вопросов (1 задание)

    3 | 4 |
      5 |
      6 | 7 | 8 |
      9 | 10 | 11 |
      12 | -------------------------------------------------------------------------------- /practice-01/app/layout.js: -------------------------------------------------------------------------------- 1 | import { Inter } from "next/font/google"; 2 | import "./globals.css"; 3 | 4 | const inter = Inter({ subsets: ["latin"] }); 5 | 6 | export const metadata = { 7 | title: "Questions App", 8 | description: "Приложение для проведения собеседования", 9 | }; 10 | 11 | export default function RootLayout({ children }) { 12 | return ( 13 | 14 | {children} 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /practice-01/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "practice-01", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "14.1.0", 13 | "react": "^18", 14 | "react-dom": "^18", 15 | "sass": "^1.71.1" 16 | }, 17 | "devDependencies": { 18 | "eslint": "^8", 19 | "eslint-config-next": "14.1.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /practice-02/components/randomQuestionNotice/notifications.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', (event) => { 2 | function fetchRandomQuestion() { 3 | fetch('/practice-02/api/getRandomQuestion.php') 4 | .then(response => response.json()) 5 | .then(encodedQuestion => { 6 | showNotice(encodedQuestion); 7 | }) 8 | .catch(error => console.error('Ошибка:', error)); 9 | } 10 | 11 | setTimeout(() => { 12 | fetchRandomQuestion(); 13 | }, 1000); 14 | }); -------------------------------------------------------------------------------- /practice-02/services/RandomQuestionService.php: -------------------------------------------------------------------------------- 1 | getQuestionsText(); 16 | $randomKey = array_rand($all); 17 | return $all[$randomKey]; 18 | } 19 | } -------------------------------------------------------------------------------- /practice-01/app/globals.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; 4 | margin: 0; 5 | } 6 | 7 | html, 8 | body { 9 | max-width: 100vw; 10 | overflow-x: hidden; 11 | } 12 | 13 | body { 14 | font-family: PT Sans, sans-serif; 15 | color: #464646; 16 | background-color: #eee; 17 | } 18 | 19 | a { 20 | color: inherit; 21 | text-decoration: none; 22 | } 23 | 24 | .dark { 25 | background-color: #333; 26 | color: #fff; 27 | } 28 | 29 | .light { 30 | background-color: #fff; 31 | color: #333; 32 | } 33 | -------------------------------------------------------------------------------- /practice-02/components/checkEmail/script.js: -------------------------------------------------------------------------------- 1 | // fetch to /api/checkEmail 2 | // handle result 3 | 4 | (function (){ 5 | const form = document.querySelector('.formEmail_js'); 6 | form.addEventListener('submit', async (event) => { 7 | event.preventDefault(); 8 | 9 | fetch(API_BASE_URL + 'checkEmail.php', { 10 | method: 'POST', 11 | body: (new FormData(form)) 12 | }) 13 | .then((response) => response.json()) 14 | .then((text) => showNotice(text)) 15 | }); 16 | })() -------------------------------------------------------------------------------- /practice-02/components/questions/index.php: -------------------------------------------------------------------------------- 1 |
      2 |

      Вопросы для собеседования

      3 |
        4 |
        5 |
        6 |
        7 | 8 | 9 |
        10 | 11 |
        12 | -------------------------------------------------------------------------------- /practice-01/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /lecture02/basic/chugaev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Chugaev 7 | 8 | 9 |

        Основные теги

        10 |
        11 | 12 |
        block
        13 | inline 14 | 15 | 16 | -------------------------------------------------------------------------------- /lecture02/advanced/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /lecture03/advanced/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | All 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /practice-02/api/addQuestion.php: -------------------------------------------------------------------------------- 1 | addQuestion($newQuestion); 13 | 14 | $page = isset($_GET['page']) ? (int)$_GET['page'] : 1; 15 | $pageSize = isset($_GET['pageSize']) ? (int)$_GET['pageSize'] : 10; 16 | 17 | $result = $questionsService->getPaginatedQuestions($page, $pageSize); 18 | $questionsService->renderResult($result); -------------------------------------------------------------------------------- /lecture04/basic/chugaev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chugaev 8 | 9 | 10 |
        11 |

        Chugaev

        12 |
        13 | 14 |
        15 | 18 | 21 |
        22 | 23 | -------------------------------------------------------------------------------- /practice-02/components/questionsByIds/index.php: -------------------------------------------------------------------------------- 1 |
        2 |

        Вопросы по идентификатору (17 задание)

        3 | 4 |
          5 |
            6 |
            7 |
            8 | 9 | 10 |
            11 |
            12 | 13 | 14 |
            15 | -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/abstracts/_common.scss: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=PT+Sans:regular,italic,700,700italic); 2 | 3 | body { 4 | font-family: 'PT Sans', sans-serif; 5 | background-color: var(--color-gray); 6 | color: var(--color-font-black); 7 | } 8 | 9 | 10 | *, 11 | *::before, 12 | *::after { 13 | box-sizing: border-box; 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | .container { 19 | padding: 0 12px; 20 | margin: 0 auto; 21 | max-width: 1100px; 22 | } 23 | 24 | .svg-icon { 25 | fill: currentColor; 26 | width: 24px; 27 | height: 24px; 28 | } -------------------------------------------------------------------------------- /practice-02/components/checkEmail/index.php: -------------------------------------------------------------------------------- 1 | getLatest(); 10 | ?> 11 | 12 |
            13 |

            Чекни свой email

            14 |
            15 |
            16 | Email: 17 | 18 |
            19 |
            20 | 21 | 22 |
            -------------------------------------------------------------------------------- /practice-01/components/JokeNotice/JokeNotice.module.scss: -------------------------------------------------------------------------------- 1 | .notice { 2 | position: fixed; 3 | top: 20px; 4 | right: 20px; 5 | background-color: #007bff; /* Синий цвет фона */ 6 | color: #fff; /* Белый цвет текста */ 7 | padding: 15px; 8 | border-radius: 10px; 9 | animation: slideIn 0.5s ease-out forwards; /* Анимация появления */ 10 | box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2); /* Тень */ 11 | z-index: 1000; /* Поднимаем над другими элементами */ 12 | } 13 | 14 | @keyframes slideIn { 15 | from { 16 | opacity: 0; 17 | transform: translateY(-50px); /* Начальное положение */ 18 | } 19 | to { 20 | opacity: 1; 21 | transform: translateY(0); /* Конечное положение */ 22 | } 23 | } -------------------------------------------------------------------------------- /practice-01/components/Comment/Comment.module.scss: -------------------------------------------------------------------------------- 1 | // Comment.module.scss 2 | .container { 3 | border: 1px solid #ccc; 4 | padding: 20px; 5 | max-width: 600px; 6 | margin: 20px auto 0; 7 | } 8 | 9 | .title { 10 | margin-top: 0; 11 | margin-bottom: 10px; 12 | font-size: 1.5rem; 13 | } 14 | 15 | .comments { 16 | margin-bottom: 20px; 17 | } 18 | 19 | .comment { 20 | margin-bottom: 10px; 21 | } 22 | 23 | .textarea { 24 | width: 100%; 25 | height: 100px; 26 | margin-bottom: 10px; 27 | } 28 | 29 | .button { 30 | padding: 10px 20px; 31 | background-color: #007bff; 32 | color: #fff; 33 | border: none; 34 | border-radius: 5px; 35 | cursor: pointer; 36 | } 37 | 38 | .button:hover { 39 | background-color: #0056b3; 40 | } 41 | -------------------------------------------------------------------------------- /practice-02/components/questionsOfDay/script.js: -------------------------------------------------------------------------------- 1 | 2 | function getQuestionOfDay() { 3 | return fetch('/practice-02/api/getQuestionOfDay.php') 4 | .then((response) => { 5 | return response.json(); 6 | }); 7 | } 8 | 9 | function fillQuestionOfDay() { 10 | const container = document.getElementById("questionOfDay"); 11 | 12 | if (!container) { 13 | console.error('Ошибка! Не удалось найти контейнер для вопроса дня.'); 14 | return; 15 | } 16 | 17 | getQuestionOfDay() 18 | .then((question) => { 19 | container.innerText = question; 20 | }) 21 | .catch((error) => { 22 | console.error('Произошла ошибка при получении вопроса дня:', error); 23 | }); 24 | } 25 | 26 | window.onload = fillQuestionOfDay; 27 | -------------------------------------------------------------------------------- /lecture03/basic/chugaev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Chugaev 7 | 8 | 9 |

            Основные CSS свойства

            10 |
            11 | Список всех CSS свойств 12 | 13 | 26 | 27 | -------------------------------------------------------------------------------- /practice-02/services/CheckEmailService.php: -------------------------------------------------------------------------------- 1 | email = $email; 15 | } 16 | 17 | public function checkEmail(): string 18 | { 19 | if (filter_var($this->email, FILTER_VALIDATE_EMAIL)) { 20 | return "Контакт сохранен"; 21 | } else { 22 | return "Ошибка валидации email"; 23 | } 24 | } 25 | 26 | public function getLatest(): string 27 | { 28 | return $_SESSION[self::SESSION_KEY] ?? ""; 29 | } 30 | 31 | public function save(): void 32 | { 33 | $_SESSION[self::SESSION_KEY] = $this->email; 34 | } 35 | } 36 | ?> -------------------------------------------------------------------------------- /practice-01/components/RandomQuestionsFrequency/RandomQuestionsFrequency.module.scss: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | border: 1px solid #ccc; 3 | max-width: 800px; 4 | margin: 20px auto 0; 5 | text-align: center; /* Центрирование содержимого по горизонтали */ 6 | } 7 | 8 | .container { 9 | text-align: center; 10 | padding: 20px; 11 | margin-top: 10px; 12 | } 13 | 14 | .header { 15 | font-weight: bold; 16 | margin-bottom: 10px; 17 | font-size: 1.5rem; 18 | } 19 | 20 | .button { 21 | padding: 10px 20px; 22 | background-color: #007bff; 23 | color: #fff; 24 | border: none; 25 | border-radius: 5px; 26 | cursor: pointer; 27 | margin-top: 10px; 28 | } 29 | 30 | .button:hover { 31 | background-color: #0056b3; 32 | } 33 | 34 | .list { 35 | margin-top: 20px; 36 | text-align: left; 37 | } 38 | 39 | .item { 40 | margin-top: 10px; 41 | } 42 | -------------------------------------------------------------------------------- /practice-01/components/SwitchTheme/index.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useState, useEffect } from "react"; 3 | import styles from "./SwitchTheme.module.scss"; 4 | 5 | export default function SwitchTheme() { 6 | const [theme, setTheme] = useState("light"); 7 | 8 | useEffect(() => { 9 | const savedTheme = localStorage.getItem("theme"); 10 | if (savedTheme) { 11 | setTheme(savedTheme); 12 | } 13 | }, []); 14 | 15 | const toggleTheme = () => { 16 | const newTheme = theme === "light" ? "dark" : "light"; 17 | setTheme(newTheme); 18 | localStorage.setItem("theme", newTheme); 19 | }; 20 | 21 | useEffect(() => { 22 | document.body.className = theme; 23 | }, [theme]); 24 | 25 | return ( 26 |
            27 | 30 |
            31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /practice-01/components/RandomQuestionsList/RandomQuestionsList.module.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | border: 1px solid #ccc; 3 | padding: 20px; 4 | max-width: 800px; 5 | margin: 20px auto 0; 6 | text-align: center; /* Выравнивание заголовков по центру */ 7 | } 8 | 9 | .title { 10 | font-size: 1.5rem; 11 | margin-bottom: 20px; 12 | } 13 | 14 | .button { 15 | padding: 10px 20px; 16 | background-color: #007bff; 17 | color: #fff; 18 | border: none; 19 | border-radius: 5px; 20 | cursor: pointer; 21 | } 22 | 23 | .button:hover { 24 | background-color: #0056b3; 25 | } 26 | 27 | .list { 28 | margin-top: 20px; /* Добавлен отступ сверху для контейнера с вопросами */ 29 | text-align: left; /* Выравнивание рандомных вопросов по левому краю */ 30 | } 31 | 32 | .history { 33 | margin-top: 20px; 34 | } 35 | 36 | .history h2 { 37 | margin-bottom: 10px; 38 | } 39 | 40 | .history ol { 41 | text-align: left; /* Выравнивание текста в списке по левому краю */ 42 | } 43 | -------------------------------------------------------------------------------- /practice-02/services/RandomQuestionFrequency.php: -------------------------------------------------------------------------------- 1 | count = $count; 15 | } 16 | 17 | public function getRandomQuestions(): array 18 | { 19 | $questionsService = new QuestionsService(); 20 | $questionFrequencies = $questionsService->calculateQuestionFrequencies(); 21 | $weightedQuestions = []; 22 | 23 | foreach ($questionFrequencies as $question => $frequency) { 24 | for ($i = 0; $i < $frequency; $i++) { 25 | $weightedQuestions[] = $question; 26 | } 27 | } 28 | 29 | shuffle($weightedQuestions); 30 | 31 | $selectedQuestions = array_slice($weightedQuestions, 0, $this->count); 32 | 33 | return $selectedQuestions; 34 | } 35 | } -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/components/_button.scss: -------------------------------------------------------------------------------- 1 | .base-button { 2 | padding: 0; 3 | background-color: transparent; 4 | border-radius: 0; 5 | border: none; 6 | text-align: inherit; 7 | outline: 0; 8 | display: inline-flex; 9 | align-items: center; 10 | justify-content: center; 11 | color: inherit; 12 | cursor: pointer; 13 | } 14 | 15 | .base-button--size-l { 16 | padding: 7px 15px; 17 | min-height: 36px; 18 | font-weight: 700; 19 | font-size: 16px; 20 | line-height: 20px; 21 | } 22 | 23 | .base-button--appearance-extra { 24 | border-radius: 4px; 25 | background: transparent; 26 | color: var(--color-gray-3); 27 | font-weight: 700; 28 | border: 1px solid var(--color-ui-gray-bg); 29 | } 30 | 31 | .base-dropdown__toggle>* { 32 | cursor: pointer; 33 | } 34 | 35 | .base-button--appearance-extra:hover { 36 | background-color: var(--color-gray-light-2); 37 | } 38 | .base-button:hover { 39 | text-decoration: none; 40 | } -------------------------------------------------------------------------------- /practice-01/components/QuestionNotice/index.js: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import React, {useState} from 'react'; 3 | import questions from '@/questions'; 4 | 5 | const QuestionNotice = () => { 6 | const [showNotice, setShowNotice] = useState(true); 7 | const randomIndex = Math.floor(Math.random() * questions.length); 8 | const question = questions[randomIndex].text; 9 | 10 | React.useEffect(() => { 11 | const timer = setTimeout(() => { 12 | setShowNotice(false); 13 | }, 5000); 14 | 15 | return () => clearTimeout(timer); 16 | }, []); 17 | 18 | return ( 19 |
            32 | {question} 33 |
            34 | ); 35 | }; 36 | 37 | export default QuestionNotice; -------------------------------------------------------------------------------- /lecture02/basic/kuznetsov/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | kuznetsov 7 | 8 | 9 |
            10 | 11 |

            Текст абзаца

            12 | 13 | 14 | 15 | 16 | Видево прикол 19 | 20 |
            21 | 22 |
          1. Элемент списка
          2. 23 | 24 |
            block
            25 | inline 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /practice-01/components/RandomQuestions/RandomQuestions.module.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | border: 1px solid #ccc; 3 | padding: 20px; 4 | max-width: 800px; /* Увеличение максимальной ширины контейнера */ 5 | margin: 20px auto 0; 6 | } 7 | 8 | .wrapper { 9 | margin-bottom: 20px; /* Отступ снизу блока wrapper */ 10 | } 11 | 12 | .title { 13 | font-size: 1.5rem; 14 | margin-bottom: 20px; 15 | } 16 | 17 | .form { 18 | display: flex; 19 | } 20 | 21 | .input { 22 | flex: 1; 23 | padding: 10px; 24 | border: 1px solid #ccc; 25 | border-radius: 5px; 26 | margin-right: 10px; 27 | } 28 | 29 | .button { 30 | padding: 10px 20px; 31 | background-color: #007bff; 32 | color: #fff; 33 | border: none; 34 | border-radius: 5px; 35 | cursor: pointer; 36 | } 37 | 38 | .button:hover { 39 | background-color: #0056b3; 40 | } 41 | 42 | .result { 43 | margin-top: 20px; /* Отступ сверху блока result */ 44 | } 45 | 46 | .result h3 { 47 | margin-bottom: 10px; /* Отступ снизу заголовка */ 48 | } 49 | 50 | .result ol { 51 | padding-left: 20px; 52 | } -------------------------------------------------------------------------------- /practice-02/services/SimpleRandomQuestionsService.php: -------------------------------------------------------------------------------- 1 | count = $count; 21 | } 22 | 23 | public function getRandomQuestions(): array 24 | { 25 | $all = (new QuestionsService)->getQuestionsText(); 26 | 27 | return array_rand(array_flip($all), $this->count); 28 | } 29 | 30 | public function getRequestsHistory(): array 31 | { 32 | return $_SESSION[self::SESSION_KEY] ?? []; 33 | } 34 | 35 | public function saveRequest(): void 36 | { 37 | $current = $this->getRequestsHistory(); 38 | $current[] = date('Y-m-d H:i:s'); 39 | $_SESSION[self::SESSION_KEY] = $current; 40 | } 41 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | WEB Development 10 | 11 | 12 |

            Вопросы для собеседования

            13 | 14 |
              15 | 16 |
              17 |

              Случайные вопросы

              18 |
                19 | 20 |
                21 | 22 | 23 | 24 | 25 |
                26 |
                27 | 28 | -------------------------------------------------------------------------------- /practice-02/components/TextValidator/script.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const form = document.getElementById('textValidatorForm'); 3 | const textInput = document.getElementById('textInput'); 4 | const validationResult = document.getElementById('validationResult'); 5 | 6 | form.addEventListener('submit', function (event) { 7 | console.log('sdfsdfsfd'); 8 | event.preventDefault(); 9 | 10 | const text = textInput.value.trim(); 11 | 12 | fetch(API_BASE_URL + 'validateText.php', { 13 | method: 'POST', 14 | body: JSON.stringify({ text: text }), 15 | headers: { 16 | 'Content-Type': 'application/json' 17 | } 18 | }) 19 | .then(response => response.json()) 20 | .then(data => { 21 | if (data.valid) { 22 | showNotice('Успешно', 'Текст корректен'); 23 | } else { 24 | showNotice('Ошибка', 'Текст содержит недопустимые символы'); 25 | } 26 | }) 27 | .catch(error => { 28 | console.error('Ошибка:', error); 29 | }); 30 | }); 31 | }()); 32 | -------------------------------------------------------------------------------- /practice-01/components/JokeNotice/index.js: -------------------------------------------------------------------------------- 1 | 'use client' 2 | // components/JokeNotice.js 3 | import styles from './JokeNotice.module.scss'; 4 | import React, { useState, useEffect } from 'react'; 5 | 6 | const jokes = [ 7 | 'Почему программисты так не любят пляж? Потому что в нем есть много багов!', 8 | 'Какой JavaScript-фреймворк самый быстрый? Ответ: React, потому что он всегда в состоянии!', 9 | 'Что говорит один HTML-элемент другому? "Ты выглядишь как div!"', 10 | 'Как программисты проводят выходные? В своем коде!', 11 | 'Знаете ли вы, почему не можем использовать фоновую музыку в коде? Потому что код постоянно находится в цикле!' 12 | ]; 13 | 14 | const JokeNotice = () => { 15 | const [showNotice, setShowNotice] = useState(true); 16 | const joke = jokes[Math.floor(Math.random() * jokes.length)]; 17 | 18 | useEffect(() => { 19 | const timer = setTimeout(() => { 20 | setShowNotice(false); 21 | }, 5000); // Уведомление исчезнет через 5 секунд 22 | 23 | return () => clearTimeout(timer); 24 | }, []); 25 | 26 | return ( 27 |
                28 | {joke} 29 |
                30 | ); 31 | }; 32 | 33 | export default JokeNotice; -------------------------------------------------------------------------------- /lecture07/chugaev/index.php: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Form 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
                22 | 23 | 24 | 29 | 30 | 31 |
                32 | 33 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /practice-01/public/icons/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /practice-01/components/Timer/index.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect, useState } from 'react'; 4 | 5 | export default function Timer() { 6 | const [time, setTime] = useState(300); 7 | const [isRunning, setIsRunning] = useState(false); 8 | 9 | useEffect(() => { 10 | if (isRunning) { 11 | const timer = setInterval(() => { 12 | setTime(prevTime => prevTime - 1); 13 | }, 1000); 14 | 15 | return () => clearInterval(timer); 16 | } 17 | }, [isRunning]); 18 | 19 | useEffect(() => { 20 | if (time === 0) { 21 | alert('Таймер закончился'); 22 | const resetTimer = window.confirm('Хотите сбросить таймер к 5 минутам?'); 23 | if (resetTimer) { 24 | setTime(300); 25 | setIsRunning(false); 26 | } 27 | } 28 | }, [time]); 29 | 30 | const handleToggle = () => { 31 | setIsRunning(prevIsRunning => !prevIsRunning); 32 | }; 33 | const resetTime = () => { 34 | setTime(300); 35 | setIsRunning(false); 36 | }; 37 | 38 | return ( 39 |
                40 |

                {Math.floor(time / 60)}:{(time % 60).toString().padStart(2, '0')}

                41 | 42 | 43 |
                44 | ); 45 | }; -------------------------------------------------------------------------------- /practice-01/app/page.js: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | import styles from "./page.module.scss"; 3 | import Questions from '../components/Questions'; 4 | import RandomQuestionsList from '../components/RandomQuestionsList'; 5 | import JokeNotice from '../components/JokeNotice'; 6 | import QuestionNotice from '../components/QuestionNotice'; 7 | import RandomQuestions from '../components/RandomQuestions'; 8 | import RandomQuestionsFrequency from '../components/RandomQuestionsFrequency'; 9 | import Comment from '../components/Comment/Comment'; 10 | import SwitchTheme from "../components/SwitchTheme"; 11 | import Random5Questions from "@/components/Top5dieFive"; 12 | import QuestionOfTheDay from "@/components/QuestionOfTheDay"; 13 | import Timer from "@/components/Timer" 14 | 15 | export default function Home() { 16 | return ( 17 |
                18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Next.js 36 | 37 |
                38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /practice-01/components/Top5dieFive/Five.module.scss: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | border: 1px solid #ccc; 3 | padding: 20px; 4 | max-width: 800px; /* Увеличение максимальной ширины контейнера */ 5 | margin: 20px auto 0; 6 | } 7 | 8 | .title { 9 | text-align: center; /* Центрирование текста */ 10 | font-size: 1.5rem; /* Установка размера шрифта */ 11 | } 12 | 13 | .button_1 { 14 | color: #ffffff; // Изменение цвета текста кнопки на белый 15 | background-color: #007bff; // Изменение цвета фона кнопки 16 | padding: 10px 20px; 17 | border: none; 18 | border-radius: 10px; 19 | cursor: pointer; 20 | transition: background-color 0.3s ease; // Плавное изменение цвета фона при наведении 21 | } 22 | 23 | .button_1:hover { 24 | background-color: #0056b3; // Изменение цвета фона кнопки при наведении 25 | } 26 | 27 | .button_2 { 28 | color: #ffffff; // Изменение цвета текста кнопки на белый 29 | background-color: #dc3545; // Изменение цвета фона кнопки 30 | padding: 10px 20px; 31 | border: none; 32 | border-radius: 10px; 33 | cursor: pointer; 34 | transition: background-color 0.3s ease; // Плавное изменение цвета фона при наведении 35 | } 36 | 37 | .button_2:hover { 38 | background-color: #bd2130; // Изменение цвета фона кнопки при наведении 39 | } 40 | 41 | .container { 42 | display: flex; 43 | justify-content: center; 44 | gap: 20px; /* Отступ между кнопками */ 45 | margin-bottom: 20px; 46 | margin-top: 20px; 47 | } 48 | -------------------------------------------------------------------------------- /practice-02/services/QuestionOfDayService.php: -------------------------------------------------------------------------------- 1 | getQuestionsText(); 22 | foreach ($all_questions as $question) { 23 | if (!in_array($question, $_SESSION['shown_questions'])) { 24 | $question_of_day = $question; 25 | break; 26 | } 27 | } 28 | if ($question_of_day === null) { 29 | $_SESSION['shown_questions'] = array(); 30 | $question_of_day = $all_questions[0]; 31 | } 32 | $_SESSION['last_question_date'] = $today; 33 | $_SESSION['shown_questions'][] = $question_of_day; 34 | } else { 35 | $question_of_day = $_SESSION['shown_questions'][count($_SESSION['shown_questions']) - 1]; 36 | } 37 | 38 | return $question_of_day; 39 | } 40 | } 41 | ?> 42 | -------------------------------------------------------------------------------- /practice-01/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /practice-02/services/QuestionsByIdsService.php: -------------------------------------------------------------------------------- 1 | getQuestions(); 12 | 13 | $questions = []; 14 | $missingIds = []; 15 | 16 | foreach ($ids as $id) { 17 | $index = $id - 1; 18 | 19 | if (isset($all[$index])) { 20 | $questions[] = $all[$index]; 21 | } else { 22 | $missingIds[] = $id; 23 | } 24 | } 25 | 26 | return [ 27 | 'questions' => $questions, 28 | 'missing_ids' => $missingIds, 29 | ]; 30 | } 31 | 32 | public function validateQuery(mixed $params): mixed 33 | { 34 | $idsParam = isset($params['ids']) ? $params['ids'] : ''; 35 | 36 | if (empty($idsParam)) { 37 | return ['error' => 'Идентификаторы не найдены']; 38 | } 39 | 40 | $ids = array_map('intval', explode(',', $idsParam)); 41 | 42 | foreach ($ids as $id) { 43 | if ($id <= 0) { 44 | return ['error' => 'Идентификаторы должны быть положительными числами']; 45 | } 46 | } 47 | 48 | return [ 49 | 'success' => true, 50 | 'ids' => $ids 51 | ]; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /practice-02/components/randomQuestionFrequency/script.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | function getRandomQuestionFrequency() { 3 | return fetch(API_BASE_URL + 'getRandomQuestionFrequency.php') 4 | .then((response) => { 5 | return response.json(); 6 | }); 7 | } 8 | 9 | function fillRandomQuestionFrequency() { 10 | const container = document.querySelector('.js-random-question-frequency'); 11 | 12 | if (!container) { 13 | console.error('Ошибка! Не удалось найти элемент .js-random-question-frequency на странице.'); 14 | return; 15 | } 16 | 17 | getRandomQuestionFrequency() 18 | .then((questions) => { 19 | container.innerHTML = ''; 20 | questions.forEach((question) => { 21 | const node = document.createElement("li"); 22 | node.textContent = question; 23 | container.appendChild(node); 24 | }); 25 | }) 26 | .catch((error) => { 27 | console.error('Произошла ошибка при получении вопросов:', error); 28 | }); 29 | } 30 | 31 | function listenButtons() { 32 | const buttonAll = document.querySelector('.js-question-frequency'); 33 | 34 | if (!buttonAll) { 35 | console.error('Ошибка! Не удалось найти элементы .js-question-frequency на странице.'); 36 | return; 37 | } 38 | 39 | buttonAll.addEventListener('click', fillRandomQuestionFrequency); 40 | } 41 | 42 | listenButtons(); 43 | }()); -------------------------------------------------------------------------------- /practice-02/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | WEB Development 12 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /practice-01/components/RandomQuestions/index.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import styles from './RandomQuestions.module.scss'; 4 | import questions from "../../questions.js" 5 | import React from 'react'; 6 | 7 | export default function RandomQuestions() { 8 | const [randomQuestions, setRandomQuestions] = React.useState([]); 9 | 10 | const handleSubmit = (e) => { 11 | e.preventDefault(); 12 | const formData = new FormData(e.currentTarget); 13 | const count = formData.get('count'); 14 | 15 | const randomQuestions = questions 16 | .sort(() => Math.random() - 0.5) 17 | .slice(0, count); 18 | 19 | setRandomQuestions(randomQuestions); 20 | } 21 | 22 | return ( 23 |
                24 |
                25 |

                Генератор определённого количества вопросов

                26 |
                27 | 28 | 29 |
                30 |
                31 | {randomQuestions.length > 0 && ( 32 |
                33 |

                Сгенерированные вопросы:

                34 |
                  35 | {randomQuestions.map((question, index) => ( 36 |
                1. {question.text}
                2. 37 | ))} 38 |
                39 |
                40 | )} 41 |
                42 | ); 43 | } -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/abstracts/_vars.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --color-white: #fff; 3 | --color-gray: #eee; 4 | --color-gray-light: #c4c4c4; 5 | --color-gray-dark: #999; 6 | --color-gray-light-2: #f4f4f4; 7 | --color-gray-light-3: #e4e4e4; 8 | --color-gray-3: #4d5057; 9 | --color-icon-gray: #929ca5; 10 | --color-icon-purple: #a876d0; 11 | --color-icon-purple-light: #c09cdd; 12 | --color-ui-gray-bg: #ededed; 13 | --color-ui-checkbox-bg: #666; 14 | --color-ui-lightgray: #f7f7f7; 15 | --color-link-blue: #1463d9; 16 | --color-ui-blue: #5677fc; 17 | --color-ui-blue-overlay: rgba(86, 119, 252, .12); 18 | --color-font-black: #464646; 19 | --color-font-gray: #757575; 20 | --color-ui-red: #d34c09; 21 | --color-ui-red-overlay: rgba(211, 76, 9, .12); 22 | --color-ui-red-second: #ff7e75; 23 | --color-ui-green: #64c178; 24 | --color-ui-green-overlay: rgba(100, 193, 120, .12); 25 | --color-ui-yellow: #e8a700; 26 | --color-ui-orange: #f9a21f; 27 | --color-ui-yellow-overlay: rgba(232, 167, 0, .12); 28 | --color-green: #0c8326; 29 | --color-ui-overlay: rgba(70, 70, 70, .5); 30 | --color-input-focus: #f5f6f7; 31 | --color-light-purple: #dbdbff; 32 | --color-light-purple2: #8F7BF6; 33 | --color-button-range-active: #be86eb; 34 | --color-chip-bg-inactive: #ebf3ff; 35 | --color-chip-bg-hover: #d1e4ff; 36 | --color-chip-bg-press: #b8d5ff; 37 | --color-chip-border: #a3c4f5; 38 | --color-bar-blueviolet: #9f8cfa; 39 | --color-blueviolet-gradient: linear-gradient(90deg, #b09fff 0%, #8d79f6 100%); 40 | --color-bar-grey: rgba(237, 237, 237, .6); 41 | --color-toggle-border: #9783fc; 42 | } -------------------------------------------------------------------------------- /practice-01/components/QuestionOfTheDay/index.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import React, { useState, useEffect } from 'react'; 3 | import questions from "@/questions"; 4 | 5 | const QuestionOfTheDay = () => { 6 | const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); 7 | const [currentQuestion, setCurrentQuestion] = useState(''); 8 | 9 | useEffect(() => { 10 | const storedIndex = localStorage.getItem('questionIndex'); 11 | const storedDate = localStorage.getItem('lastUpdateDate'); 12 | 13 | if (storedIndex !== null && storedDate !== null) { 14 | const storedDateTime = new Date(storedDate).getTime(); 15 | const currentDateTime = new Date().getTime(); 16 | 17 | if (currentDateTime - storedDateTime > (1000 * 60 * 60 * 24)) { 18 | const newIndex = (parseInt(storedIndex) + 1) % questions.length; 19 | setCurrentQuestionIndex(newIndex); 20 | setCurrentQuestion(questions[newIndex]?.text || ''); 21 | localStorage.setItem('questionIndex', newIndex); 22 | localStorage.setItem('lastUpdateDate', new Date().toISOString()); 23 | } else { 24 | setCurrentQuestionIndex(parseInt(storedIndex)); 25 | setCurrentQuestion(questions[parseInt(storedIndex)]?.text || ''); 26 | } 27 | } else { 28 | setCurrentQuestionIndex(0); 29 | setCurrentQuestion(questions[0]?.text || ''); 30 | localStorage.setItem('questionIndex', 0); 31 | localStorage.setItem('lastUpdateDate', new Date().toISOString()); 32 | } 33 | }, []); 34 | 35 | return ( 36 |
                37 |

                Вопрос дня

                38 |

                {currentQuestion}

                39 |
                40 | ); 41 | }; 42 | 43 | export default QuestionOfTheDay; -------------------------------------------------------------------------------- /practice-02/components/simpleRandom/script.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | function getRandomQuestions() { 3 | return fetch(API_BASE_URL + 'getSimpleRandomQuestions.php') 4 | .then((response) => { 5 | return response.json(); 6 | }); 7 | } 8 | 9 | function fillRandomQuestions() { 10 | const container = document.querySelector('.js-simple-random-questions'); 11 | 12 | if (container === undefined) { 13 | console.error('Ошибка! Не смогли найти элемент .js-simple-random-questions на странице.'); 14 | return; 15 | } 16 | 17 | getRandomQuestions() 18 | .then((questions) => { 19 | container.innerHTML = ''; 20 | questions.map((question) => { 21 | const node = document.createElement("li"); 22 | node.textContent = question; 23 | container.appendChild(node); 24 | }); 25 | }); 26 | } 27 | 28 | function showHistory() { 29 | fetch(API_BASE_URL + 'getSimpleRandomQuestionsHistory.php') 30 | .then((response) => { 31 | return response.text(); 32 | }) 33 | .then((text) => { 34 | showNotice('История', text); 35 | }); 36 | } 37 | 38 | function listenButtons() { 39 | const buttonAll = document.querySelector('.js-simple-random'); 40 | const buttonOne = document.querySelector('.js-simple-random-history'); 41 | 42 | if (buttonAll === undefined || buttonOne === undefined) { 43 | console.error('Ошибка! Не смогли найти элементы .js-simple-random на странице.'); 44 | return; 45 | } 46 | 47 | buttonAll.addEventListener('click', () => fillRandomQuestions()); 48 | buttonOne.addEventListener('click', () => showHistory()); 49 | } 50 | 51 | listenButtons(); 52 | }()); 53 | -------------------------------------------------------------------------------- /practice-01/components/Questions/Questions.module.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | font-family: Arial, sans-serif; 3 | color: #333333; 4 | font-size: 16px; 5 | line-height: 1.5; 6 | 7 | } 8 | 9 | .tags { 10 | margin-top: 10px; 11 | } 12 | 13 | .tags span { 14 | display: inline-block; 15 | padding: 8px; 16 | background-color: #007bff; /* изменение цвета фона */ 17 | color: #ffffff; 18 | border-radius: 5px; 19 | margin-right: 8px; 20 | font-size: 12px; 21 | } 22 | 23 | .tags span:last-child { 24 | margin-right: 0; 25 | } 26 | 27 | .question { 28 | display: flex; 29 | padding-top: 5px; 30 | padding-bottom: 5px; 31 | justify-content: space-between; 32 | align-items: center; 33 | } 34 | 35 | .large { 36 | font-size: 1.5rem; /* увеличение размера шрифта */ 37 | 38 | color: #101828; 39 | } 40 | 41 | .accord { 42 | flex-direction: column; 43 | justify-content: flex-start; 44 | align-items: stretch; 45 | border-bottom: 1px solid #cccccc; /* изменение цвета границы */ 46 | } 47 | 48 | .faqList { 49 | max-width: 800px; /* увеличение максимальной ширины */ 50 | margin: 0 auto; /* центрирование на странице */ 51 | } 52 | 53 | .title { 54 | margin-top: 2rem; /* увеличение отступа сверху */ 55 | margin-bottom: 1rem; 56 | font-size: 2rem; /* уменьшение размера шрифта */ 57 | font-weight: bold; /* усиление шрифта */ 58 | text-align: center; 59 | } 60 | .filterContainer { 61 | display: flex; 62 | align-items: center; 63 | justify-content: space-between; 64 | margin-bottom: 20px; /* добавим отступ снизу */ 65 | border: 1px solid #ccc; /* добавим рамку */ 66 | padding: 10px; /* добавим отступ внутри рамки */ 67 | } 68 | 69 | .label { 70 | margin-right: 10px; /* добавим отступ справа для метки */ 71 | } 72 | 73 | /* Обновленные стили для селекта */ 74 | .select { 75 | padding: 8px; 76 | font-size: 16px; 77 | border: 1px solid #ccc; 78 | border-radius: 5px; 79 | } -------------------------------------------------------------------------------- /practice-01/components/Comment/Comment.js: -------------------------------------------------------------------------------- 1 | 'use client' 2 | import styles from './Comment.module.scss'; // Подключаем стили 3 | import React, { useState, useEffect } from 'react'; 4 | 5 | 6 | export default function Comment() { 7 | const [comments, setComments] = useState([]); 8 | const [text, setText] = useState(""); 9 | 10 | useEffect(() => { 11 | const loadedComments = JSON.parse(localStorage.getItem('comments')); 12 | setComments(loadedComments || []); 13 | }, []); 14 | 15 | const addNewComment = (e) => { 16 | e.preventDefault(); 17 | 18 | const newComment = { 19 | text, 20 | createdAt: new Date().toISOString(), 21 | }; 22 | 23 | const updatedComments = [...comments, newComment]; 24 | setComments(updatedComments); 25 | setText(''); 26 | 27 | localStorage.setItem('comments', JSON.stringify(updatedComments)); 28 | }; 29 | 30 | return ( 31 |
                32 |

                Добавить комментарий

                {/* Надпись "Добавить комментарий" */} 33 |
                34 | {comments && comments.map((comment, index) => ( 35 |
                36 |

                {comment.text}

                37 | {comment.createdAt} 38 |
                39 | ))} 40 |
                41 |
                42 | 48 | {/* Кнопка "Добавить комментарий" */} 49 |
                50 |
                51 | ); 52 | } -------------------------------------------------------------------------------- /lecture02/basic/ankudinova/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Ankudinova 7 | 8 | 9 |

                Основные теги

                10 |
                11 | 57 |
                block
                58 | inline 59 | 60 | 61 | -------------------------------------------------------------------------------- /practice-01/components/RandomQuestionsFrequency/index.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | import styles from './RandomQuestionsFrequency.module.scss'; 3 | import questions from "../../questions.js" 4 | import React from 'react'; 5 | 6 | export default function RandomQuestionsFrequency() { 7 | const [randomQuestions, setRandomQuestions] = React.useState([]); 8 | 9 | const generateRandomQuestionsFrequency = () => { 10 | const totalQuestionsCount = questions.reduce((total, question) => total + (question.frequency ?? 100), 0); 11 | const selectedQuestions = []; 12 | 13 | for (let i = 0; i < 5; i++) { 14 | const randomNumber = Math.floor(Math.random() * totalQuestionsCount); 15 | 16 | let cumulativeFrequency = 0; 17 | let selectedQuestion; 18 | for (const question of questions) { 19 | cumulativeFrequency += (question.frequency ?? 100); 20 | if (randomNumber < cumulativeFrequency) { 21 | selectedQuestion = question; 22 | break; 23 | } 24 | } 25 | 26 | selectedQuestions.push(selectedQuestion); 27 | } 28 | 29 | setRandomQuestions(selectedQuestions); 30 | } 31 | 32 | return ( 33 |
                34 |
                35 |
                Рандомные вопросы с частотой
                36 | 37 |
                  38 | {randomQuestions.map(function(question, index) { 39 | if (question && question.text) { 40 | return
                1. {question.text}
                2. ; {/* Добавлен класс стиля для элементов списка */} 41 | } else { 42 | return null; 43 | } 44 | })} 45 |
                46 |
                47 |
                48 | ); 49 | } -------------------------------------------------------------------------------- /lecture03/basic/trebunskih/css/style.css: -------------------------------------------------------------------------------- 1 | .background{ 2 | background-color: aqua; 3 | } 4 | .background2{ 5 | background-image: linear-gradient(#c8bdf2, #4441e6); 6 | } 7 | 8 | .background3{ 9 | background-image: url(https://img.freepik.com/free-photo/adorable-looking-kitten-with-yarn_23-2150886292.jpg?w=740&t=st=1707209036~exp=1707209636~hmac=bdfe58529dc9628fa0a3de7063cc03f14f4cec462bb34fa546ffd9f413ca4d9c); 10 | } 11 | 12 | 13 | 14 | 15 | #border{ 16 | border: solid red; 17 | } 18 | .border2{ 19 | border: dashed rgb(14, 26, 255); 20 | } 21 | .border3{ 22 | border: 4mm ridge rgba(211, 220, 50, .6);; 23 | } 24 | 25 | 26 | 27 | 28 | .color{ 29 | color:brown; 30 | } 31 | .color2{ 32 | color: aqua; 33 | } 34 | .color3{ 35 | color: blueviolet; 36 | } 37 | 38 | 39 | 40 | 41 | .cursor{ 42 | cursor: wait; 43 | } 44 | .cursor2{ 45 | cursor: pointer; 46 | } 47 | .cursor3{ 48 | cursor: all-scroll; 49 | } 50 | 51 | 52 | 53 | 54 | .content { 55 | display: block; 56 | } 57 | .content1{ 58 | display: flex; 59 | } 60 | .content2{ 61 | display: grid; 62 | } 63 | 64 | 65 | 66 | .filter{ 67 | filter: blur(3px); 68 | } 69 | .filter2{ 70 | filter: drop-shadow(2px 3px 5px black); 71 | } 72 | .filter3{ 73 | filter: contrast(20%); 74 | } 75 | 76 | 77 | 78 | .margin{ 79 | margin: 10px 50px 20px; 80 | } 81 | .margin2{ 82 | margin: 150px; 83 | } 84 | .margin3{ 85 | margin: 10% auto; 86 | } 87 | 88 | 89 | 90 | .padding{ 91 | padding: 25px 50px 75px 100px; 92 | } 93 | .padding2{ 94 | padding: 10px 20px; 95 | } 96 | 97 | .padding3{ 98 | padding: 10px 3% 20px; 99 | } 100 | 101 | 102 | .font{ 103 | font: small-caps bold 24px/1 sans-serif; 104 | } 105 | .font2{ 106 | font: italic 1.2rem "Fira Sans", serif; 107 | } 108 | .font3{ 109 | font: bold italic large serif; 110 | } 111 | 112 | 113 | .transform{ 114 | transform: scale(2, 0.5); 115 | } 116 | 117 | .transform2{ 118 | transform: rotate(0.5turn); 119 | } 120 | .transform3{ 121 | transform: skew(10deg, 5deg); 122 | } -------------------------------------------------------------------------------- /practice-01/components/Top5dieFive/index.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import styles from './Five.module.scss'; 4 | import questions from "../../questions.js" 5 | import React, { useState } from 'react'; 6 | 7 | export default function Random5Questions() { 8 | const [count, setCount] = useState(5); 9 | const [randomQuestions, setRandomQuestions] = useState([]); 10 | const [remainingQuestions, setRemainingQuestions] = useState([...questions]); // Копия исходного массива вопросов 11 | const [showQuestions, setShowQuestions] = useState(false); 12 | 13 | const handleSubmit = (e) => { 14 | e.preventDefault(); 15 | generateRandomQuestions(); 16 | setShowQuestions(true); 17 | } 18 | 19 | const handleReset = () => { 20 | setShowQuestions(false); 21 | setRandomQuestions([]); 22 | setRemainingQuestions([...questions]); // Восстанавливаем копию исходного массива 23 | } 24 | 25 | const generateRandomQuestions = () => { 26 | if (remainingQuestions.length < count) { 27 | setRandomQuestions(remainingQuestions); 28 | setRemainingQuestions([]); 29 | } else { 30 | const selectedQuestions = []; 31 | for (let i = 0; i < count; i++) { 32 | const randomIndex = Math.floor(Math.random() * remainingQuestions.length); 33 | const randomQuestion = remainingQuestions[randomIndex]; 34 | selectedQuestions.push(randomQuestion); 35 | remainingQuestions.splice(randomIndex, 1); 36 | } 37 | setRandomQuestions(selectedQuestions); 38 | } 39 | } 40 | 41 | return ( 42 |
                43 |

                Рандомные вопросы

                44 |
                45 | 46 | 47 |
                48 | {showQuestions && ( 49 |
                  50 | {randomQuestions.map((question, index) => ( 51 |
                1. {question.text}
                2. 52 | ))} 53 |
                54 | )} 55 |
                56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /practice-01/components/RandomQuestionsList/index.js: -------------------------------------------------------------------------------- 1 | "use client" 2 | import styles from './RandomQuestionsList.module.scss'; 3 | import { useState } from 'react'; 4 | import questions from '@/questions'; 5 | 6 | export default function RandomQuestionsList() { 7 | const [questionsList, setQuestionsList] = useState([]); 8 | const [history, setHistory] = useState([]); 9 | const [showMessage, setShowMessage] = useState(true); 10 | 11 | const generateRandomQuestions = () => { 12 | setShowMessage(false); 13 | const randomQuestions = []; 14 | while (randomQuestions.length < 5) { 15 | const randomIndex = Math.floor(Math.random() * questions.length); 16 | if (!randomQuestions.includes(questions[randomIndex])) { 17 | randomQuestions.push(questions[randomIndex]); 18 | } 19 | } 20 | 21 | setQuestionsList(randomQuestions); 22 | updateHistory(randomQuestions); 23 | }; 24 | 25 | const updateHistory = (newQuestions) => { 26 | const currentDate = new Date().toLocaleString(); 27 | const historyItem = `${currentDate} - ${JSON.stringify(newQuestions.map(question => question.text))}`; 28 | 29 | const updatedHistory = [historyItem, ...history.slice(0, 9)]; 30 | setHistory(updatedHistory); 31 | }; 32 | 33 | return ( 34 |
                35 |

                Рандомные вопросы с историей

                36 | 37 |
                38 | {questionsList.length > 0 && ( 39 |
                  40 | {questionsList.map((question, index) => ( 41 |
                1. {question.text}
                2. 42 | ))} 43 |
                44 | )} 45 |
                46 |
                47 |

                History

                48 |
                  49 | {history.map((item, index) => ( 50 |
                1. {item}
                2. 51 | ))} 52 |
                53 |
                54 | {showMessage &&

                Тыкни кнопочку выше чтобы появилась история :()

                } 55 |
                56 | ); 57 | } -------------------------------------------------------------------------------- /lecture03/basic/Puchkov/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Kuznetsov 7 | 8 | 9 |

                Основные CSS свойства

                10 |
                11 | Список всех CSS свойств 14 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /lecture03/basic/kuznetsov/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Kuznetsov 7 | 8 | 9 |

                Основные CSS свойства

                10 |
                11 | Список всех CSS свойств 14 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /lecture03/basic/Ankudinova-basic-lecture03/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Ankudinova 7 | 8 | 9 |

                Основные CSS свойства

                10 |
                11 | Список 10 CSS свойств 12 | 13 | 74 | 75 | -------------------------------------------------------------------------------- /lecture03/basic/gladkov/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gladkov 7 | 8 | 9 |

                Основные CSS свойства

                10 |
                11 | Список всех CSS свойств 12 | 13 | 78 | 79 | -------------------------------------------------------------------------------- /lecture03/basic/Harin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Harin 7 | 8 | 9 |

                Основные CSS свойства

                10 |
                11 | Список всех CSS свойств 12 | 13 | 76 | 77 | -------------------------------------------------------------------------------- /lecture06/index.php: -------------------------------------------------------------------------------- 1 | age = $age; 11 | } 12 | } 13 | 14 | $obj = new Test('test'); 15 | 16 | try { 17 | throw new CustomException(); 18 | var_dump($obj->age); 19 | } catch (CustomException $e) { 20 | var_dump('CustomException'); 21 | } catch (\Throwable $e) { 22 | var_dump('Throwable'); 23 | } 24 | 25 | abstract class Human { 26 | public $name; 27 | public $age; 28 | 29 | // Инкапсуляция. Скрытие внутреннего состояния и функций объекта и предоставление доступа только через открытый набор функций. 30 | // --- private, protected, public 31 | private $pasport; 32 | 33 | public function __construct($name, $age) { 34 | $this->name = $name; 35 | $this->age = $age; 36 | } 37 | 38 | function getInfo() { 39 | return 'Меня зовут '.$this->name.'. И мне '.$this->age. $this->getPasport(); 40 | } 41 | 42 | function getPasport() { 43 | return $this->pasport; 44 | } 45 | 46 | function setPasport($value) { 47 | $this->pasport = $value; 48 | return $this; 49 | } 50 | 51 | // Абстракция. Моделирование требуемых атрибутов и взаимодействий сущностей в виде классов для определения абстрактного представления системы.--- abstract 52 | abstract function check(); 53 | } 54 | 55 | interface IPRegisterable { 56 | function register(); 57 | } 58 | 59 | class Student extends Human implements IPRegisterable { 60 | private const ADULT_AGE = 18; 61 | 62 | function isAdult() { 63 | return $this->age >= self::ADULT_AGE; 64 | } 65 | 66 | // Полиморфизм. Возможность реализации наследуемых свойств или методов отличающимися способами в рамках множества абстракций. 67 | // --- переопределение функций 68 | function getInfo() { 69 | return 'Я студент '.$this->name.'. И мне '.$this->age. $this->getPasport(); 70 | } 71 | 72 | function register() { 73 | return md5($this->age.$this->name); 74 | } 75 | 76 | function check() { 77 | return 0; 78 | } 79 | } 80 | 81 | // Наследование. Возможность создания новых абстракций на основе существующих.--- extends 82 | class Teacher extends Human implements IPRegisterable { 83 | function register() { 84 | return md5($this->age); 85 | } 86 | 87 | function check() { 88 | return 0; 89 | } 90 | } 91 | 92 | function check(IPRegisterable $human) { 93 | return $human->register(); 94 | } 95 | 96 | $student = new Student('Антон', 18); 97 | $teacher = new Teacher('Миша',25); 98 | 99 | print_r($student->getInfo()); 100 | echo "\n"; 101 | var_dump($student->isAdult()); 102 | echo "\n"; 103 | var_dump($student->register()); 104 | var_dump($teacher->register()); 105 | var_dump(check($teacher)); 106 | 107 | ?> -------------------------------------------------------------------------------- /lecture02/basic/Harin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Harin 7 | 8 | 9 |

                Основные теги

                10 |
                11 | 12 | 13 | 51 | 52 | 53 | inline 54 | 55 | 56 | -------------------------------------------------------------------------------- /practice-02/components/questionsByIds/script.js: -------------------------------------------------------------------------------- 1 | const getQuestionsByIds = async (query) => { 2 | try { 3 | const response = await fetch(`${API_BASE_URL}getQuestionsByIds.php?ids=${query}`); 4 | if (!response.ok) { 5 | console.error("Ошибка запроса"); 6 | return null; 7 | } 8 | return await response.json(); 9 | } catch (error) { 10 | console.error(error); 11 | return null; 12 | } 13 | } 14 | 15 | const getQuestionsByIdsFill = (questionsArray) => { 16 | const container = document.querySelector('.js-questions-by-ids'); 17 | 18 | if (!container) { 19 | console.error('Ошибка! Не смогли найти элемент .js-questions-by-ids на странице.'); 20 | return; 21 | } 22 | 23 | container.textContent = ''; 24 | 25 | for(const question of questionsArray) { 26 | const node = document.createElement("li"); 27 | node.textContent = question?.text || "Текст не найден"; 28 | container.appendChild(node); 29 | } 30 | } 31 | 32 | const getQuestionsByIdsFillMissing = (missingIdsArray) => { 33 | const container = document.querySelector('.js-questions-missing-ids'); 34 | 35 | if (!container) { 36 | console.error('Ошибка! Не смогли найти элемент .js-questions-missing-ids на странице.'); 37 | return; 38 | } 39 | container.textContent = ''; 40 | for(const questionId of missingIdsArray) { 41 | const node = document.createElement("li"); 42 | node.textContent = `Вопрос с идентификатором ${questionId} не найден`; 43 | container.appendChild(node); 44 | } 45 | } 46 | 47 | const getQuestionsByIdsClickHandler = async () => { 48 | const form = document.querySelector('.js-questions-by-ids-form') 49 | 50 | if (!form) { 51 | console.error('Ошибка! Не смогли найти элемент .js-questions-by-ids-form на странице.'); 52 | return; 53 | } 54 | 55 | const question_ids = form.querySelector('[name="question_ids"]') 56 | 57 | if (!question_ids) { 58 | console.error('Ошибка! Не смогли найти инпут question_ids на странице.'); 59 | return; 60 | } 61 | 62 | const questions = await getQuestionsByIds(question_ids.value).catch((error) => { 63 | console.error(error) 64 | }) 65 | 66 | if(!questions) { 67 | showNotice('Ошибка при получении данных.'); 68 | return 69 | } 70 | 71 | if(questions.error) { 72 | showNotice('Ошибка', questions.error) 73 | return 74 | } 75 | 76 | if(!questions.questions || !questions.missing_ids) { 77 | showNotice('Ошибка', 'Получены некорректные данные.') 78 | return 79 | } 80 | 81 | getQuestionsByIdsFill(questions.questions) 82 | getQuestionsByIdsFillMissing(questions.missing_ids) 83 | }; 84 | 85 | (() => { 86 | const getQuestionsButton= document.querySelector('.js-questions-by-ids-button') 87 | 88 | if (!getQuestionsButton) { 89 | console.error('Ошибка! Не смогли найти элементы .js-questions-by-ids-button на странице.'); 90 | return 91 | } 92 | 93 | getQuestionsButton.addEventListener('click', (event) => { 94 | event.preventDefault(); 95 | getQuestionsByIdsClickHandler(); 96 | }) 97 | })(); 98 | 99 | -------------------------------------------------------------------------------- /lecture03/basic/britvin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Chugaev 7 | 8 | 9 |

                Основные CSS свойства

                10 |
                11 | Список всех CSS свойств 12 | 13 | 86 | 87 | -------------------------------------------------------------------------------- /lecture02/basic/gladkov/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | gladkov 7 | 8 | 9 |

                Основные теги

                10 |
                11 | 12 | - 13 | - 14 | block - 15 | - 16 |

                block

                до
                block
                - 17 |

                block

                - 18 | inline - 19 | inline - 20 |
                block
                - 21 | inline - 22 | - 23 |
                  block
                - 24 |
              1. list-item
              2. - 25 | table
                - 26 | table-row - 27 | table-cell - 28 | table-cell - 29 |
                block
                - 30 | inline-block - 31 | - 32 | - 33 | - 34 | - 35 | - 36 |
                inline - 37 |
                block - 38 | inline - 39 | inline - 40 |
                block
                - 41 | inline - 42 |
                block
                - 43 | - 44 | - 45 | - 46 | inline-block - 47 | inline-block - 48 | - 49 | - 50 |
                block
                51 | inline 52 | 53 | 54 | -------------------------------------------------------------------------------- /practice-02/components/questions/script.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | let currentPage = 1; 3 | const pageSize = 10; 4 | 5 | function getQuestions(page = currentPage) { 6 | const url = `${API_BASE_URL}getQuestions.php?page=${page}&pageSize=${pageSize}`; 7 | return fetch(url) 8 | .then(response => response.json()); 9 | } 10 | 11 | function updateURL(page) { 12 | const newURL = `${window.location.protocol}//${window.location.host}${window.location.pathname}?page=${page}`; 13 | window.history.pushState({ path: newURL }, '', newURL); 14 | } 15 | 16 | function fillQuestions() { 17 | const container = document.querySelector('.js-questions'); 18 | 19 | getQuestions().then(data => { 20 | container.innerHTML = ''; 21 | const questions = data.questions; 22 | questions.forEach((question, index) => { 23 | const questionNode = document.createElement('li'); 24 | questionNode.textContent = question.text + " " + question.smile; 25 | 26 | container.appendChild(questionNode); 27 | }); 28 | updatePaginationControls(data.totalQuestions); 29 | }); 30 | } 31 | 32 | function navigate(page) { 33 | currentPage = page; 34 | updateURL(page); 35 | fillQuestions(); 36 | } 37 | 38 | function updatePaginationControls(totalQuestions) { 39 | const paginationContainer = document.querySelector('.js-pagination'); 40 | paginationContainer.innerHTML = ''; 41 | 42 | if (currentPage > 1) { 43 | const prevButton = document.createElement('button'); 44 | prevButton.textContent = 'Назад'; 45 | prevButton.addEventListener('click', () => navigate(currentPage - 1)); 46 | paginationContainer.appendChild(prevButton); 47 | } 48 | 49 | const pageInfo = document.createElement('span'); 50 | pageInfo.textContent = `Страница ${currentPage}`; 51 | paginationContainer.appendChild(pageInfo); 52 | 53 | if (totalQuestions > currentPage * pageSize) { 54 | const nextButton = document.createElement('button'); 55 | nextButton.textContent = 'Вперед'; 56 | nextButton.addEventListener('click', () => navigate(currentPage + 1)); 57 | paginationContainer.appendChild(nextButton); 58 | } 59 | } 60 | 61 | document.addEventListener('DOMContentLoaded', () => { 62 | const params = new URLSearchParams(window.location.search); 63 | const page = parseInt(params.get('page'), 10); 64 | if (page) { 65 | currentPage = page; 66 | } 67 | fillQuestions(); 68 | }); 69 | 70 | document.getElementById('addQuestionForm').addEventListener('submit', function(event) { 71 | event.preventDefault(); 72 | 73 | const newQuestion = document.getElementById('newQuestion').value; 74 | 75 | fetch('/practice-02/api/addQuestion.php', { 76 | method: 'POST', 77 | body: new URLSearchParams({ newQuestion }) 78 | }) 79 | .then(response => { 80 | if (response.ok) { 81 | showNotice('Вопрос добавлен'); 82 | fillQuestions(); 83 | } else { 84 | throw new Error('Ошибка при добавлении вопроса'); 85 | } 86 | }) 87 | .catch(error => { 88 | showNotice('Ошибка', error.message); 89 | }); 90 | }); 91 | 92 | 93 | }()); 94 | -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/style.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["abstracts/_common.scss","abstracts/_vars.scss","style.css","components/_button.scss","sections/_graph.scss"],"names":[],"mappings":"AAAQ,yFAAA;ACAR;EACI,mBAAA;EACA,kBAAA;EACA,2BAAA;EACA,uBAAA;EACA,6BAAA;EACA,6BAAA;EACA,uBAAA;EACA,0BAAA;EACA,4BAAA;EACA,kCAAA;EACA,2BAAA;EACA,4BAAA;EACA,6BAAA;EACA,0BAAA;EACA,wBAAA;EACA,gDAAA;EACA,2BAAA;EACA,0BAAA;EACA,uBAAA;EACA,6CAAA;EACA,8BAAA;EACA,yBAAA;EACA,kDAAA;EACA,0BAAA;EACA,0BAAA;EACA,iDAAA;EACA,sBAAA;EACA,wCAAA;EACA,4BAAA;EACA,6BAAA;EACA,8BAAA;EACA,oCAAA;EACA,iCAAA;EACA,8BAAA;EACA,8BAAA;EACA,4BAAA;EACA,+BAAA;EACA,6EAAA;EACA,yCAAA;EACA,8BAAA;ACEJ;;AFxCA;EACI,kCAAA;EACA,mCAAA;EACA,8BAAA;AE2CJ;;AFvCA;;;EAGI,sBAAA;EACA,SAAA;EACA,UAAA;AE0CJ;;AFvCA;EACI,eAAA;EACA,cAAA;EACA,iBAAA;AE0CJ;;AFvCA;EACI,kBAAA;EACA,WAAA;EACA,YAAA;AE0CJ;;ACpEA;EACI,UAAA;EACA,6BAAA;EACA,gBAAA;EACA,YAAA;EACA,mBAAA;EACA,UAAA;EACA,oBAAA;EACA,mBAAA;EACA,uBAAA;EACA,cAAA;EACA,eAAA;ADuEJ;;ACpEA;EACI,iBAAA;EACA,gBAAA;EACA,gBAAA;EACA,eAAA;EACA,iBAAA;ADuEJ;;ACpEA;EACI,kBAAA;EACA,uBAAA;EACA,0BAAA;EACA,gBAAA;EACA,yCAAA;ADuEJ;;ACpEA;EACI,eAAA;ADuEJ;;ACpEA;EACI,2CAAA;ADuEJ;;ACrEA;EACI,qBAAA;ADwEJ;;AE9GA;EAGI,gCAAA;EACA,cAAA;EACA,aAAA;AF+GJ;AE5GI;EACI,oCAAA;EACA,kBAAA;EACA,aAAA;AF8GR;AE3GI;EACI,SAAA;EACA,gBAAA;EAEA,eAAA;EACA,iBAAA;AF4GR;AEzGI;EACI,gBAAA;AF2GR;AExGI;EACI,uBAAA;EACA,aAAA;EACA,8BAAA;EACA,eAAA;EACA,SAAA;EAEA,oCAAA;EACA,kBAAA;EACA,aAAA;AFyGR;AEtGI;EACI,aAAA;EACA,uBAAA;EACA,8BAAA;EACA,WAAA;EACA,SAAA;AFwGR;AErGI;EACI,SAAA;EACA,gBAAA;EACA,iBAAA;EACA,eAAA;AFuGR;AEpGI;EACI,QAAA;EACA,eAAA;AFsGR;;AElGA;EAEI,eAAA;EAEA,cAAA;EACA,kBAAA;EACA,mBAAA;EACA,kBAAA;EACA,6BAAA;EACA,2CAAA;AFmGJ;AEjGI;EACI,wCAAA;AFmGR;AEjGQ;EACI,2GAAA;AFmGZ;AE/FI;EACI,kBAAA;EAEA,kBAAA;EACA,aAAA;EACA,kBAAA;EACA,8BAAA;EACA,YAAA;AFgGR;AE3FI;EACI,gBAAA;AF6FR;AE1FI;EACI,eAAA;EAEA,kBAAA;EACA,UAAA;EACA,OAAA;EACA,QAAA;EACA,MAAA;EACA,SAAA;AF2FR;AExFI;EACI,wCAAA;EACA,kBAAA;EACA,cAAA;EACA,gBAAA;EACA,oBAAA;EACA,iBAAA;EACA,kBAAA;EACA,gBAAA;AF0FR;;AEtFA;EACI,uBAAA;EACA,aAAA;EACA,8BAAA;EACA,SAAA;EACA,eAAA;AFyFJ;AErFI;EACI,gBAAA;EACA,aAAA;EAEA,eAAA;EACA,iBAAA;EACA,mBAAA;AFsFR;AEnFI;EACI,aAAA;EACA,QAAA;AFqFR;AElFI;EACI,eAAA;EACA,iBAAA;EACA,gBAAA;AFoFR;AEjFI;EACI,aAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,sBAAA;AFmFR;AEhFI;EACI,eAAA;EACA,iBAAA;EACA,gBAAA;AFkFR;AE/EI;EACI,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,6BAAA;EACA,aAAA;EACA,QAAA;AFiFR;AE/EQ;EACI,WAAA;EACA,YAAA;EACA,kBAAA;AFiFZ;AE5EI;EACI,aAAA;EACA,mBAAA;EACA,YAAA;EACA,qBAAA;EACA,gBAAA;EACA,eAAA;EACA,WAAA;AF8ER;AE1EI;EACI,qBAAA;EAEA,WAAA;EACA,YAAA;EACA,kBAAA;EACA,iBAAA;AF2ER;AEvEQ;EACI,mBAAA;AFyEZ;AEpEQ;EACI,uCAAA;AFsEZ;AEjEI;EACI,iBAAA;EACA,YAAA;EACA,6BAAA;AFmER;AEhEI;EACI,4CAAA;EACA,eAAA;AFkER;;AE7DA;EACI,mBAAA;EACA,gBAAA;EACA,WAAA;AFgEJ;AE9DI;EACI,WAAA;EACA,YAAA;EACA,kBAAA;EACA,iCAAA;EACA,kBAAA;AFgER;AE3DI;EACI,OAAA;AF6DR;AE1DI;EACI,QAAA;AF4DR;AEzDI;EAEI,kBAAA;EACA,gBAAA;EACA,6BAAA;EACA,qBAAA;EACA,eAAA;AF0DR;AEvDI;EACI,gBAAA;EACA,kBAAA;EACA,MAAA;EACA,oBAAA;EACA,aAAA;EACA,8BAAA;EACA,WAAA;EACA,YAAA;AFyDR;AEtDI;EACI,UAAA;EACJ,WAAA;EACA,qCAAA;EACA,kBAAA;AFwDJ;AErDI;EACI,kBAAA;EACA,YAAA;EACA,4CAAA;EACA,oCAAA;EACA,wDAAA;EACA,kBAAA;EACA,cAAA;EACA,eAAA;EACA,MAAA;AFuDR;AEpDI;EACI,kBAAA;EACA,gBAAA;EACA,kCAAA;EACA,qBAAA;EACA,eAAA;EACA,OAAA;AFsDR;AEnDI;EACI,kBAAA;EACA,gBAAA;EACA,kCAAA;EACA,qBAAA;EACA,eAAA;EACA,QAAA;AFqDR;AElDI;EACI,kBAAA;EACA,YAAA;EACA,UAAA;EACA,QAAA;EACA,8BAAA;EACA,kDAAA;EACA,kBAAA;EACA,0BAAA;EACA,cAAA;AFoDR;AEjDI;EACI,WAAA;EACA,YAAA;EACA,cAAA;EACA,aAAA;EACA,iCAAA;EACA,yCAAA;EACA,kBAAA;AFmDR;AEhDI;EACI,aAAA;EACA,eAAA;EACA,gBAAA;EACA,8BAAA;EACA,eAAA;EACA,cAAA;EACA,kBAAA;EACA,0BAAA;AFkDR;AE/CI;EACI,UAAA;EACA,wCAAA;EACA,YAAA;EACA,eAAA;EACA,uBAAA;EACA,UAAA;EACA,kBAAA;EACA,kBAAA;AFiDR;AE7CI;EACI,WAAA;EACA,YAAA;EACA,wBAAA;EACA,UAAA;EACA,UAAA;EAEA,4BAAA;EACA,kBAAA;AF8CR","file":"style.css"} -------------------------------------------------------------------------------- /lecture02/basic/Puchkov/puchkov.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Puchkov 7 | 8 | 9 | 10 | Определяет текст как аббревиатуру или акроним 11 |
                12 |
                Элемент-контейнер для разделов HTML-документа
                13 |
                14 | Контейнер для строчных элементов 15 |
                16 |

                Текст абзаца

                17 |
                18 | 19 |
                20 |
              3. Элемент маркированного или нумерованного списка
              4. 21 |
                22 |

                Используется для залаговков

                23 |
                24 |
                Задает контактные данные автора/владельца документа или статьи.
                25 |
                26 | Задает полужирное начертание отрывка текста, не придавая акцент или важность выделенному 27 |
                28 |
                Перенос текста на новую строку 29 |
                30 | 31 | 32 | 33 |

                <input>

                34 | 59 | 60 | 61 | 62 | 63 | Видео 66 | 67 | 68 |
                69 | 70 | 71 |

                72 | 73 | 74 | -------------------------------------------------------------------------------- /lecture04/basic/lecture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chugaev 8 | 9 | 10 |
                11 |

                Chugaev

                12 |
                13 | 16 | 17 |
                  18 |
                19 |
                20 | 113 | 137 |
                138 | 139 | -------------------------------------------------------------------------------- /lecture03/basic/trebunskih/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Trebunskih 8 | 9 | 10 |
                11 |

                DISPLAY

                12 |

                BLOCK
                13 | display определяет тип отображения элемента, как он будет 14 | отображаться на веб-странице: как блок, 15 | строчный элемент или каким-то другим способом.

                16 |

                FLEX

                17 |

                GRID

                18 |
                19 | 20 | 21 |
                22 |

                BACKGROUND

                23 |

                background позволяет установить 24 | одновременно несколько характеристик фона

                25 | 26 |

                background, но с градиентом

                27 |

                28 | s
                s
                s
                s
                s
                s

                s
                s
                s

                29 |
                30 | 31 | 32 |
                33 |

                BORDER

                34 |

                Универсальное свойство border позволяет одновременно
                35 | установить толщину, стиль и цвет границы вокруг элемента.

                36 |

                Синий пунктир

                37 |

                Крутая толстая рамка

                38 |
                39 | 40 |
                41 |

                COLOR

                42 |

                43 | CSS-свойство color позволяет задавать цвет 44 | текста и фона элемента на веб-странице. 45 |

                46 |

                Зелёный

                47 |

                Розовый

                48 | 49 |
                50 | 51 |

                CURSOR

                52 |
                Устанавливает форму курсора,
                когда он находится в пределах элемента.
                53 | Вид курсора зависит от операционной системы
                и установленных параметров. 54 |


                55 |
                Ну
                Сюда
                Типо
                Можно нажать
                56 |

                57 |
                Ну
                Это
                Типо
                Лютый скроллинг
                58 | 59 | 60 |
                61 |

                FILTER

                62 |

                Фильтры воспроизводят в браузере визуальные эффекты, 63 | похожие на фильтры Photoshop

                64 |

                Меня чот размыло

                65 |

                Регулирует контрастность изображения, т.е.
                66 | разницу между самыми темными и самыми
                67 | светлыми участками изображения/фона

                68 |
                69 | 70 |
                71 |

                MARGIN

                72 |

                по вертикали | по горизонтали, 10% auto

                73 |

                свойство margin определяет внешний отступ на всех четырёх сторонах элемента.

                74 |

                Отступ со всех сторон (я сделал на 150)

                75 | 76 |
                77 | 78 |
                79 |

                PADDING

                80 |

                Устанавливает значение полей вокруг
                81 | содержимого элемента. Полем называется расстояние
                82 | от внутреннего края рамки элемента до воображаемого
                83 | прямоугольника, ограничивающего его содержимое

                84 |

                Отступ сверху и снизу 10px, слева и справа отступ 20px

                85 |

                сверху отступ 10px слева и справа отступ 3% снизу отступ 20px

                86 |
                87 | 88 |
                89 |

                FONT

                90 |

                Свойство font используется для оформления текста на сайте

                91 |

                italic "Fira Sans"

                92 |

                Жирный курсив

                93 |
                94 | 95 |
                96 |

                TRANSFROM

                97 |

                Свойство CSS Transform позволяет вращать, масштабировать, наклонять или переводить элемент.

                98 |

                Я перевернулся

                99 |

                100 |

                102 | 103 |
                104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /practice-01/components/Questions/index.js: -------------------------------------------------------------------------------- 1 | 'use client'; 2 | 3 | import { useEffect, useState } from 'react'; 4 | import styles from './Questions.module.scss'; 5 | import questions from "../../questions.js"; 6 | 7 | export default function Questions() { 8 | const [filter, setFilter] = useState("all"); 9 | const [newQuestions, setNewQuestions] = useState([]); 10 | const [filteredQuestions, setFilteredQuestions] = useState([]); 11 | const [newQuestion, setNewQuestion] = useState(""); 12 | 13 | useEffect(() => { 14 | const storedQuestions = JSON.parse(localStorage.getItem('questions')) || []; 15 | setNewQuestions(storedQuestions); 16 | }, []); 17 | 18 | useEffect(() => { 19 | const filtered = getAllQuestions().filter(question => { 20 | if (filter === "all") { 21 | return true; 22 | } else { 23 | return question.tags.includes(filter); 24 | } 25 | }); 26 | setFilteredQuestions(filtered); 27 | }, [filter, newQuestions]); 28 | 29 | const getAllQuestions = (e) => { 30 | return [...questions, ...newQuestions]; 31 | }; 32 | 33 | const handleFilterChange = (e) => { 34 | setFilter(e.target.value); 35 | }; 36 | 37 | const handleNewQuestionChange = (e) => { 38 | setNewQuestion(e.target.value); 39 | }; 40 | 41 | const handleSubmit = (e) => { 42 | e.preventDefault(); 43 | if (newQuestion.trim() !== "") { 44 | const updatedQuestions = [ 45 | ...newQuestions, 46 | { text: newQuestion, tags: ["New"] } 47 | ]; 48 | localStorage.setItem('questions', JSON.stringify(updatedQuestions)); 49 | setNewQuestion(""); 50 | setNewQuestions(updatedQuestions); 51 | } 52 | }; 53 | 54 | return ( 55 |
                56 |

                Вопросы для собеседования

                57 |
                58 | 59 | 69 |
                70 |
                71 | {filteredQuestions.map(function(question, index) { 72 | return ( 73 |
                74 |
                75 |
                76 |
                77 |
                78 | {index+1}. {question.text} 79 |
                80 |
                81 | {question.tags.map(function (tag, index) { 82 | return ( 83 | 84 | {tag} 85 | 86 | ); 87 | })} 88 |
                89 |
                90 |
                91 |
                92 |
                93 | ); 94 | })} 95 |
                96 |
                97 | 103 | 104 |
                105 |
                106 | ); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /script.js: -------------------------------------------------------------------------------- 1 | const questions = [ 2 | // -- Basics 3 | { 4 | "text": "Что происходит в браузере после перехода по url", 5 | }, 6 | { 7 | "text": "Что такое клиент-серверная архитектура, какие особенности", 8 | }, 9 | { 10 | "text": "Расшифруйте HTTP, какие есть актуальные версии", 11 | }, 12 | { 13 | "text": "Какие бывают типы HTTP-запросов", 14 | }, 15 | { 16 | "text": "Какие бывают коды состояния ответа HTTP (категории в сотнях)", 17 | }, 18 | { 19 | "text": "Что такое CORS, зачем нужен, как избежать", 20 | }, 21 | { 22 | "text": "Что такое REST API, примеры url", 23 | // https://gb.ru/blog/rest-api/ 24 | }, 25 | { 26 | "text": "Что такое GraphQL, примеры тела запроса", 27 | }, 28 | { 29 | "text": "Что такое Cookie и зачем они используются", 30 | // https://habr.com/ru/articles/710578/ 31 | }, 32 | { 33 | "text": "Что такое сложность алгоритма, нотация О большое", 34 | // https://techrocks.ru/2021/04/02/big-o-notation-examples/ 35 | }, 36 | // -- CSS 37 | // Для 3х ниже - https://developer.mozilla.org/ru/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance 38 | { 39 | "text": "Что такое каскад в CSS, несколько примеров", 40 | }, 41 | { 42 | "text": "Что такое специфичность в CSS, как рассчитывается, примеры расчетов", 43 | }, 44 | { 45 | "text": "Что такое наследование в CSS, какие свойства наследуются, как контролировать", 46 | }, 47 | { 48 | "text": "Что такое препроцессоры и постпроцессоры в CSS, перечислить основные", 49 | }, 50 | { 51 | "text": "Для чего нужны media-запросы в CSS, как работают", 52 | }, 53 | { 54 | "text": "Какие бывают типы позиционирования в CSS, в чём особенности", 55 | }, 56 | { 57 | "text": "Какие бывают значения у свойства display в CSS, в чём отличия", 58 | }, 59 | { 60 | "text": "Что такое доступность и как обеспечивается доступность в браузере (HTML)", 61 | }, 62 | // -- JS 63 | // Часть вопросов и ответов - https://github.com/ivan-isaev21/300-questions-js/blob/main/Junior/README.MD 64 | { 65 | "text": "Что такое window и в чём отличие от document", 66 | }, 67 | { 68 | "text": "Какие различия между let, var и const", 69 | }, 70 | { 71 | "text": "Какие есть типы данных в JS", 72 | }, 73 | { 74 | "text": "Какие различия между примитивными и ссылочными типами", 75 | }, 76 | { 77 | "text": "Как работает приведение типов в JS, примеры с == и ===", 78 | }, 79 | { 80 | "text": "Что такое область видимости в JS, несколько примеров", 81 | }, 82 | { 83 | "text": "Что такое localStorage и в чём отличие от sessionStorage", 84 | }, 85 | { 86 | "text": "Что такое fetch, основные options и процесс получения результата", 87 | }, 88 | { 89 | "text": "Что такое JSON, примеры использования", 90 | }, 91 | { 92 | "text": "Какие основные библиотеки для JS, в чём отличия", 93 | }, 94 | { 95 | "text": "В чём отличия между библиотекой и фреймворком", 96 | }, 97 | { 98 | "text": "Что такое менеджер пакетов, как работает npm", 99 | }, 100 | // -- OOP 101 | // Очень кратко - https://tproger.ru/translations/oop-principles-cheatsheet 102 | // Чуть подробнее - https://skillbox.ru/media/code/oop_chast_1_chto_takoe_klassy_i_obekty/ 103 | { 104 | "text": "Опишите базовые принципы ООП", 105 | }, 106 | { 107 | "text": "Назовите несколько паттернов проектирования", 108 | }, 109 | { 110 | "text": "Что такое класс и объект, в чём разница", 111 | }, 112 | { 113 | "text": "Что такое абстрактный класс, примеры применения", 114 | }, 115 | { 116 | "text": "Что такое интерфейс, примеры применения", 117 | }, 118 | { 119 | "text": "Что такое DRY, как расшифровывается, пара примеров", 120 | }, 121 | { 122 | "text": "Что такое KISS, как расшифровывается, пара примеров", 123 | }, 124 | { 125 | "text": "Что такое SOLID, как расшифровывается, пара примеров", 126 | }, 127 | { 128 | "text": "В чем разница между модификаторами доступа public, private и protected", 129 | }, 130 | { 131 | "text": "Что такое конструктор класса", 132 | }, 133 | { 134 | "text": "Что такое статические методы и свойства, чем отличаются от обычных", 135 | }, 136 | // Git 137 | // Краткие ответы - https://hackr.io/blog/git-interview-questions 138 | { 139 | "text": "Что такое Git и в чём отличие от GitHub", 140 | }, 141 | { 142 | "text": "Назовите некоторые наиболее часто используемые команды Git", 143 | }, 144 | { 145 | "text": "Что такое head с точки зрения Git", 146 | }, 147 | { 148 | "text": "Что такое конфликт с точки зрения Git и какие есть пути решения", 149 | }, 150 | { 151 | "text": "Каким образом можно переключиться на другую ветку не делая коммит сделанных изменений", 152 | }, 153 | { 154 | "text": "Опишите стратегию ветвления GitFlow", 155 | }, 156 | // Database 157 | // Очень просто - https://habr.com/ru/articles/555760/ 158 | { 159 | "text": "Для чего нужны базы данных, примеры популярных", 160 | }, 161 | // PHP 162 | // Побольше вопросов - https://github.com/ivan-isaev21/250-questions-PHP/blob/master/Junior/README.MD 163 | { 164 | "text": "Базовый синтаксис PHP, как объявить переменную, функцию, класс и объект", 165 | }, 166 | { 167 | "text": "Что такое сессия в PHP, как хранится", 168 | }, 169 | ]; 170 | 171 | function fillQuestions() { 172 | const container = document.querySelector('.js-questions'); 173 | 174 | if (container === undefined) { 175 | console.error('Ошибка! Не смогли найти элемент .js-questions на странице.'); 176 | return; 177 | } 178 | 179 | questions.map((question) => { 180 | const node = document.createElement('li'); 181 | node.textContent = question.text; 182 | container.appendChild(node); 183 | }); 184 | } 185 | 186 | function generateRandom(count, clear) { 187 | const container = document.querySelector('.js-random-questions'); 188 | 189 | if (container === undefined) { 190 | console.error('Ошибка! Не смогли найти элемент .js-random-questions на странице.'); 191 | return; 192 | } 193 | 194 | if (clear) { 195 | container.innerHTML = ''; 196 | } 197 | 198 | questions 199 | .sort(() => Math.random() - 0.5) 200 | .slice(0, count) 201 | .map((question) => { 202 | const node = document.createElement('li'); 203 | node.textContent = question.text; 204 | container.appendChild(node); 205 | }); 206 | 207 | window.scrollTo(0, document.body.scrollHeight); 208 | } 209 | 210 | function listenButtons() { 211 | const buttonAll = document.querySelector('.js-generate-random'); 212 | const buttonOne = document.querySelector('.js-generate-random-one'); 213 | 214 | if (buttonAll === undefined || buttonOne === undefined) { 215 | console.error('Ошибка! Не смогли найти элементы .js-generate-random на странице.'); 216 | return; 217 | } 218 | 219 | buttonAll.addEventListener('click', () => generateRandom(5, true)); 220 | buttonOne.addEventListener('click', () => generateRandom(1)); 221 | } 222 | 223 | function startApp() { 224 | fillQuestions(); 225 | listenButtons(); 226 | } 227 | 228 | document.addEventListener('DOMContentLoaded', startApp); -------------------------------------------------------------------------------- /practice-02/services/QuestionsService.php: -------------------------------------------------------------------------------- 1 | "Что происходит в браузере после перехода по url", 15 | 'frequency' => 100 16 | ], 17 | [ 18 | 'text' => "Что такое клиент-серверная архитектура, какие особенности", 19 | 'frequency' => 50 20 | ], 21 | [ 22 | 'text' => "Расшифруйте HTTP, какие есть актуальные версии", 23 | 'frequency' => 40 24 | ], 25 | [ 26 | 'text' => "Какие бывают типы HTTP-запросов", 27 | 'frequency' => 30 28 | ], 29 | [ 30 | 'text' => "Какие бывают коды состояния ответа HTTP (категории в сотнях)", 31 | 'frequency' => 10 32 | ], 33 | [ 34 | 'text' => "Что такое CORS, зачем нужен, как избежать", 35 | 'frequency' => 10 36 | ], 37 | [ 38 | 'text' => "Что такое REST API, примеры url", 39 | 'frequency' => 10 40 | ], 41 | [ 42 | 'text' => "Что такое GraphQL, примеры тела запроса", 43 | 'frequency' => 10 44 | ], 45 | [ 46 | 'text' => "Что такое Cookie и зачем они используются", 47 | ], 48 | [ 49 | 'text' => "Что такое сложность алгоритма, нотация О большое", 50 | ], 51 | [ 52 | 'text' => "Что такое каскад в CSS, несколько примеров", 53 | ], 54 | [ 55 | 'text' => "Что такое специфичность в CSS, как рассчитывается, примеры расчетов", 56 | ], 57 | [ 58 | 'text' => "Что такое наследование в CSS, какие свойства наследуются, как контролировать", 59 | ], 60 | [ 61 | 'text' => "Что такое препроцессоры и постпроцессоры в CSS, перечислить основные", 62 | ], 63 | [ 64 | 'text' => "Для чего нужны media-запросы в CSS, как работают", 65 | ], 66 | [ 67 | 'text' => "Какие бывают типы позиционирования в CSS, в чём особенности", 68 | ], 69 | [ 70 | 'text' => "Какие бывают значения у свойства display в CSS, в чём отличия", 71 | ], 72 | [ 73 | 'text' => "Что такое доступность и как обеспечивается доступность в браузере (HTML)", 74 | ], 75 | [ 76 | 'text' => "Что такое window и в чём отличие от document", 77 | ], 78 | [ 79 | 'text' => "Какие различия между let, var и const", 80 | ], 81 | [ 82 | 'text' => "Какие есть типы данных в JS", 83 | ], 84 | [ 85 | 'text' => "Какие различия между примитивными и ссылочными типами", 86 | ], 87 | [ 88 | 'text' => "Как работает приведение типов в JS, примеры с == и ===", 89 | ], 90 | [ 91 | 'text' => "Что такое область видимости в JS, несколько примеров", 92 | ], 93 | [ 94 | 'text' => "Что такое localStorage и в чём отличие от sessionStorage", 95 | ], 96 | [ 97 | 'text' => "Что такое fetch, основные options и процесс получения результата", 98 | ], 99 | [ 100 | 'text' => "Что такое JSON, примеры использования", 101 | ], 102 | [ 103 | 'text' => "Какие основные библиотеки для JS, в чём отличия", 104 | ], 105 | [ 106 | 'text' => "В чём отличия между библиотекой и фреймворком", 107 | ], 108 | [ 109 | 'text' => "Что такое менеджер пакетов, как работает npm", 110 | ], 111 | [ 112 | 'text' => "Опишите базовые принципы ООП", 113 | ], 114 | [ 115 | 'text' => "Назовите несколько паттернов проектирования", 116 | ], 117 | [ 118 | 'text' => "Что такое класс и объект, в чём разница", 119 | ], 120 | [ 121 | 'text' => "Что такое абстрактный класс, примеры применения", 122 | ], 123 | [ 124 | 'text' => "Что такое интерфейс, примеры применения", 125 | ], 126 | [ 127 | 'text' => "Что такое DRY, как расшифровывается, пара примеров", 128 | ], 129 | [ 130 | 'text' => "Что такое KISS, как расшифровывается, пара примеров", 131 | ], 132 | [ 133 | 'text' => "Что такое SOLID, как расшифровывается, пара примеров", 134 | ], 135 | [ 136 | 'text' => "В чем разница между модификаторами доступа public, private и protected", 137 | ], 138 | [ 139 | 'text' => "Что такое конструктор класса", 140 | ], 141 | [ 142 | 'text' => "Что такое статические методы и свойства, чем отличаются от обычных", 143 | ], 144 | [ 145 | 'text' => "Что такое Git и в чём отличие от GitHub", 146 | ], 147 | [ 148 | 'text' => "Назовите некоторые наиболее часто используемые команды Git", 149 | ], 150 | [ 151 | 'text' => "Что такое head с точки зрения Git", 152 | ], 153 | [ 154 | 'text' => "Что такое конфликт с точки зрения Git и какие есть пути решения", 155 | ], 156 | [ 157 | 'text' => "Каким образом можно переключиться на другую ветку не делая коммит сделанных изменений", 158 | ], 159 | [ 160 | 'text' => "Опишите стратегию ветвления GitFlow", 161 | ], 162 | [ 163 | 'text' => "Для чего нужны базы данных, примеры популярных", 164 | ], 165 | [ 166 | 'text' => "Базовый синтаксис PHP, как объявить переменную, функцию, класс и объект", 167 | ], 168 | [ 169 | 'text' => "Что такое сессия в PHP, как хранится", 170 | ], 171 | ]; 172 | 173 | public function getQuestions(): array 174 | { 175 | $questions = self::QUESTIONS; 176 | 177 | if (isset($_SESSION['questions'])) { 178 | $questions = array_merge($_SESSION['questions'], $questions); 179 | } 180 | 181 | $randomSmileService = new RandomSmileService(); 182 | 183 | return array_map(function($item) use ($randomSmileService) { 184 | $item['smile'] = $randomSmileService->getSmile(); 185 | return $item; 186 | }, $questions); 187 | } 188 | 189 | public function addQuestion(string $question): void 190 | { 191 | if (!isset($_SESSION['questions'])) { 192 | $_SESSION['questions'] = []; 193 | } 194 | 195 | $_SESSION['questions'][] = ['text' => $question]; 196 | } 197 | 198 | public function getQuestionsText(): array 199 | { 200 | $all = $this->getQuestions(); 201 | 202 | return array_map(function($el) { 203 | return $el['text']; 204 | }, $all); 205 | } 206 | 207 | public function getPaginatedQuestions(int $page, int $pageSize): array 208 | { 209 | $allQuestions = $this->getQuestions(); 210 | $questions = array_slice($allQuestions, ($page - 1) * $pageSize, $pageSize); 211 | 212 | return [ 213 | 'questions' => $questions, 214 | 'totalQuestions' => count($allQuestions), 215 | ]; 216 | } 217 | 218 | public function calculateQuestionFrequencies(): array 219 | { 220 | $questions = $this->getQuestions(); 221 | $frequencies = []; 222 | 223 | foreach ($questions as $question) { 224 | $text = $question['text']; 225 | $frequencies[$text] = $question['frequency'] ?? 1; 226 | } 227 | 228 | return $frequencies; 229 | } 230 | } -------------------------------------------------------------------------------- /practice-01/questions.js: -------------------------------------------------------------------------------- 1 | const questions = [ 2 | // -- Basics 3 | { 4 | "text": "Что происходит в браузере после перехода по url", 5 | "tags": ["Basics"], 6 | "frequency": 100, 7 | }, 8 | { 9 | "text": "Что такое клиент-серверная архитектура, какие особенности", 10 | "tags": ["Basics"], 11 | }, 12 | { 13 | "text": "Расшифруйте HTTP, какие есть актуальные версии", 14 | "tags": ["Basics "] 15 | }, 16 | { 17 | "text": "Какие бывают типы HTTP-запросов", 18 | "tags": ["Basics"] 19 | }, 20 | { 21 | "text": "Какие бывают коды состояния ответа HTTP (категории в сотнях)", 22 | "tags": ["Basics"] 23 | }, 24 | { 25 | "text": "Что такое CORS, зачем нужен, как избежать", 26 | "tags": ["Basics"] 27 | }, 28 | { 29 | "text": "Что такое REST API, примеры url", 30 | "tags": ["Basics"] 31 | }, 32 | { 33 | "text": "Что такое GraphQL, примеры тела запроса", 34 | "tags": ["Basics"] 35 | }, 36 | { 37 | "text": "Что такое Cookie и зачем они используются", 38 | "tags": ["Basics"] 39 | }, 40 | { 41 | "text": "Что такое сложность алгоритма, нотация О большое", 42 | "tags": ["Basics"] 43 | }, 44 | // -- CSS 45 | { 46 | "text": "Что такое каскад в CSS, несколько примеров", 47 | "tags": ["CSS"] 48 | }, 49 | { 50 | "text": "Что такое специфичность в CSS, как рассчитывается, примеры расчетов", 51 | "tags": ["CSS"] 52 | }, 53 | { 54 | "text": "Что такое наследование в CSS, какие свойства наследуются, как контролировать", 55 | "tags": ["CSS"] 56 | }, 57 | { 58 | "text": "Что такое препроцессоры и постпроцессоры в CSS, перечислить основные", 59 | "tags": ["CSS"] 60 | }, 61 | { 62 | "text": "Для чего нужны media-запросы в CSS, как работают", 63 | "tags": ["CSS"] 64 | }, 65 | { 66 | "text": "Какие бывают типы позиционирования в CSS, в чём особенности", 67 | "tags": ["CSS"] 68 | }, 69 | { 70 | "text": "Какие бывают значения у свойства display в CSS, в чём отличия", 71 | "tags": ["CSS"] 72 | }, 73 | { 74 | "text": "Что такое доступность и как обеспечивается доступность в браузере (HTML)", 75 | "tags": ["CSS"] 76 | }, 77 | // -- JS 78 | { 79 | "text": "Что такое window и в чём отличие от document", 80 | "tags": ["JS"] 81 | }, 82 | { 83 | "text": "Какие различия между let, var и const", 84 | "tags": ["JS"] 85 | }, 86 | { 87 | "text": "Какие есть типы данных в JS", 88 | "tags": ["JS"] 89 | }, 90 | { 91 | "text": "Какие различия между примитивными и ссылочными типами", 92 | "tags": ["JS"] 93 | }, 94 | { 95 | "text": "Как работает приведение типов в JS, примеры с == и ===", 96 | "tags": ["JS"] 97 | }, 98 | { 99 | "text": "Что такое область видимости в JS, несколько примеров", 100 | "tags": ["JS"] 101 | }, 102 | { 103 | "text": "Что такое localStorage и в чём отличие от sessionStorage", 104 | "tags": ["JS"] 105 | }, 106 | { 107 | "text": "Что такое fetch, основные options и процесс получения результата", 108 | "tags": ["JS"] 109 | }, 110 | { 111 | "text": "Что такое JSON, примеры использования", 112 | "tags": ["JS"] 113 | }, 114 | { 115 | "text": "Какие основные библиотеки для JS, в чём отличия", 116 | "tags": ["JS"] 117 | }, 118 | { 119 | "text": "В чём отличия между библиотекой и фреймворком", 120 | "tags": ["JS"] 121 | }, 122 | { 123 | "text": "Что такое менеджер пакетов, как работает npm", 124 | "tags": ["JS"] 125 | }, 126 | // -- OOP 127 | { 128 | "text": "Опишите базовые принципы ООП", 129 | "tags": ["OOP"] 130 | }, 131 | { 132 | "text": "Назовите несколько паттернов проектирования", 133 | "tags": ["OOP"] 134 | }, 135 | { 136 | "text": "Что такое класс и объект, в чём разница", 137 | "tags": ["OOP"] 138 | }, 139 | 140 | { 141 | "text": "Что такое абстрактный класс, примеры применения", 142 | "tags": ["OOP"] 143 | }, 144 | { 145 | "text": "Что такое интерфейс, примеры применения", 146 | "tags": ["OOP"] 147 | }, 148 | { 149 | "text": "Что такое DRY, как расшифровывается, пара примеров", 150 | "tags": ["OOP"] 151 | }, 152 | { 153 | "text": "Что такое KISS, как расшифровывается, пара примеров", 154 | "tags": ["OOP"] 155 | }, 156 | { 157 | "text": "Что такое SOLID, как расшифровывается, пара примеров", 158 | "tags": ["OOP"] 159 | }, 160 | { 161 | "text": "В чем разница между модификаторами доступа public, private и protected", 162 | "tags": ["OOP"] 163 | }, 164 | { 165 | "text": "Что такое конструктор класса", 166 | "tags": ["OOP"] 167 | }, 168 | { 169 | "text": "Что такое статические методы и свойства, чем отличаются от обычных", 170 | "tags": ["OOP"] 171 | }, 172 | // Git 173 | // Краткие ответы - https://hackr.io/blog/git-interview-questions 174 | { 175 | "text": "Что такое Git и в чём отличие от GitHub", 176 | "tags": ["Git"] 177 | }, 178 | { 179 | "text": "Назовите некоторые наиболее часто используемые команды Git", 180 | "tags": ["Git"] 181 | }, 182 | { 183 | "text": "Что такое head с точки зрения Git", 184 | "tags": ["Git"] 185 | }, 186 | { 187 | "text": "Что такое конфликт с точки зрения Git и какие есть пути решения", 188 | "tags": ["Git"] 189 | }, 190 | { 191 | "text": "Каким образом можно переключиться на другую ветку не делая коммит сделанных изменений", 192 | "tags": ["Git"] 193 | }, 194 | { 195 | "text": "Опишите стратегию ветвления GitFlow", 196 | "tags": ["Git"] 197 | }, 198 | { 199 | "text": "Какие есть способы слияния веток (default, squash, rebase)", 200 | "tags": ["Git"] 201 | }, 202 | // Database 203 | // Очень просто - https://habr.com/ru/articles/555760/ 204 | { 205 | "text": "Для чего нужны базы данных, примеры популярных", 206 | "tags": ["Database"] 207 | }, 208 | { 209 | "text": "Какие есть типы связей в базе данных, пример для каждого", 210 | "tags": ["Database"] 211 | }, 212 | { 213 | "text": "Что такое ключи, какие бывают, как использовать", 214 | "tags": ["Database"] 215 | }, 216 | { 217 | "text": "Что такое индексы, опишите структуру данных (btree)", 218 | "tags": ["Database"] 219 | }, 220 | { 221 | "text": "Что такое индексы, опишите структуру данных (btree)", 222 | "tags": ["Database"] 223 | }, 224 | { 225 | "text": "Что такое транзакции, расшифруйте ACID", 226 | "tags": ["Database"] 227 | }, 228 | { 229 | "text": "Что такое миграции и для чего они нужны", 230 | "tags": ["Database"] 231 | }, 232 | { 233 | "text": "Какие четыре основных типа JOIN в SQL", 234 | "tags": ["Database"] 235 | }, 236 | { 237 | "text": "В чём разница между DELETE и TRUNCATE", 238 | "tags": ["Database"] 239 | }, 240 | { 241 | "text": "В чём разница между WHERE и HAVING", 242 | "tags": ["Database"] 243 | }, 244 | // PHP 245 | // Побольше вопросов - https://github.com/ivan-isaev21/250-questions-PHP/blob/master/Junior/README.MD 246 | { 247 | "text": "Базовый синтаксис PHP, как объявить переменную, функцию, класс и объект", 248 | "tags": ["PHP"] 249 | }, 250 | { 251 | "text": "Что такое менеджер зависимостей, как работает composer", 252 | "tags": ["PHP"] 253 | } 254 | // остальные вопросы... 255 | ]; 256 | 257 | export default questions; 258 | -------------------------------------------------------------------------------- /lecture03/advanced/chugaev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chugaev 8 | 9 | 10 |
                11 |

                Chugaev

                12 |
                13 |

                14 | Нажмите на квадраты ниже, чтобы изменить цвет 15 |

                16 |
                17 |
                18 |
                19 | 20 | 21 | 22 | 23 | 24 |
                25 |
                26 | 93 | 215 |
                216 | 217 | -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/sections/_graph.scss: -------------------------------------------------------------------------------- 1 | .graph { 2 | 3 | 4 | grid-template-columns: 264px 1fr; 5 | grid-gap: 16px; 6 | display: grid; 7 | 8 | 9 | &__qualification { 10 | background-color: var(--color-white); 11 | border-radius: 8px; 12 | padding: 24px; 13 | } 14 | 15 | &__qualification-title { 16 | margin: 0; 17 | font-weight: 700; 18 | 19 | font-size: 21px; 20 | line-height: 27px; 21 | } 22 | 23 | &__qualification-options { 24 | margin-top: 24px; 25 | } 26 | 27 | &__diagram { 28 | align-items: flex-start; 29 | display: flex; 30 | justify-content: space-between; 31 | flex-wrap: wrap; 32 | gap: 24px; 33 | 34 | background-color: var(--color-white); 35 | border-radius: 8px; 36 | padding: 24px; 37 | } 38 | 39 | &__diagram-header { 40 | display: flex; 41 | align-items: flex-start; 42 | justify-content: space-between; 43 | width: 100%; 44 | gap: 20px; 45 | } 46 | 47 | &__diagram-title { 48 | margin: 0; 49 | font-weight: 700; 50 | line-height: 27px; 51 | font-size: 21px; 52 | } 53 | 54 | &__diagram-share { 55 | gap: 8px; 56 | font-size: 14px; 57 | } 58 | } 59 | 60 | .qualification { 61 | 62 | cursor: pointer; 63 | 64 | display: block; 65 | position: relative; 66 | margin-bottom: 16px; 67 | border-radius: 8px; 68 | border: 2px solid transparent; 69 | background-color: var(--color-gray-light-2); 70 | 71 | &_active { 72 | border-color: var(--color-toggle-border); 73 | 74 | .qualification__text { 75 | background: linear-gradient(0deg, rgba(154, 135, 249, .16), rgba(154, 135, 249, .16)), var(--color-white); 76 | } 77 | } 78 | 79 | &__text { 80 | position: relative; 81 | 82 | padding: 13px 16px; 83 | display: flex; 84 | border-radius: 6px; 85 | justify-content: space-between; 86 | height: 100%; 87 | } 88 | 89 | &__level {} 90 | 91 | &__salary { 92 | font-weight: 700; 93 | } 94 | 95 | &__radio { 96 | cursor: pointer; 97 | 98 | position: absolute; 99 | opacity: 0; 100 | left: 0; 101 | right: 0; 102 | top: 0; 103 | bottom: 0; 104 | } 105 | 106 | &__avatar { 107 | border: 2px solid var(--color-ui-orange); 108 | border-radius: 50%; 109 | display: block; 110 | overflow: hidden; 111 | -o-object-fit: cover; 112 | object-fit: cover; 113 | margin-right: auto; 114 | margin-left: 8px; 115 | } 116 | } 117 | 118 | .graph-content { 119 | align-items: flex-start; 120 | display: flex; 121 | justify-content: space-between; 122 | gap: 24px; 123 | flex-wrap: wrap; 124 | 125 | &__salary {} 126 | 127 | &__salary-main { 128 | font-weight: 700; 129 | display: flex; 130 | 131 | font-size: 42px; 132 | line-height: 54px; 133 | margin-bottom: 10px; 134 | } 135 | 136 | &__salary-sub { 137 | display: flex; 138 | gap: 8px; 139 | } 140 | 141 | &__salary-divider { 142 | font-size: 21px; 143 | line-height: 27px; 144 | font-weight: 700; 145 | } 146 | 147 | &__salary-block { 148 | display: flex; 149 | font-size: 21px; 150 | line-height: 27px; 151 | font-weight: 700; 152 | flex-direction: column; 153 | } 154 | 155 | &__salary-value { 156 | font-size: 21px; 157 | line-height: 27px; 158 | font-weight: 700; 159 | } 160 | 161 | &__salary-comment { 162 | font-size: 16px; 163 | line-height: 20px; 164 | font-weight: 400; 165 | color: var(--color-gray-dark); 166 | display: flex; 167 | gap: 2px; 168 | 169 | svg { 170 | width: 20px; 171 | height: 20px; 172 | fill: currentColor; 173 | } 174 | } 175 | 176 | 177 | &__info { 178 | display: flex; 179 | align-items: center; 180 | row-gap: 8px; 181 | -moz-column-gap: 16px; 182 | column-gap: 16px; 183 | flex-wrap: wrap; 184 | width: 100%; 185 | } 186 | 187 | 188 | &__found-circle { 189 | display: inline-block; 190 | 191 | width: 12px; 192 | height: 12px; 193 | border-radius: 6px; 194 | margin-right: 8px; 195 | } 196 | 197 | &__found_rare { 198 | .graph-content__found-circle { 199 | background: #e4e4e4; 200 | } 201 | } 202 | 203 | &__found_often { 204 | .graph-content__found-circle { 205 | background: var(--color-bar-blueviolet); 206 | } 207 | } 208 | 209 | 210 | &__counter { 211 | text-align: right; 212 | flex-grow: 1; 213 | color: var(--color-gray-dark); 214 | } 215 | 216 | &__counter-text { 217 | border-bottom: 1px dashed rgba(0, 0, 0, .3); 218 | cursor: pointer; 219 | } 220 | } 221 | 222 | 223 | .salary-bar { 224 | margin-bottom: 55px; 225 | margin-top: 75px; 226 | width: 100%; 227 | 228 | &__container { 229 | width: 100%; 230 | height: 36px; 231 | position: relative; 232 | background: var(--color-bar-grey); 233 | border-radius: 8px; 234 | } 235 | 236 | &__container--left-avatar {} 237 | 238 | &__min { 239 | left: 0; 240 | } 241 | 242 | &__max { 243 | right: 0; 244 | } 245 | 246 | &__min, 247 | &__max { 248 | position: absolute; 249 | font-weight: 700; 250 | color: var(--color-gray-dark); 251 | top: calc(100% + 4px); 252 | cursor: pointer; 253 | } 254 | 255 | &__circle-container { 256 | overflow: hidden; 257 | position: absolute; 258 | top: 0; 259 | padding: 16px 24px 0; 260 | display: flex; 261 | justify-content: space-between; 262 | width: 100%; 263 | height: 36px; 264 | } 265 | 266 | &__circle-item { 267 | width: 4px; 268 | height: 4px; 269 | background: var(--color-gray-light-3); 270 | border-radius: 50%; 271 | } 272 | 273 | &__sub-bar { 274 | position: absolute; 275 | height: 36px; 276 | background: var(--color-blueviolet-gradient); 277 | border: 2px solid var(--color-white); 278 | box-shadow: 0 4px 16px #8e7af63d; 279 | border-radius: 8px; 280 | left: 20.1711%; 281 | right: 25.5064%; 282 | top: 0; 283 | } 284 | 285 | &__sub-bar-min { 286 | position: absolute; 287 | font-weight: 700; 288 | color: var(--color-bar-blueviolet); 289 | top: calc(100% + 6px); 290 | cursor: pointer; 291 | left: 0; 292 | } 293 | 294 | &__sub-bar-max { 295 | position: absolute; 296 | font-weight: 700; 297 | color: var(--color-bar-blueviolet); 298 | top: calc(100% + 6px); 299 | cursor: pointer; 300 | right: 0; 301 | } 302 | 303 | &__median-divider { 304 | border-radius: 6px; 305 | height: 24px; 306 | width: 4px; 307 | top: 6px; 308 | background: var(--color-white); 309 | box-shadow: 0 5px 25px #0000001a; 310 | position: absolute; 311 | transform: translate(-50%); 312 | left: 44.9959%; 313 | } 314 | 315 | &__median-arrow { 316 | width: 12px; 317 | height: 12px; 318 | left: 44.9959%; 319 | bottom: -30px; 320 | fill: var(--color-bar-blueviolet); 321 | transform: translate(-50%) rotate(180deg); 322 | position: absolute; 323 | } 324 | 325 | &__median-divider-value { 326 | bottom: -53px; 327 | font-size: 18px; 328 | font-weight: 700; 329 | color: var(--color-font-black); 330 | cursor: pointer; 331 | left: 44.9959%; 332 | position: absolute; 333 | transform: translate(-50%); 334 | } 335 | 336 | &__my-avatar { 337 | top: -64px; 338 | border: 2px solid var(--color-ui-orange); 339 | padding: 2px; 340 | cursor: pointer; 341 | transform: translate(0); 342 | left: 12px; 343 | position: absolute; 344 | border-radius: 50%; 345 | 346 | } 347 | 348 | &__avatar-arrow { 349 | width: 12px; 350 | height: 12px; 351 | transform: rotate(90deg); 352 | top: -48px; 353 | left: -4px; 354 | 355 | fill: var(--color-ui-orange); 356 | position: absolute; 357 | } 358 | } -------------------------------------------------------------------------------- /lecture04/basic/kuznetsov/scss/style.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=PT+Sans:regular,italic,700,700italic); 2 | :root { 3 | --color-white: #fff; 4 | --color-gray: #eee; 5 | --color-gray-light: #c4c4c4; 6 | --color-gray-dark: #999; 7 | --color-gray-light-2: #f4f4f4; 8 | --color-gray-light-3: #e4e4e4; 9 | --color-gray-3: #4d5057; 10 | --color-icon-gray: #929ca5; 11 | --color-icon-purple: #a876d0; 12 | --color-icon-purple-light: #c09cdd; 13 | --color-ui-gray-bg: #ededed; 14 | --color-ui-checkbox-bg: #666; 15 | --color-ui-lightgray: #f7f7f7; 16 | --color-link-blue: #1463d9; 17 | --color-ui-blue: #5677fc; 18 | --color-ui-blue-overlay: rgba(86, 119, 252, .12); 19 | --color-font-black: #464646; 20 | --color-font-gray: #757575; 21 | --color-ui-red: #d34c09; 22 | --color-ui-red-overlay: rgba(211, 76, 9, .12); 23 | --color-ui-red-second: #ff7e75; 24 | --color-ui-green: #64c178; 25 | --color-ui-green-overlay: rgba(100, 193, 120, .12); 26 | --color-ui-yellow: #e8a700; 27 | --color-ui-orange: #f9a21f; 28 | --color-ui-yellow-overlay: rgba(232, 167, 0, .12); 29 | --color-green: #0c8326; 30 | --color-ui-overlay: rgba(70, 70, 70, .5); 31 | --color-input-focus: #f5f6f7; 32 | --color-light-purple: #dbdbff; 33 | --color-light-purple2: #8F7BF6; 34 | --color-button-range-active: #be86eb; 35 | --color-chip-bg-inactive: #ebf3ff; 36 | --color-chip-bg-hover: #d1e4ff; 37 | --color-chip-bg-press: #b8d5ff; 38 | --color-chip-border: #a3c4f5; 39 | --color-bar-blueviolet: #9f8cfa; 40 | --color-blueviolet-gradient: linear-gradient(90deg, #b09fff 0%, #8d79f6 100%); 41 | --color-bar-grey: rgba(237, 237, 237, .6); 42 | --color-toggle-border: #9783fc; 43 | } 44 | 45 | body { 46 | font-family: "PT Sans", sans-serif; 47 | background-color: var(--color-gray); 48 | color: var(--color-font-black); 49 | } 50 | 51 | *, 52 | *::before, 53 | *::after { 54 | box-sizing: border-box; 55 | margin: 0; 56 | padding: 0; 57 | } 58 | 59 | .container { 60 | padding: 0 12px; 61 | margin: 0 auto; 62 | max-width: 1100px; 63 | } 64 | 65 | .svg-icon { 66 | fill: currentColor; 67 | width: 24px; 68 | height: 24px; 69 | } 70 | 71 | .base-button { 72 | padding: 0; 73 | background-color: transparent; 74 | border-radius: 0; 75 | border: none; 76 | text-align: inherit; 77 | outline: 0; 78 | display: inline-flex; 79 | align-items: center; 80 | justify-content: center; 81 | color: inherit; 82 | cursor: pointer; 83 | } 84 | 85 | .base-button--size-l { 86 | padding: 7px 15px; 87 | min-height: 36px; 88 | font-weight: 700; 89 | font-size: 16px; 90 | line-height: 20px; 91 | } 92 | 93 | .base-button--appearance-extra { 94 | border-radius: 4px; 95 | background: transparent; 96 | color: var(--color-gray-3); 97 | font-weight: 700; 98 | border: 1px solid var(--color-ui-gray-bg); 99 | } 100 | 101 | .base-dropdown__toggle > * { 102 | cursor: pointer; 103 | } 104 | 105 | .base-button--appearance-extra:hover { 106 | background-color: var(--color-gray-light-2); 107 | } 108 | 109 | .base-button:hover { 110 | text-decoration: none; 111 | } 112 | 113 | .graph { 114 | grid-template-columns: 264px 1fr; 115 | grid-gap: 16px; 116 | display: grid; 117 | } 118 | .graph__qualification { 119 | background-color: var(--color-white); 120 | border-radius: 8px; 121 | padding: 24px; 122 | } 123 | .graph__qualification-title { 124 | margin: 0; 125 | font-weight: 700; 126 | font-size: 21px; 127 | line-height: 27px; 128 | } 129 | .graph__qualification-options { 130 | margin-top: 24px; 131 | } 132 | .graph__diagram { 133 | align-items: flex-start; 134 | display: flex; 135 | justify-content: space-between; 136 | flex-wrap: wrap; 137 | gap: 24px; 138 | background-color: var(--color-white); 139 | border-radius: 8px; 140 | padding: 24px; 141 | } 142 | .graph__diagram-header { 143 | display: flex; 144 | align-items: flex-start; 145 | justify-content: space-between; 146 | width: 100%; 147 | gap: 20px; 148 | } 149 | .graph__diagram-title { 150 | margin: 0; 151 | font-weight: 700; 152 | line-height: 27px; 153 | font-size: 21px; 154 | } 155 | .graph__diagram-share { 156 | gap: 8px; 157 | font-size: 14px; 158 | } 159 | 160 | .qualification { 161 | cursor: pointer; 162 | display: block; 163 | position: relative; 164 | margin-bottom: 16px; 165 | border-radius: 8px; 166 | border: 2px solid transparent; 167 | background-color: var(--color-gray-light-2); 168 | } 169 | .qualification_active { 170 | border-color: var(--color-toggle-border); 171 | } 172 | .qualification_active .qualification__text { 173 | background: linear-gradient(0deg, rgba(154, 135, 249, 0.16), rgba(154, 135, 249, 0.16)), var(--color-white); 174 | } 175 | .qualification__text { 176 | position: relative; 177 | padding: 13px 16px; 178 | display: flex; 179 | border-radius: 6px; 180 | justify-content: space-between; 181 | height: 100%; 182 | } 183 | .qualification__salary { 184 | font-weight: 700; 185 | } 186 | .qualification__radio { 187 | cursor: pointer; 188 | position: absolute; 189 | opacity: 0; 190 | left: 0; 191 | right: 0; 192 | top: 0; 193 | bottom: 0; 194 | } 195 | .qualification__avatar { 196 | border: 2px solid var(--color-ui-orange); 197 | border-radius: 50%; 198 | display: block; 199 | overflow: hidden; 200 | -o-object-fit: cover; 201 | object-fit: cover; 202 | margin-right: auto; 203 | margin-left: 8px; 204 | } 205 | 206 | .graph-content { 207 | align-items: flex-start; 208 | display: flex; 209 | justify-content: space-between; 210 | gap: 24px; 211 | flex-wrap: wrap; 212 | } 213 | .graph-content__salary-main { 214 | font-weight: 700; 215 | display: flex; 216 | font-size: 42px; 217 | line-height: 54px; 218 | margin-bottom: 10px; 219 | } 220 | .graph-content__salary-sub { 221 | display: flex; 222 | gap: 8px; 223 | } 224 | .graph-content__salary-divider { 225 | font-size: 21px; 226 | line-height: 27px; 227 | font-weight: 700; 228 | } 229 | .graph-content__salary-block { 230 | display: flex; 231 | font-size: 21px; 232 | line-height: 27px; 233 | font-weight: 700; 234 | flex-direction: column; 235 | } 236 | .graph-content__salary-value { 237 | font-size: 21px; 238 | line-height: 27px; 239 | font-weight: 700; 240 | } 241 | .graph-content__salary-comment { 242 | font-size: 16px; 243 | line-height: 20px; 244 | font-weight: 400; 245 | color: var(--color-gray-dark); 246 | display: flex; 247 | gap: 2px; 248 | } 249 | .graph-content__salary-comment svg { 250 | width: 20px; 251 | height: 20px; 252 | fill: currentColor; 253 | } 254 | .graph-content__info { 255 | display: flex; 256 | align-items: center; 257 | row-gap: 8px; 258 | -moz-column-gap: 16px; 259 | column-gap: 16px; 260 | flex-wrap: wrap; 261 | width: 100%; 262 | } 263 | .graph-content__found-circle { 264 | display: inline-block; 265 | width: 12px; 266 | height: 12px; 267 | border-radius: 6px; 268 | margin-right: 8px; 269 | } 270 | .graph-content__found_rare .graph-content__found-circle { 271 | background: #e4e4e4; 272 | } 273 | .graph-content__found_often .graph-content__found-circle { 274 | background: var(--color-bar-blueviolet); 275 | } 276 | .graph-content__counter { 277 | text-align: right; 278 | flex-grow: 1; 279 | color: var(--color-gray-dark); 280 | } 281 | .graph-content__counter-text { 282 | border-bottom: 1px dashed rgba(0, 0, 0, 0.3); 283 | cursor: pointer; 284 | } 285 | 286 | .salary-bar { 287 | margin-bottom: 55px; 288 | margin-top: 75px; 289 | width: 100%; 290 | } 291 | .salary-bar__container { 292 | width: 100%; 293 | height: 36px; 294 | position: relative; 295 | background: var(--color-bar-grey); 296 | border-radius: 8px; 297 | } 298 | .salary-bar__min { 299 | left: 0; 300 | } 301 | .salary-bar__max { 302 | right: 0; 303 | } 304 | .salary-bar__min, .salary-bar__max { 305 | position: absolute; 306 | font-weight: 700; 307 | color: var(--color-gray-dark); 308 | top: calc(100% + 4px); 309 | cursor: pointer; 310 | } 311 | .salary-bar__circle-container { 312 | overflow: hidden; 313 | position: absolute; 314 | top: 0; 315 | padding: 16px 24px 0; 316 | display: flex; 317 | justify-content: space-between; 318 | width: 100%; 319 | height: 36px; 320 | } 321 | .salary-bar__circle-item { 322 | width: 4px; 323 | height: 4px; 324 | background: var(--color-gray-light-3); 325 | border-radius: 50%; 326 | } 327 | .salary-bar__sub-bar { 328 | position: absolute; 329 | height: 36px; 330 | background: var(--color-blueviolet-gradient); 331 | border: 2px solid var(--color-white); 332 | box-shadow: 0 4px 16px rgba(142, 122, 246, 0.2392156863); 333 | border-radius: 8px; 334 | left: 20.1711%; 335 | right: 25.5064%; 336 | top: 0; 337 | } 338 | .salary-bar__sub-bar-min { 339 | position: absolute; 340 | font-weight: 700; 341 | color: var(--color-bar-blueviolet); 342 | top: calc(100% + 6px); 343 | cursor: pointer; 344 | left: 0; 345 | } 346 | .salary-bar__sub-bar-max { 347 | position: absolute; 348 | font-weight: 700; 349 | color: var(--color-bar-blueviolet); 350 | top: calc(100% + 6px); 351 | cursor: pointer; 352 | right: 0; 353 | } 354 | .salary-bar__median-divider { 355 | border-radius: 6px; 356 | height: 24px; 357 | width: 4px; 358 | top: 6px; 359 | background: var(--color-white); 360 | box-shadow: 0 5px 25px rgba(0, 0, 0, 0.1019607843); 361 | position: absolute; 362 | transform: translate(-50%); 363 | left: 44.9959%; 364 | } 365 | .salary-bar__median-arrow { 366 | width: 12px; 367 | height: 12px; 368 | left: 44.9959%; 369 | bottom: -30px; 370 | fill: var(--color-bar-blueviolet); 371 | transform: translate(-50%) rotate(180deg); 372 | position: absolute; 373 | } 374 | .salary-bar__median-divider-value { 375 | bottom: -53px; 376 | font-size: 18px; 377 | font-weight: 700; 378 | color: var(--color-font-black); 379 | cursor: pointer; 380 | left: 44.9959%; 381 | position: absolute; 382 | transform: translate(-50%); 383 | } 384 | .salary-bar__my-avatar { 385 | top: -64px; 386 | border: 2px solid var(--color-ui-orange); 387 | padding: 2px; 388 | cursor: pointer; 389 | transform: translate(0); 390 | left: 12px; 391 | position: absolute; 392 | border-radius: 50%; 393 | } 394 | .salary-bar__avatar-arrow { 395 | width: 12px; 396 | height: 12px; 397 | transform: rotate(90deg); 398 | top: -48px; 399 | left: -4px; 400 | fill: var(--color-ui-orange); 401 | position: absolute; 402 | }/*# sourceMappingURL=style.css.map */ -------------------------------------------------------------------------------- /lecture07/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
                 12 |  $value) {
                 26 |             if (property_exists(Form::class, $key)) {
                 27 |                 $this->$key = $value;
                 28 |             }
                 29 |         }
                 30 |     }
                 31 | 
                 32 |     function isSubmitted(): bool {
                 33 |         return $this->submit === self::SUBMIT_VALUE;
                 34 |     }
                 35 | 
                 36 |     function validate(): self {
                 37 |         $this->validateFirstName();
                 38 |         $this->validateRadio();
                 39 |         $this->validateCheck();
                 40 | 
                 41 |         return $this;
                 42 |     }
                 43 | 
                 44 |     function getErrors(): array {
                 45 |         return $this->errors;
                 46 |     }
                 47 | 
                 48 |     private function validateFirstName(): void {
                 49 |         $this->checkIsEmpty('first_name');
                 50 |         $this->checkLength('first_name', 5);
                 51 |     }
                 52 | 
                 53 |     private function validateRadio(): void {
                 54 |         $this->checkIsEmpty('radio');
                 55 |     }
                 56 | 
                 57 |     private function validateCheck(): void {
                 58 |         $this->checkIsEmpty('check');
                 59 |     }
                 60 | 
                 61 |     private function checkIsEmpty(string $name): void {
                 62 |         if (!empty($this->$name)) {
                 63 |             return;
                 64 |         }
                 65 | 
                 66 |         $this->errors[$name][] = 'Поле не может быть пустым';
                 67 |     }
                 68 | 
                 69 |     private function checkLength(string $name, int $symbolsCount): void {
                 70 |         if (!is_string($this->$name)) {
                 71 |             return;
                 72 |         }
                 73 | 
                 74 |         if (mb_strlen($this->$name) > $symbolsCount) {
                 75 |             return;
                 76 |         }
                 77 | 
                 78 |         $this->errors[$name][] = "Поле не может содержать меньше $symbolsCount символов";
                 79 |     }
                 80 | }
                 81 | 
                 82 | $form = new Form($_POST);
                 83 | 
                 84 | $errors = [];
                 85 | 
                 86 | if ($form->isSubmitted()) {
                 87 |     $errors = $form->validate()->getErrors();
                 88 | }
                 89 |     
                 90 | var_dump($_GET);
                 91 | var_dump($_POST);
                 92 | var_dump($errors);
                 93 | 
                 94 | ?>
                 95 | 
                96 |
                97 |
                98 |
                99 |
                100 |
                101 | 102 | 103 |
                  104 | $error"; 106 | }?> 107 |
                108 |
                109 |
                110 | 111 | 112 |
                113 |
                114 |
                115 |
                116 | 117 | 122 | 127 |
                128 |
                129 |
                130 |
                131 | 132 | 137 | 142 | 147 |
                148 |
                149 |
                150 |
                151 | 152 |
                153 |
                154 |
                155 |
                156 |
                157 | 158 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /lecture03/advanced/spesivtsev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 |
                10 |
                Спесивцев
                11 |
                12 |
                Нажмите на квадраты ниже, чтобы изменить цвет
                13 |
                14 |
                15 |
                16 |
                17 |
                18 |
                19 |
                20 |
                21 |
                22 |
                23 | 24 |
                25 |
                26 |
                27 |
                28 |
                29 |
                30 |
                31 |
                Обновить страницу
                32 |
                33 |
                Добавить 3 квадрата*
                34 |
                Случайные цвета*
                35 |
                Сбросить
                36 |
                Сохранить
                37 |
                38 |
                39 |
                40 |
                41 | 277 | 341 | 342 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Репозиторий для студентов по дисциплине "Разработка WEB-приложений" 2 | 3 | ## Основная информация 4 | - Преподаватель - [Чугаев Михаил Александрович](https://career.habr.com/almor) 5 | - Канал в telegram с новостями - [WEB Development](https://t.me/+o-JtFsksEe9iZmIy) 6 | - Продолжительность курса - 1 семестр, 18 пар, 36 часов 7 | 8 | ## Система оценивания 9 | - Всего 3 оценки 10 | - оценка за практическое задание по фронтенду (html, css, js) 11 | - оценка за практическое задание по бекенду (php, sql) 12 | - оценка за собеседование (5 случайных вопросов) 13 | - Допуск к собеседованию предоставляется только когда: 14 | - Сданы 2 практических задания 15 | - Проверка будет осуществляться по наличию вашего кода в этом репозитории 16 | - Итоговая оценка = среднее арифметическое из 3х оценок 17 | 18 | ## Как сдать быстрее 19 | *В случае если вы хотите:* 20 | - Не ходить на пары 21 | - Не сдавать лекционные задания 22 | - Получить ранний доступ к собеседованию 23 | 24 | *Вам нужно:* 25 | 1. Выполнить 20 из 20 практических заданий по фронтенду (продвинутый уровень) 26 | 1. Выполнить 20 из 20 практических заданий по бекенду (продвинутый уровень) 27 | 1. Оформить всё это в отдельные репозитории Github 28 | 1. Предоставить доступ к репозиториям [m-chugaev](https://github.com/m-chugaev) 29 | 30 | ## Практическое задание фронтенд 31 | 1. Взять за основу папку с Next `practice-01` 32 | 1. Создать новую ветку с названием `фамилия-тип-задание`, например `chugaev-frontend-20` 33 | 1. Сделать одно из выпавших ниже заданий 34 | 1. Каждое задание должно быть реализовано через создание компонента и его использование. По необходимости должен быть создан компонент в папке /practice-01/components/, этот компонент необходимо будет подключить в основной файл /practice-01/app/page.js 35 | 1. Сделать один или несколько коммитов в свою ветку 36 | 1. Создать запрос на слияние в ветку `main` 37 | 1. Решить все конфликты слияния, если они есть 38 | 1. Подойти ко мне, показать результат, получить оценку 39 | 40 | *Задания:* 41 | 1. Стилизация страницы. Оформить в стиле [Untitled UI](https://untitled-ui-webflow-library.webflow.io). 42 | 2. Пагинация для списка вопросов. По 10 вопросов на странице. 43 | 3. Случайные n вопросов. Отправляется форма с числовым инпутом и кнопкой. После чего появляется n вопросов после основного списка. 5 вопросов по умолчанию. 44 | 4. Список 5 случайных вопросов без повторений с предыдущими. После обновления страницы сбрасывается. Выпавшие вопросы должны получить opacity: 0.5. По нажатию на кнопку после списка на страницу выводится получившийся список. 45 | 5. Список 5 случайных вопросов с разной частотой выпадения. Частота выпадения редактируется в изначальном списке, без форм и инпутов. По нажатию на кнопку после списка на страницу выводится получившийся список. 46 | 6. Список 5 случайных вопросов с историей. История сохраняется после обновления страницы. Всего в истории хранится 10 последних выпадений. По нажатию на кнопку после списка на страницу выводится получившийся список. История выводится отдельным блоком после списка в виде нумерованного списка "25 Jan 2023 23:59:59 - [1,2,3,4,5]" 47 | 7. Добавление новых вопросов. Форма в списке из строкового инпута и кнопки, при отправке которой появляется новый вопрос. Вопросы сохраняются после обновления страницы. 48 | 8. Удаление вопросов из списка. Кнопка в общем списке, по нажатию на которую пропадает вопрос. Вопросы сохраняются после обновления страницы. 49 | 9. Переключение между светлой и тёмной темой. В правом верхнем углу, фиксированный переключатель между темами. Тема сохраняется после обновления страницы. 50 | 10. Переключение между языками (ru, en). В правом нижнем углу, фиксированный переключатель между языками. Язык сохраняется после обновления страницы. 51 | 11. Отправка событий в Яндекс.Метрика. Конверсиями считаем нажатия на любые кнопки. Завести несколько кастомных событий. 52 | 12. Таймер на ответы. В правой части экрана в середине должен быть зафиксирован блок таймера. Таймер длительностью 5 минут. По окончании выводится alert о том, что таймер закончился и после подтверждения alert таймер сбрасывается к 5 минутам. Таймер можно остановить и перезапустить. 53 | 13. Сделать рекламный лендинг продукта. Минимум 3 секции (hero, pricing, contact us). В стиле [Untitled UI](https://untitled-ui-webflow-library.webflow.io). 54 | 14. Блок с комментариями. В самом конце страницы textarea с кнопкой. Перед ней комментарии карточками с датой отправки. Комментарии сохраняются после обновления страницы. 55 | 15. Нотайс со случайной шуткой при заходе на страницу. Нотайс появляется в правом верхнем углу страницы через 1 секунду после загрузки страницы и пропадает через 5 секунд. Должна быть возможность отключить появление нотайса через консоль. 56 | 16. Нотайс со случайным вопросом при заходе на страницу. Нотайс появляется в правом верхнем углу страницы через 1 секунду после загрузки страницы и пропадает через 5 секунд. Должна быть возможность отключить появление нотайса через консоль. 57 | 17. Вопрос дня на странице. Меняется раз в день для пользователя. Вопросы не должны повторяться пока не будут показаны все, после чего сбрасываются и показываются снова. 58 | 18. Рандомный смайл к каждому вопросу. Смайлы появляются после загрузки страницы. У каждого вопроса должен быть свой уникальный смайл. 59 | 19. Теги к вопросам и фильтр по ним. Теги по типу JS, CSS, Основы и тд. Фильтр отображается перед списком. Сами теги надо заполнить, у вопроса может быть несколько тегов. Теги также отображаются после вопроса тегами mark. 60 | 20. Бонус! Придумать любое улучшение для продукта и внедрить без конфликтов. 61 | 62 | 63 | ## Практическое задание бекенд 64 | 1. Взять за основу папку с PHP `practice-02` 65 | 1. Создать новую ветку с названием `фамилия-тип-задание`, например `chugaev-frontend-20` 66 | 1. Сделать одно из выпавших ниже заданий 67 | 1. Каждое задание должно быть реализовано через создание php класса и его использование. Нужно обязательно добавить один или несколько api-endpoints (файл в папке /practice-02/api/). Также по необходимости должен быть создан компонент в папке /practice-02/components/, этот компонент необходимо будет подключить в основной файл /practice-02/index.php 68 | 1. Любые сохранения данных между обновлениями страницы должны использовать php сессии. Предзаполнять данные можно через php, например если вы сохранили значения инпутов можно заполнить их через php, при этом можно и заполнить через js, использовав дополнительный api запрос. 69 | 1. Любой функционал не должен обновлять страницу. То есть все формы должны отправляться через JS и использовать функцию fetch. Все кнопки должны использовать fetch и обновлять контент страницы. 70 | 1. Сделать один или несколько коммитов в свою ветку 71 | 1. Создать запрос на слияние в ветку `main` 72 | 1. Решить все конфликты слияния, если они есть 73 | 1. Подойти ко мне, показать результат, получить оценку 74 | 75 | *Задания:* 76 | 1. Случайные 5 вопросов. По нажатию на кнопку после списка выводятся 5 случайных вопросов. Также должна быть кнопка которая показывает нотайс с датами предыдущих запросов. (Для показа нотайса использовать js функцию showNotice) 77 | 2. Случайные n вопросов. Отправляется форма с числовым инпутом и кнопкой. После чего появляется n вопросов после основного списка. 5 вопросов по умолчанию. 78 | 3. Список 5 случайных вопросов без повторений с предыдущими. По нажатию на кнопку после списка на страницу выводится получившийся список. Должна быть кнопка сброса истории, по нажатию на которую все повторения сбрасываются. 79 | 4. Список 5 случайных вопросов с разной частотой выпадения. Частота выпадения редактируется в изначальном списке, без форм и инпутов. По нажатию на кнопку после списка на страницу выводится получившийся список. 80 | 5. Список 5 случайных вопросов с историей. История сохраняется после обновления страницы. Всего в истории хранится 10 последних выпадений. По нажатию на кнопку после списка на страницу выводится получившийся список. История выводится отдельным блоком после списка в виде нумерованного списка "25 Jan 2023 23:59:59 - [1,2,3,4,5]" 81 | 6. Добавление новых вопросов. Форма в списке из строкового инпута и кнопки, при отправке которой появляется новый вопрос. Вопросы сохраняются после обновления страницы. 82 | 7. Удаление вопросов из списка. Кнопка в общем списке, по нажатию на которую пропадает вопрос. Вопросы сохраняются после обновления страницы. 83 | 8. Пагинация для списка вопросов. По 10 вопросов на странице. После списка должны быть кнопки Вперед, Назад и отображение текущей страницы. Страницы не должны уходить за рамки допустимого, в таком случае нужно добавлять к кнопкам аттрибут disabled. После обновления страницы открывается та страница на которой остановились. 84 | 9. Переключение между языками (ru, en). В правом нижнем углу, фиксированный переключатель между языками. Язык сохраняется после обновления страницы. 85 | 10. Блок с комментариями. В самом конце страницы textarea с кнопкой. Перед ней комментарии карточками с датой отправки. Комментарии сохраняются после обновления страницы. 86 | 11. Нотайс со случайной шуткой при заходе на страницу. Нотайс появляется в правом верхнем углу страницы через 1 секунду после загрузки страницы и пропадает через 5 секунд. (Для показа нотайса использовать js функцию showNotice) 87 | 12. Нотайс со случайным вопросом при заходе на страницу. Нотайс появляется в правом верхнем углу страницы через 1 секунду после загрузки страницы и пропадает через 5 секунд. (Для показа нотайса использовать js функцию showNotice) 88 | 13. Вопрос дня на странице. Меняется раз в день для пользователя. Вопросы не должны повторяться пока не будут показаны все, после чего сбрасываются и показываются снова. 89 | 14. Рандомный смайл к каждому вопросу. Смайлы появляются после загрузки страницы. У каждого вопроса должен быть свой уникальный смайл. 90 | 15. Теги к вопросам и фильтр по ним. Теги по типу JS, CSS, Основы и тд. Фильтр отображается перед списком. Сами теги надо заполнить, у вопроса может быть несколько тегов. Теги также отображаются после вопроса тегами mark. 91 | 16. Форма с email и валидацией через php, после отправки показывается нотайс с ошибкой или успешное сообщение "Контакт сохранен". После обновления страницы введённые значения сохраняются. (Для показа нотайса использовать js функцию showNotice) 92 | 17. Форма с текстовым инпутом и валидацией через php. В инпуте должны быть id вопросов через запятую и пробел, например "1, 2, 5, 10". Валидируется существование вопросов с такими id и наличие в запросе хотя бы одного id. При ошибке показывается нотайс с ошибкой. При успешном запросе выводятся запрошенные вопросы в список под формой. (Для показа нотайса использовать js функцию showNotice) 93 | 18. Форма с текстовым инпутом и валидацией через php. В инпуте должны быть только буквы на кирилице и пробелы. После отправки показывается нотайс с ошибкой или успешное сообщение "Текст корректен". После обновления страницы введённые значения сохраняются. 94 | 19. Форма с 3 чекбоксами ["Быстро", "Качественно", "Дешево"]. После отправки php проверяет, что отмечены только 2 из 3 чекбоксов, а также что отправлены только те что были в списке. Если в запросе была ошибка, показывается нотайс "Это нереально". если запрос был успешен, показывается нотайс "Сделаем". После обновления страницы введённые значения сохраняются. 95 | 20. Форма с 3 инпутами (text, radio и select). В radio и select минимум 2 выбора. Все поля должны быть заполнены, если нет, то показывается нотайс с ошибкой "Заполните <тип> поле". После обновления страницы введённые значения сохраняются. --------------------------------------------------------------------------------