diff --git a/package-lock.json b/package-lock.json index e1958d5..141fb0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { - "parcel": "^2.16.0", - "posthtml-expressions": "^1.11.4" + "parcel": "^2.16.0" } }, "node_modules/@lezer/common": { @@ -2306,75 +2305,6 @@ "node": ">=0.10" } }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "license": "BSD-2-Clause", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -2411,19 +2341,6 @@ "dev": true, "license": "ISC" }, - "node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2434,13 +2351,6 @@ "node": ">=6" } }, - "node_modules/fclone": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fclone/-/fclone-1.0.11.tgz", - "integrity": "sha512-GDqVQezKzRABdeqflsgMr7ktzgF9CyS+p2oe0jJqUY6izSSbhPIQJDpoU4PtGcD7VPM9xh/dVrTu6z1nwgmEGw==", - "dev": true, - "license": "MIT" - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -2490,26 +2400,6 @@ "node": ">=8" } }, - "node_modules/htmlparser2": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz", - "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.2", - "domutils": "^2.8.0", - "entities": "^3.0.1" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2533,13 +2423,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-json": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz", - "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==", - "dev": true, - "license": "ISC" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3055,86 +2938,6 @@ "dev": true, "license": "MIT" }, - "node_modules/posthtml": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz", - "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "posthtml-parser": "^0.11.0", - "posthtml-render": "^3.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/posthtml-expressions": { - "version": "1.11.4", - "resolved": "https://registry.npmjs.org/posthtml-expressions/-/posthtml-expressions-1.11.4.tgz", - "integrity": "sha512-tJI6KhKLcePRO0/i4d01MNXfcaBa2jIu4MuVLixvGwCRzxdY2D7LLm17ijNyQNQu3xOhCffBLtUMju0K64smmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fclone": "^1.0.11", - "posthtml": "^0.16.5", - "posthtml-match-helper": "^1.0.1", - "posthtml-parser": "^0.10.0", - "posthtml-render": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/posthtml-match-helper": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/posthtml-match-helper/-/posthtml-match-helper-1.0.4.tgz", - "integrity": "sha512-Tj9orTIBxHdnraCxoEGjoizsFsTGvukzwcuhOjYQGmDG6gTlaRbMrGgi1J+FwKTN8hsCQENHYY0Deqs9a89BVg==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "posthtml": ">=0.5.0" - } - }, - "node_modules/posthtml-parser": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.10.2.tgz", - "integrity": "sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "htmlparser2": "^7.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/posthtml-render": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz", - "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-json": "^2.0.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/posthtml/node_modules/posthtml-parser": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz", - "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "htmlparser2": "^7.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/react-refresh": { "version": "0.16.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.16.0.tgz", diff --git a/package.json b/package.json index 1758671..9a625f2 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "author": "", "license": "ISC", "devDependencies": { - "parcel": "^2.16.0", - "posthtml-expressions": "^1.11.4" + "parcel": "^2.16.0" } } diff --git a/posthtml.config.js b/posthtml.config.js deleted file mode 100644 index ad90161..0000000 --- a/posthtml.config.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - plugins: { - 'posthtml-expressions': { - locals: { - movies: require('./src/data/movies.json') - } - } - } -}; \ No newline at end of file diff --git a/src/data/movies.js b/src/data/movies.js new file mode 100644 index 0000000..d1f6776 --- /dev/null +++ b/src/data/movies.js @@ -0,0 +1,248 @@ +export default [ + { + "id": 1, + "title": "Аватар", + "subtitle": "Avatar, 2009", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/4adf61aa-3cb7-4381-9245-523971e5b4c8/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/4adf61aa-3cb7-4381-9245-523971e5b4c8/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2009" } + ] + }, + { + "id": 2, + "title": "Интерстеллар", + "subtitle": "Interstellar, 2014", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1600647/430042eb-ee69-4818-aed0-a312400a26bf/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1600647/430042eb-ee69-4818-aed0-a312400a26bf/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2014" }, + { name: "Жанр", value: "фантастика, драма, приключения" }, + { name: "Слоган", value: "«Следующий шаг человечества станет величайшим»" }, + { name: "Режиссер", value: "Кристофер Нолан" }, + { name: "Продюсер", value: "Кристофер Нолан, Линда Обст, Эмма Томас" }, + { name: "Бюджет", value: "$165 000 000" }, + { name: "Время", value: "2 ч 49 мин" } + ] + }, + { + "id": 3, + "title": "Начало", + "subtitle": "Inception, 2010", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1629390/8ab9a119-dd74-44f0-baec-0629797483d7/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1629390/8ab9a119-dd74-44f0-baec-0629797483d7/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2010" } + ] + }, + { + "id": 4, + "title": "Мстители: Война бесконечности", + "subtitle": "Avengers: Infinity War, 2018", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1773646/af92d310-4ae5-4daa-b42c-5bcc380c2e6e/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1773646/af92d310-4ae5-4daa-b42c-5bcc380c2e6e/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2018" } + ] + }, + { + "id": 5, + "title": "Матрица", + "subtitle": "The Matrix, 1999", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4774061/cf1970bc-3f08-4e0e-a095-2fb57c3aa7c6/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/4774061/cf1970bc-3f08-4e0e-a095-2fb57c3aa7c6/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "1999" } + ] + }, + { + "id": 6, + "title": "Мстители: Финал", + "subtitle": "Avengers: Endgame, 2019", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1600647/ae22f153-9715-41bb-adb4-f648b3e16092/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1600647/ae22f153-9715-41bb-adb4-f648b3e16092/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2019" } + ] + }, + { + "id": 7, + "title": "Дюна", + "subtitle": "Dune: Part One, 2021", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4303601/9eb762d6-4cdd-464f-9937-aebf30067acc/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/4303601/9eb762d6-4cdd-464f-9937-aebf30067acc/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2021" } + ] + }, + { + "id": 8, + "title": "Пятый элемент", + "subtitle": "The Fifth Element, 1997", + "details": "Франция • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1629390/9e9e2b2c-a3c1-462e-8d84-e6a19fbe5b9c/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1629390/9e9e2b2c-a3c1-462e-8d84-e6a19fbe5b9c/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "1997" } + ] + }, + { + "id": 9, + "title": "Стражи Галактики", + "subtitle": "Guardians of the Galaxy, 2014", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1773646/2e6ab20b-7cf1-49e7-b465-bd5a71c13fa3/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1773646/2e6ab20b-7cf1-49e7-b465-bd5a71c13fa3/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2014" } + ] + }, + { + "id": 10, + "title": "Кракен", + "subtitle": "2025", + "details": "Россия • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/10809116/b722ab4d-497b-4a62-b243-95ca989401ff/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/10809116/b722ab4d-497b-4a62-b243-95ca989401ff/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2025" } + ] + }, + { + "id": 11, + "title": "Темный рыцарь", + "subtitle": "The Dark Knight, 2008", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/0fa5bf50-d5ad-446f-a599-b26d070c8b99/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/0fa5bf50-d5ad-446f-a599-b26d070c8b99/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2008" } + ] + }, + { + "id": 12, + "title": "Доктор Стрэндж", + "subtitle": "Doctor Strange, 2016", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4303601/bb966b79-5b10-485d-88d7-fb6aeb79b185/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/4303601/bb966b79-5b10-485d-88d7-fb6aeb79b185/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2016" } + ] + }, + { + "id": 13, + "title": "Мстители", + "subtitle": "The Avengers, 2012", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1898899/972b7f43-9677-40ce-a9bc-02a88ad3919d/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1898899/972b7f43-9677-40ce-a9bc-02a88ad3919d/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2012" } + ] + }, + { + "id": 14, + "title": "Терминатор 2: Судный день", + "subtitle": "Terminator 2: Judgment Day, 1991", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/10893610/2dd14742-f241-42ca-9db4-331e3a483c50/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/10893610/2dd14742-f241-42ca-9db4-331e3a483c50/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "1991" } + ] + }, + { + "id": 15, + "title": "Железный человек", + "subtitle": "Iron Man, 2008", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4774061/c8e2f069-15f1-4803-95c0-aba858fec360/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/4774061/c8e2f069-15f1-4803-95c0-aba858fec360/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2008" } + ] + }, + { + "id": 16, + "title": "Назад в будущее", + "subtitle": "Back to the Future, 1985", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/73cf2ed0-fd52-47a2-9e26-74104360786a/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/73cf2ed0-fd52-47a2-9e26-74104360786a/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "1985" } + ] + }, + { + "id": 17, + "title": "Марсианин", + "subtitle": "The Martian, 2015", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1900788/6f631486-e947-487d-94d6-41c2b5a8f5a0/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1900788/6f631486-e947-487d-94d6-41c2b5a8f5a0/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2015" } + ] + }, + { + "id": 18, + "title": "Кибердеревня", + "subtitle": "2023", + "details": "Россия • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/9784475/70c75cf3-f456-4474-a900-9a38c1bb2987/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/9784475/70c75cf3-f456-4474-a900-9a38c1bb2987/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2023" } + ] + }, + { + "id": 19, + "title": "Главный герой", + "subtitle": "Free Guy, 2021", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/6201401/db4fbef1-466a-4dec-9b7a-d4f13eb45738/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/6201401/db4fbef1-466a-4dec-9b7a-d4f13eb45738/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2021" } + ] + }, + { + "id": 20, + "title": "Первому игроку приготовиться", + "subtitle": "Ready Player One, 2018", + "details": "США • фантастика", + "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1946459/5ae82f4b-fd6a-46b5-b5ba-897106eb1eae/136x204", + "imgBig": "https://avatars.mds.yandex.net/get-kinopoisk-image/1946459/5ae82f4b-fd6a-46b5-b5ba-897106eb1eae/600x900", + "link": "#", + "metadata": [ + { name: "Год производства", value: "2018" } + ] + } +] \ No newline at end of file diff --git a/src/data/movies.json b/src/data/movies.json deleted file mode 100644 index 4f1f5f2..0000000 --- a/src/data/movies.json +++ /dev/null @@ -1,142 +0,0 @@ -[ - { - "title": "Аватар", - "subtitle": "Avatar, 2009", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/4adf61aa-3cb7-4381-9245-523971e5b4c8/136x204", - "link": "#" - }, - { - "title": "Интерстеллар", - "subtitle": "Interstellar, 2014", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1600647/430042eb-ee69-4818-aed0-a312400a26bf/136x204", - "link": "#" - }, - { - "title": "Начало", - "subtitle": "Inception, 2010", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1629390/8ab9a119-dd74-44f0-baec-0629797483d7/136x204", - "link": "#" - }, - { - "title": "Мстители: Война бесконечности", - "subtitle": "Avengers: Infinity War, 2018", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1773646/af92d310-4ae5-4daa-b42c-5bcc380c2e6e/136x204", - "link": "#" - }, - { - "title": "Матрица", - "subtitle": "The Matrix, 1999", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4774061/cf1970bc-3f08-4e0e-a095-2fb57c3aa7c6/136x204", - "link": "#" - }, - { - "title": "Мстители: Финал", - "subtitle": "Avengers: Endgame, 2019", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1600647/ae22f153-9715-41bb-adb4-f648b3e16092/136x204", - "link": "#" - }, - { - "title": "Дюна", - "subtitle": "Dune: Part One, 2021", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4303601/9eb762d6-4cdd-464f-9937-aebf30067acc/136x204", - "link": "#" - }, - { - "title": "Пятый элемент", - "subtitle": "The Fifth Element, 1997", - "details": "Франция • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1629390/9e9e2b2c-a3c1-462e-8d84-e6a19fbe5b9c/136x204", - "link": "#" - }, - { - "title": "Стражи Галактики", - "subtitle": "Guardians of the Galaxy, 2014", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1773646/2e6ab20b-7cf1-49e7-b465-bd5a71c13fa3/136x204", - "link": "#" - }, - { - "title": "Кракен", - "subtitle": "2025", - "details": "Россия • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/10809116/b722ab4d-497b-4a62-b243-95ca989401ff/136x204", - "link": "#" - }, - { - "title": "Темный рыцарь", - "subtitle": "The Dark Knight, 2008", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/0fa5bf50-d5ad-446f-a599-b26d070c8b99/136x204", - "link": "#" - }, - { - "title": "Доктор Стрэндж", - "subtitle": "Doctor Strange, 2016", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4303601/bb966b79-5b10-485d-88d7-fb6aeb79b185/136x204", - "link": "#" - }, - { - "title": "Мстители", - "subtitle": "The Avengers, 2012", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1898899/972b7f43-9677-40ce-a9bc-02a88ad3919d/136x204", - "link": "#" - }, - { - "title": "Терминатор 2: Судный день", - "subtitle": "Terminator 2: Judgment Day, 1991", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/10893610/2dd14742-f241-42ca-9db4-331e3a483c50/136x204", - "link": "#" - }, - { - "title": "Железный человек", - "subtitle": "Iron Man, 2008", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/4774061/c8e2f069-15f1-4803-95c0-aba858fec360/136x204", - "link": "#" - }, - { - "title": "Назад в будущее", - "subtitle": "Back to the Future, 1985", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1599028/73cf2ed0-fd52-47a2-9e26-74104360786a/136x204", - "link": "#" - }, - { - "title": "Марсианин", - "subtitle": "The Martian, 2015", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1900788/6f631486-e947-487d-94d6-41c2b5a8f5a0/136x204", - "link": "#" - }, - { - "title": "Кибердеревня", - "subtitle": "2023", - "details": "Россия • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/9784475/70c75cf3-f456-4474-a900-9a38c1bb2987/136x204", - "link": "#" - }, - { - "title": "Главный герой", - "subtitle": "Free Guy, 2021", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/6201401/db4fbef1-466a-4dec-9b7a-d4f13eb45738/136x204", - "link": "#" - }, - { - "title": "Первому игроку приготовиться", - "subtitle": "Ready Player One, 2018", - "details": "США • фантастика", - "img": "https://avatars.mds.yandex.net/get-kinopoisk-image/1946459/5ae82f4b-fd6a-46b5-b5ba-897106eb1eae/136x204", - "link": "#" - } -] \ No newline at end of file diff --git a/src/index.html b/src/index.html index d70da3d..d441d1c 100644 --- a/src/index.html +++ b/src/index.html @@ -1,5 +1,6 @@ + @@ -8,32 +9,20 @@ + + +

