-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
name: All in One | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
permissions: | ||
contents: write # чтобы action мог push делать | ||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v4 | ||
|
||
- name: Install Rust | ||
uses: actions-rs/toolchain@v1 | ||
with: | ||
profile: minimal # этот профиль включает как можно меньше компонентов для работы компилятора. Он устанавливает rustc (компилятор Rust), rust-std (стандартную библиотеку Rust) и cargo (систему сборки и менеджер пакетов Rust) | ||
toolchain: nightly # ночная версия rust, а не стабильная, т.к. некоторые фишки практичнее здесь | ||
target: wasm32-unknown-unknown # обозначает платформу, для которой вы компилируете ваш код. В данном случае, wasm32-unknown-unknown указывает на то, что мы компилируем код для WebAssembly (wasm32) без конкретной операционной системы или процессора (unknown-unknown). | ||
override: true # следует ли перезаписать существующую установку Rust на вашей машине. установит указанный вами toolchain и target, даже если на вашей машине уже установлен другой toolchain или target | ||
|
||
- name: Install Trunk | ||
run: cargo install --locked trunk # установить trunk. --locked для гарантии, что Cargo будет использовать точные версии зависимостей, указанные в файле Cargo.lock. | ||
|
||
- name: Build with Trunk | ||
run: trunk build --release # сборка в статические файлы(html, js, wasm, favicon...) | ||
|
||
- name: Deploy to GitHub Pages | ||
uses: JamesIves/github-pages-deploy-action@v4 # специально разработан для деплоя на GitHub Pages | ||
with: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
BRANCH: gh-pages # в ветку gh-pages | ||
FOLDER: dist # из папки dist(формируется после сборки leptos) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/target | ||
/dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
[package] | ||
name = "wasm_parser" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["smir-ant"] | ||
|
||
[dependencies] | ||
leptos = { version = "0.6", features = ["csr", "nightly"] } # для создания реактивных компонентов в Rust. "csr" включает поддержку рендеринга на стороне клиента, а "nightly" активирует функции, доступные только в ночных сборках Rust. | ||
leptos_meta = { version = "0.6", features = ["csr", "nightly"] } # предоставляет дополнительные инструменты и утилиты для работы с метаданными и мета-тегами | ||
leptos_router = { version = "0.6", features = ["csr", "nightly"] } # предоставляет маршрутизацию для SPA (одностраничных приложений) | ||
web-sys = "0.3.69" # web-sys предоставляет доступ к браузерным API через WebAssembly, что позволяет взаимодействовать с DOM и другими веб-функциями. | ||
reqwasm = "0.5.0" # для выполнения HTTP-запросов в WebAssembly с использованием асинхронных функций. | ||
# почему не reqwest например? ring является библиотекой, которая зависит от компиляции C-кода, а это не поддерживается для WebAssembly | ||
scraper = "0.19.0" # для парсинга HTML документов и извлечения данных из них | ||
# wasm-bindgen = "0.2.92" # не использовал |для взаимодействия между WebAssembly и JavaScript, позволяя вызывать JavaScript из Rust и наоборот | ||
wasm-bindgen-futures = "0.4.42" # предоставляет инструменты для работы с асинхронным кодом в WebAssembly, интегрируя Future с wasm-bindgen | ||
rand = "0.8.5" # исключительно для случайного выбора классов картинкам | ||
|
||
[profile.release] # Этот раздел содержит настройки для сборки вашего проекта в режиме release. | ||
opt-level = 'z' # сargo будет стараться минимизировать размер бинарного файла. | ||
lto = true # включает оптимизацию всего программного обеспечения (Link Time Optimization, LTO) | ||
codegen-units = 1 # вы говорите компилятору обрабатывать всю вашу программу как одну единицу кодогенерации. Это может привести к более эффективной оптимизации кода, потому что компилятор видит всю программу целиком, но это также может замедлить процесс компиляции, потому что он не может использовать параллелизм для ускорения | компромисс между скоростью компиляции и эффективностью оптимизации. | ||
panic = "abort" # что делать при панике. abort означает, что процесс должен немедленно завершиться |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[build] | ||
public_url = "/wasm_parser/" # фикс путей для github-pages конкретно во всех dist файлах(т.к. в gh-pages мы начинаем не с "user.github.io/", а с "user.github.io/repository_name") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<!-- +wasm: https://rustwasm.github.io/docs/wasm-bindgen/reference/weak-references.html --> | ||
<link data-trunk rel="rust" data-wasm-opt="z" data-weak-refs /> | ||
|
||
<!-- +tailwind: https://trunkrs.dev/assets/#tailwind --> | ||
<link data-trunk rel="tailwind-css" href="/public/tailwind.css" /> | ||
|
||
<!-- +css: https://trunkrs.dev/assets/#css --> | ||
<link data-trunk rel="css" href="/public/styles.css" /> | ||
|
||
<!-- +favicon: https://trunkrs.dev/assets/#icon --> | ||
<link data-trunk rel="icon" href="/public/favicon.ico" /> | ||
</head> | ||
<body class="bg-neutral-100 dark:bg-neutral-800"></body> | ||
</html> |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.counter { | ||
margin: 20px 0px; | ||
} | ||
|
||
.counter > * { | ||
margin-right: 10px; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
@layer base { | ||
button { | ||
@apply p-3 rounded-lg text-black dark:text-white font-bold | ||
bg-gradient-to-r from-teal-500 to-lime-500; | ||
} | ||
|
||
input { | ||
@apply p-3 rounded-lg bg-white text-black dark:bg-black dark:text-white font-mono; | ||
} | ||
} | ||
|
||
@layer components { | ||
#images-container { | ||
@apply grid p-3 gap-3; | ||
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); | ||
grid-auto-rows: 150px; | ||
} | ||
|
||
#images-container img { | ||
@apply block w-full h-full object-cover rounded-xl; | ||
} | ||
|
||
/* Стили для разных размеров изображений */ | ||
.size1 { grid-row: span 1; grid-column: span 1; } | ||
.size2 { grid-row: span 2; grid-column: span 2; } | ||
.size3 { grid-row: span 2; grid-column: span 1; } | ||
.size4 { grid-row: span 1; grid-column: span 2; } | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[toolchain] | ||
channel = "nightly" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
use leptos::*; | ||
use leptos_meta::{provide_meta_context, Html, Meta, Title}; | ||
use leptos_router::{Router, Route, Routes}; | ||
|
||
mod pages; | ||
use crate::pages::home::Home; | ||
|
||
|
||
fn main() { | ||
mount_to_body(|| { | ||
provide_meta_context(); // контекст, который управляет различными аспектами веб-страницы, такими как стили, заголовки, мета-теги и т.д. | ||
// “контекст” обычно относится к набору данных или состоянию, которое доступно всему приложению или определенной его части | ||
|
||
view! { | ||
<Html lang="en" dir="ltr" /> // ltr (слева-направо направление текста) | ||
<Title text="WASM parser by smir-ant"/> // название страницы | ||
<Meta charset="UTF-8"/> | ||
<Meta name="viewport" content="width=device-width, initial-scale=1.0"/> | ||
|
||
<Router> | ||
<Routes> | ||
<Route path="/*" view=Home /> | ||
</Routes> | ||
</Router> | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
use leptos::*; // Leptos для создания реактивных компонентов | ||
use web_sys::console; // для логирования в консоль браузера | ||
use reqwasm::http::Request; // для выполнения HTTP-запросов из wasm | ||
use wasm_bindgen_futures::spawn_local; // для запуска асинхронных операций в текущем потоке | ||
use scraper::{Html, Selector}; // для парсинга HTML | ||
use rand::seq::SliceRandom; use rand::thread_rng; // для выбора случайного класса | ||
use leptos::ev::SubmitEvent; | ||
|
||
#[component] | ||
pub fn Home() -> impl IntoView { | ||
// Создаем сигнал для хранения запроса, введенного пользователем | несмотря на ссылку в value=""(речь про <input type=text>), сигнал, связанный с этим полем нужно тоже инициализировать по умолчанию этой же ссылкой | ||
let (search_request, set_search_request) = create_signal("rust".to_string()); // p.s. иначе если сходу нажать на подгрузить, то компонент не тригернёт и value не будет взят для ссылки | ||
|
||
// Создаем сигнал для хранения количества изображений, которые нужно загрузить | ||
let (num_images, set_num_images) = create_signal(1); | ||
|
||
// Обработчик клика по кнопке "Подгрузить" | ||
let submit = { | ||
let search_request = search_request.clone(); // Клонируем сигнал search_request для использования в замыкании | ||
let num_images = num_images.clone(); // Клонируем сигнал num_images для использования в замыкании | ||
move |e: SubmitEvent| { | ||
e.prevent_default(); // Предотвращаем отправку формы | ||
|
||
let url_value = search_request.get(); // Получаем текущее значение URL | ||
let num_images_value = num_images.get(); // Получаем текущее значение количества изображений | ||
|
||
// Логируем значения в консоль для отладки | ||
console::log_1(&url_value.clone().into()); | ||
console::log_1(&num_images_value.to_string().into()); | ||
|
||
// Формируем URL для запроса с использованием введенного пользователем URL | CORS-ANYWHERE + UNSPLASH | ||
let url = format!("https://cors-anywhere.herokuapp.com/https://unsplash.com/s/photos/{}", url_value); | ||
console::log_1(&format!("Полученная ссылка для парсинга: {:?}", url).into()); | ||
// Выполнение асинхронного GET-запроса | ||
spawn_local(async move { | ||
// Отправляем GET-запрос и ждем ответа | ||
match Request::get(&url).send().await { | ||
// Если запрос выполнен успешно | ||
Ok(response) => { | ||
if response.ok() { // Если ответ успешный (код 200) | ||
let body = response.text().await.unwrap(); // Получаем текст ответа | ||
parse_html_and_log_images(&body, num_images_value); // Парсим HTML и логируем изображения | ||
} else { | ||
console::log_1(&"запрос не 200(OK)".into()); // Логируем ошибку, если ответ не успешный | ||
} | ||
} | ||
// Если произошла ошибка при выполнении запроса | ||
Err(err) => { | ||
console::log_1(&format!("Ошибка: {:?}", err).into()); // Логируем ошибку | ||
} | ||
} | ||
}); | ||
} | ||
}; | ||
|
||
// Формируем HTML представление компонента | ||
view! { | ||
<form class="m-4 flex justify-between" on:submit=submit> // форма для валидации(max и min), чтобы не было -10 картинок, а то там работает, но не совсем так как ожидается | ||
<a href="https://github.com/smir-ant/wasm_parser"> | ||
<img class="inline-block w-12 mr-4 dark:invert animate-pulse" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/Octicons-mark-github.svg/1200px-Octicons-mark-github.svg.png" /> | ||
</a> | ||
// Поле ввода для URL | ||
<input class="mr-2 w-[65%]" type="text" value="rust" placeholder="что будем искать?" on:input=move |e| set_search_request(event_target_value(&e)) /> | ||
// Поле ввода для количества изображений | ||
<input class="mr-2 w-[20%]" type="number" min="1" max="999" placeholder="кол-во изображений" on:input=move |e| set_num_images(event_target_value(&e).parse().unwrap_or(1)) /> | ||
// Кнопка для отправки запроса | ||
<button>{"Подгрузить"}</button> | ||
</form> | ||
// Контейнер для изображений | ||
<div id="images-container"></div> | ||
} | ||
} | ||
|
||
// Функция для парсинга HTML и логирования изображений | ||
fn parse_html_and_log_images(html: &str, num_images: usize) { | ||
// Парсинг HTML с помощью библиотеки scraper | ||
let document = Html::parse_document(html); // Создаем документ из HTML строки | ||
let selector = Selector::parse("img[src]").unwrap(); // Создаем селектор для выбора всех тегов img с атрибутом src | ||
|
||
let window = web_sys::window().expect("отсутствует a Window"); // Получаем объект окна браузера | ||
let web_document = window.document().expect("отсутствует Document"); // Получаем объект документа браузера | ||
let images_container = web_document.get_element_by_id("images-container").expect("отсутствует #images-container"); // Получаем контейнер для изображений | ||
images_container.set_inner_html(""); // Очистка содержимого контейнера | если несколько раз был запрос | ||
let mut will_show_count = 0; | ||
|
||
// Перебираем найденные элементы img и добавляем их на страницу | ||
for (i, element) in document.select(&selector).enumerate() { | ||
if will_show_count >= num_images { | ||
break; // Прерываем цикл, если добавлено достаточно изображений | ||
} | ||
|
||
if let Some(src) = element.value().attr("src") { | ||
if src.starts_with("data:") || src.starts_with("https://images.unsplash.com/profile") || src.starts_with("https://images.unsplash.com/placeholder"){ continue; } // фильтруем лишнее | ||
will_show_count += 1; // выше убрали мусор, и теперь вроде как норм фотка, поэтому +1 | ||
console::log_1(&src.into()); // Логируем src изображения в консоль | ||
|
||
// Создание элемента img с помощью web_sys | ||
let img = web_document.create_element("img").unwrap(); // Создаем <img> | ||
img.set_attribute("src", src).unwrap(); // Устанавливаем атрибут src | ||
|
||
// делаем ссылку, в которую будет помещена картинка | ||
let link = web_document.create_element("a").unwrap(); // Создаем <a> | ||
link.set_attribute("href", src).unwrap(); // Устанавливаем атрибут href в <a> | ||
link.append_child(&img).unwrap(); // <img> идёт внутрь <a> | ||
link.set_attribute("class", ["size1", "size2", "size3", "size4"].choose(&mut thread_rng()).unwrap()).unwrap(); // случайный класс для размера | ||
|
||
images_container.append_child(&link).unwrap(); // вкладываем ссылку+картинку в контейнер | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod home; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/** @type {import('tailwindcss').Config} */ | ||
module.exports = { | ||
content: { | ||
files: ["*.html", "src/pages/*.rs"], | ||
}, | ||
theme: { | ||
extend: { | ||
colors: { // переопределяем цвета | ||
neutral: { // группы neutral | ||
100: '#F1F1F1', | ||
800: '#202020' | ||
} | ||
} | ||
}, | ||
}, | ||
plugins: [], | ||
} |