Каталог фильмов

-
-
- - - - -
-
+
+ + + \ No newline at end of file diff --git a/src/scripts/index.js b/src/scripts/index.js new file mode 100644 index 0000000..7bc0ed0 --- /dev/null +++ b/src/scripts/index.js @@ -0,0 +1,33 @@ +import MovieListView from "./views/movie-list-view"; +import MovieModel from "./models/movie-model"; + +/** + * Класс главной страницы приложения. + * Отвечает за инициализацию и рендер списка фильмов. + */ +class IndexPage { + /** @type {MovieListView} Список фильмов */ + movieListView + + constructor() { + // Получаем все фильмы из модели + const movies = MovieModel.getAll(); + // Создаём View для списка фильмов + this.movieListView = new MovieListView("#movie-list-container", movies); + } + + /** Рендерит главную страницу */ + render() { + this.movieListView.render(); + } +} + +/** + * Инициализация приложения после полной загрузки DOM + * - чтобы все селекторы уже существовали + * - window.indexPage даёт доступ к корневому объекту в консоли браузера (для отладки) + */ +document.addEventListener("DOMContentLoaded", () => { + window.indexPage = new IndexPage(); + window.indexPage.render(); +}); \ No newline at end of file diff --git a/src/scripts/models/movie-model.js b/src/scripts/models/movie-model.js new file mode 100644 index 0000000..34adde3 --- /dev/null +++ b/src/scripts/models/movie-model.js @@ -0,0 +1,24 @@ +import movies from "../../data/movies.js"; + +/** + * Класс модели фильмов. + * Отвечает за работу с данными о фильмах. + */ +export default class MovieModel { + /** + * Возвращает все фильмы + * @returns {Array} Массив объектов фильмов + */ + static getAll() { + return movies; + } + + /** + * Возвращает фильм по его идентификатору + * @param {number} id - Идентификатор фильма + * @returns {Object|undefined} Объект фильма или undefined, если не найден + */ + static getById(id) { + return movies.find(movie => movie.id === id); + } +} \ No newline at end of file diff --git a/src/scripts/views/base-view.js b/src/scripts/views/base-view.js new file mode 100644 index 0000000..a872a30 --- /dev/null +++ b/src/scripts/views/base-view.js @@ -0,0 +1,60 @@ +/** + * Базовый класс для всех View-компонентов. + * Содержит общие методы рендера и управления событиями. + * + * Примечание: методы _createInnerHTML, _attachEvents и _detachEvents + * должны быть реализованы в наследниках, иначе будет ошибка. + */ +export default class BaseView { + /** @type {HTMLElement} Элемент контейнера, куда рендерится контент */ + _$el + + /** @type {any} Данные для отображения в компоненте */ + _data + + /** + * @param {string} selector - CSS-селектор контейнера в DOM + * @param {any} initialData - Начальные данные для компонента + */ + constructor(selector, initialData = {}) { + this._$el = document.querySelector(selector); + this._data = initialData; + } + + /** + * Метод должен вернуть HTML-контент компонента. + * Должен быть реализован в наследнике. + * @returns {string} HTML-код компонента + */ + _createInnerHTML() { + throw new Error("Method _createInnerHTML() must be implemented"); + } + + /** + * Метод для удаления событий перед перерендером. + * Должен быть реализован в наследнике. + */ + _detachEvents() { + throw new Error("Method _detachEvents() must be implemented"); + } + + /** + * Метод для установки событий после рендера. + * Должен быть реализован в наследнике. + */ + _attachEvents() { + throw new Error("Method _attachEvents() must be implemented"); + } + + /** + * Основной метод рендера компонента. + * Сначала удаляет старые события, затем создаёт HTML, + * затем вешает новые события. + */ + render() { + this._detachEvents(); + const innerHTML = this._createInnerHTML(); + this._$el.innerHTML = innerHTML; + this._attachEvents(); + } +} \ No newline at end of file diff --git a/src/scripts/views/movie-list-view.js b/src/scripts/views/movie-list-view.js new file mode 100644 index 0000000..11601c2 --- /dev/null +++ b/src/scripts/views/movie-list-view.js @@ -0,0 +1,92 @@ + +import BaseView from "./base-view"; +import { createMovieModal } from "./movie-modal-view"; +import MovieModel from "../models/movie-model"; + +/** + * Класс для отображения списка фильмов. + * Рендерит карточки фильмов и обрабатывает открытие модалки при клике. + * Наследуется от BaseView. + */ +export default class MovieListView extends BaseView { + /** @type {MovieModalView} Экземпляр модального окна */ + #movieModal; + + /** + * @param {string} selector - CSS-селектор контейнера списка фильмов + * @param {Array} initialData - Массив объектов фильмов + */ + constructor(selector, initialData = []) { + super(selector, initialData); + this.#movieModal = createMovieModal(); + } + + /** + * Генерирует HTML для одной карточки фильма + * @param {Object} movie - Объект фильма + * @returns {string} HTML-код карточки + */ + #createItem({ id, link, title, subtitle, img, details }) { + return ` + + `; + } + + /** + * Генерирует HTML для всего списка фильмов + * @returns {string} HTML-код списка фильмов + */ + #createList() { + return ` +
+ ${this._data.map(this.#createItem.bind(this)).join("")} +
+ `; + } + + /** Метод рендера HTML (обязательный для BaseView) */ + _createInnerHTML() { + return this.#createList(); + } + + /** + * Обработчик клика на карточке фильма. + * Делегирование: ищет ближайший элемент с data-modal-open + * и открывает соответствующую модалку. + * @param {MouseEvent} event + */ + #handleModal = (event) => { + event.preventDefault(); + + // Используем event.target.closest('[data-modal-open]') + // чтобы найти ближайший элемент с атрибутом data-modal-open + // даже если кликнули по вложенному тегу внутри карточки + const movieItem = event.target.closest("[data-modal-open]"); + if (movieItem) { + const movieId = +movieItem.dataset.id; + const movie = MovieModel.getById(movieId); + this.#movieModal.open(movie); + } + } + + /** Убирает обработчики событий перед перерендером */ + _detachEvents() { + this._$el.removeEventListener("click", this.#handleModal); + } + + /** Добавляет обработчики событий после рендера */ + _attachEvents() { + this._$el.addEventListener("click", this.#handleModal); + } +} \ No newline at end of file diff --git a/src/scripts/views/movie-modal-view.js b/src/scripts/views/movie-modal-view.js new file mode 100644 index 0000000..7e12f10 --- /dev/null +++ b/src/scripts/views/movie-modal-view.js @@ -0,0 +1,129 @@ +import BaseView from "./base-view"; + +/** + * Класс модального окна фильма. + * Отвечает за отображение деталей фильма и работу с кнопками внутри модалки. + * Наследуется от BaseView. + */ +export default class MovieModalView extends BaseView { + /** + * @param {string} selector - CSS-селектор контейнера модалки + * @param {Object} initialData - Начальные данные для модалки + */ + constructor(selector, initialData = {}) { + super(selector, initialData); + } + + /** + * Открывает модалку с переданными данными фильма + * @param {Object} movie - Объект фильма + */ + open(movie) { + this._data = movie; + this.render(); + this._$el.showModal(); // встроенный метод HTML-элемента + } + + /** Закрывает модалку */ + close() { + this._$el.close(); + } + + /** + * Генерирует HTML для списка метаданных фильма + * @returns {string} HTML-строка с метаданными + */ + #createMetadataList() { + if (!this._data.metadata || !this._data.metadata.length) { + return "Нет информации"; + } + + return ` +
    + ${this._data.metadata.map(({ name, value }) => ` +
  • + ${name}:${value} +
  • + `).join("")} +
+ `; + } + + /** Генерирует полный HTML модалки */ + #createModal() { + return ` +
+
+

Выбор фильма

+ +
+
+
+ ${this._data.title} +
+
+
+

${this._data.title}

+ ${this.#createMetadataList()} +
+ + + Смотреть вместе → + +
+
+
+ `; + } + + /** Метод для рендера HTML (обязательный для BaseView) */ + _createInnerHTML() { + return this.#createModal(); + } + + /** TODO: Показ уведомления о настройках (заглушка) */ + #showSettings() { + alert("Settings are not implemented"); + } + + /** TODO: Переход на страницу просмотра фильма (заглушка) */ + #navigateToWatchPage(movieId) { + alert("Watch page is not implemented"); + } + + /** + * Обработчик кликов по кнопкам модалки + * @param {MouseEvent} event + */ + #handleButtons = (event) => { + const closeBtn = event.target.closest("[data-modal-close]"); + if (closeBtn) return this.close(); + + const settingsBtn = event.target.closest(".movie-modal-settings-btn"); + if (settingsBtn) { + event.preventDefault(); + this.#showSettings(); + } + + const watchBtn = event.target.closest(".movie-modal-watch-btn"); + if (watchBtn) { + event.preventDefault(); + this.#navigateToWatchPage(this._data.id); + } + } + + /** Убирает события перед перерендером (BaseView) */ + _detachEvents() { + this._$el.removeEventListener("click", this.#handleButtons); + } + + /** Добавляет события после рендера (BaseView) */ + _attachEvents() { + // Делегирование событий кликов на контейнер модалки + // Позволяет обрабатывать все кнопки внутри одной функции + this._$el.addEventListener("click", this.#handleButtons); + } +} + +/** Фабрика для создания модалки */ +export const createMovieModal = () => new MovieModalView("#movie-modal"); \ No newline at end of file diff --git a/src/styles/common.css b/src/styles/common.css index 27361d8..17eaea2 100644 --- a/src/styles/common.css +++ b/src/styles/common.css @@ -4,6 +4,10 @@ --color-h1: #FFFFFF; --color-base: #E0E0E0; --color-base2: #A0A0A0; + --color-primary: #4A90E2; + --color-primary-hover: #357ABD; + --color-secondary: #F4B400; + --color-secondary-hover: #D99A00; --spacing: .25rem; @@ -14,6 +18,7 @@ --text-h2: clamp(16px, 3vw, 21px); --text-h3: clamp(14px, 2.5vw, 17px); --text-base: clamp(12px, 2vw, 14px); + --text-button: clamp(13px, 2vw, 15px); } *, @@ -27,10 +32,38 @@ body { font-family: Inter, sans-serif; + font-size: var(--text-base); + color: var(--color-base); line-height: 1.5; background-color: var(--color-bg); } +body:has(dialog[open]) { + overflow: hidden; +} + +p { + font-size: var(--text-base); + color: var(--color-base); +} + +h1 { + font-size: var(--text-h1); + color: var(--color-h1); +} + +h2 { + font-weight: var(--font-weight-bold); + font-size: var(--text-h2); + color: var(--color-base); +} + +h3 { + font-weight: var(--font-weight-semibold); + font-size: var(--text-h3); + color: var(--color-base2); +} + /* header */ .main-header { position: sticky; @@ -39,9 +72,4 @@ body { padding-block: calc(var(--spacing) * 6) calc(var(--spacing) * 2); padding-inline: calc(var(--spacing) * 6); box-shadow: 6px 10px 10px 0 color-mix(in srgb, var(--color-bg) 50%, transparent); -} - -.main-header h1 { - font-size: var(--text-h1); - color: var(--color-h1); } \ No newline at end of file diff --git a/src/styles/form.css b/src/styles/form.css new file mode 100644 index 0000000..ddc774d --- /dev/null +++ b/src/styles/form.css @@ -0,0 +1,31 @@ +.primary-btn, +.secondary-btn { + height: 45px; + min-width: 185px; + font-size: var(--text-button); + font-weight: var(--font-weight-bold); + display: flex; + align-items: center; + justify-content: center; + border: none; + text-decoration: none; + cursor: pointer; +} + +.primary-btn { + background-color: var(--color-primary); + color: var(--color-h1); +} + +.primary-btn:hover { + background-color: var(--color-primary-hover); +} + +.secondary-btn { + background-color: var(--color-secondary); + color: var(--color-bg); +} + +.secondary-btn:hover { + background-color: var(--color-secondary-hover); +} \ No newline at end of file diff --git a/src/styles/movie-list.css b/src/styles/movie-list.css index e7ad8f9..dc9f170 100644 --- a/src/styles/movie-list.css +++ b/src/styles/movie-list.css @@ -41,23 +41,6 @@ gap: 0.45rem; } -.movie-item-title { - font-weight: var(--font-weight-bold); - font-size: var(--text-h2); - color: var(--color-base); -} - -.movie-item-subtitle { - font-weight: var(--font-weight-semibold); - font-size: var(--text-h3); - color: var(--color-base2); -} - -.movie-item-details { - font-size: var(--text-base); - color: var(--color-base); -} - @media (max-width: 1024px) { .movie-list { grid-template-columns: repeat(2, minmax(0, 1fr)); diff --git a/src/styles/movie-modal.css b/src/styles/movie-modal.css new file mode 100644 index 0000000..0c5e828 --- /dev/null +++ b/src/styles/movie-modal.css @@ -0,0 +1,142 @@ +dialog { + align-self: center; + justify-self: center; + border: none; + padding: 0; + max-width: 860px; + width: 90%; + background-color: var(--color-bg); + color: var(--color-base); + box-shadow: 6px 10px 10px 0 color-mix(in srgb, var(--color-bg) 50%, transparent); +} + +dialog::backdrop { + background: rgba(0, 0, 0, 0.5); +} + +.movie-modal-header { + display: flex; + align-items: center; + height: 70px; + padding-inline: calc(var(--spacing) * 5); +} + +.movie-modal-header h3 { + flex-grow: 1; +} + +.movie-modal-close-btn { + background: none; + border: none; + font-weight: var(--font-weight-bold); + font-size: var(--text-h2); + color: var(--color-base); + cursor: pointer; +} + +.movie-modal-poster img { + width: 400px; + object-fit: cover; +} + +.movie-modal-body { + display: flex; +} + +.movie-modal-content { + display: flex; + flex-direction: column; + flex-grow: 1; + min-width: 0; + padding-inline: calc(var(--spacing) * 6); + padding-block-end: calc(var(--spacing) * 6); +} + +.movie-modal-content>div { + flex-grow: 1; + display: flex; + flex-direction: column; + gap: calc(var(--spacing) * 3); +} + +.movie-modal-content ul { + list-style: none; + display: flex; + flex-direction: column; + gap: calc(var(--spacing) * 2); +} + +.movie-modal-content li { + display: flex; +} + +.movie-modal-content li>span:nth-child(1) { + width: 160px; + flex: 0 0 auto; +} + +.movie-modal-content menu { + display: flex; + justify-content: center; + gap: calc(var(--spacing) * 7); +} + +@media (max-width: 1024px) { + .movie-modal-header { + height: 50px; + padding-inline: calc(var(--spacing) * 4); + } + + .movie-modal-content { + padding-block-end: calc(var(--spacing) * 2); + } + + .movie-modal-content li>span:nth-child(1) { + width: 140px; + } + + .movie-modal-content menu { + flex-direction: column; + gap: calc(var(--spacing) * 4); + } +} + +@media (max-width: 600px) { + dialog { + width: 100vw; + height: 100vh; + max-height: 100vh; + overflow: hidden; + } + + .movie-modal-header { + padding-inline: calc(var(--spacing) * 4); + position: relative; + width: 100vw; + background-color: var(--color-bg); + box-shadow: 6px 10px 10px 0 color-mix(in srgb, var(--color-bg) 50%, transparent); + } + + .movie-modal-body { + flex-direction: column; + overflow-y: auto; + height: calc(100vh - 120px); + } + + .movie-modal-content>div { + padding-block: calc(var(--spacing) * 3) calc(var(--spacing) * 10); + } + + .movie-modal-poster img { + object-fit: cover; + width: 100%; + } + + .movie-modal-content menu { + position: fixed; + bottom: calc(var(--spacing) * 3); + flex-direction: row; + left: 0; + width: 100vw; + } +} \ No newline at end of file