Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d58f50c03 |
|
|
@ -74,7 +74,7 @@ style-file = "style/output.css"
|
|||
# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
|
||||
#
|
||||
# Optional. Env: LEPTOS_ASSETS_DIR.
|
||||
assets-dir = "public"
|
||||
assets-dir = "/home/denis/wallpaper-gen-data"
|
||||
|
||||
# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup.
|
||||
site-addr = "0.0.0.0:3000"
|
||||
|
|
|
|||
26
input.css
26
input.css
|
|
@ -21,6 +21,29 @@ body {
|
|||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.hosting {
|
||||
@apply inline-flex items-center justify-between;
|
||||
@apply w-full;
|
||||
@apply p-2;
|
||||
@apply text-gray-500;
|
||||
@apply bg-white;
|
||||
@apply border;
|
||||
@apply border-gray-200;
|
||||
@apply rounded-lg;
|
||||
@apply cursor-pointer;
|
||||
@apply dark:hover:text-gray-300;
|
||||
@apply dark:border-gray-700;
|
||||
@apply dark:peer-checked:text-blue-500;
|
||||
@apply peer-checked:border-blue-600;
|
||||
@apply peer-checked:text-blue-600;
|
||||
@apply hover:text-gray-600;
|
||||
@apply hover:bg-gray-100;
|
||||
@apply dark:text-gray-400;
|
||||
@apply dark:bg-gray-800;
|
||||
@apply dark:hover:bg-gray-700;
|
||||
@apply text-center;
|
||||
}
|
||||
|
||||
.pic-outer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
@ -41,7 +64,7 @@ body {
|
|||
}
|
||||
|
||||
.pic-inner:hover {
|
||||
transform: scale(0.98);
|
||||
transform: scale(0.99);
|
||||
}
|
||||
|
||||
#info-button {
|
||||
|
|
@ -73,6 +96,7 @@ body {
|
|||
/* The container <div> - needed to position the dropdown content */
|
||||
.dropdown {
|
||||
position: relative;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
/* Dropdown Content (Hidden by Default) */
|
||||
|
|
|
|||
403
src/app.rs
403
src/app.rs
|
|
@ -3,6 +3,7 @@ use cfg_if::*;
|
|||
use leptos::*;
|
||||
use leptos_meta::*;
|
||||
use leptos_router::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature="ssr")]{
|
||||
|
|
@ -48,14 +49,14 @@ pub fn App() -> impl IntoView {
|
|||
fn Home() -> impl IntoView {
|
||||
use leptos::html::Div;
|
||||
use leptos_use::*;
|
||||
let (size, set_size) = create_signal(1.);
|
||||
let (size, set_size) = create_signal(1);
|
||||
let (page, set_page) = create_signal(0);
|
||||
//let res = create_local_resource(page, get_pics2);
|
||||
let (all, set_all) = create_signal(Vec::<PicStruct>::new());
|
||||
let res = create_local_resource(
|
||||
move || (page.get(), size.get()),
|
||||
move |d| get_pics2(d.0, d.1),
|
||||
);
|
||||
let (all, set_all) = create_signal(Vec::<Wallpaper>::new());
|
||||
let (search_string, set_search_string) = create_signal("".to_string());
|
||||
let res = create_local_resource(page, get_pics2);
|
||||
let s_res = create_local_resource(search_string, get_pics);
|
||||
|
||||
let el = create_node_ref::<Div>();
|
||||
|
||||
let _ = use_infinite_scroll_with_options(
|
||||
|
|
@ -67,294 +68,220 @@ fn Home() -> impl IntoView {
|
|||
res.and_then(move |_| {
|
||||
set_all.update(|dat| dat.extend(res().unwrap().unwrap()));
|
||||
});
|
||||
/*if !res.loading().get() {
|
||||
set_page.update(|page| *page += 1);
|
||||
} else if res().is_some() {
|
||||
set_all.update(|dat| dat.extend(res().unwrap().unwrap()));
|
||||
// println!("{:?}", all().len())
|
||||
}*/
|
||||
},
|
||||
UseInfiniteScrollOptions::default().distance(10.0),
|
||||
UseInfiniteScrollOptions::default().distance(512.),
|
||||
);
|
||||
|
||||
view! {
|
||||
<h1>"Home"</h1>
|
||||
<div>
|
||||
<div class="text-center m-3">
|
||||
<div class="w-72">
|
||||
<div class="relative w-full min-w-[200px] h-10">
|
||||
<input
|
||||
class="peer w-full h-full bg-transparent text-blue-gray-700 font-sans font-normal outline outline-0 focus:outline-0 disabled:bg-blue-gray-50 disabled:border-0 transition-all placeholder-shown:border placeholder-shown:border-blue-gray-200 placeholder-shown:border-t-blue-gray-200 border focus:border-2 border-t-transparent focus:border-t-transparent text-sm px-3 py-2.5 rounded-[7px] border-blue-gray-200 focus:border-gray-900"
|
||||
placeholder=" "
|
||||
on:input=move |ev| {
|
||||
set_size(event_target_value(&ev).parse::<f64>().unwrap());
|
||||
set_all.update(|all| all.clear());
|
||||
set_search_string(event_target_value(&ev));
|
||||
}
|
||||
|
||||
prop:value=size
|
||||
type="range"
|
||||
min="0.5"
|
||||
max="2"
|
||||
step="0.5"
|
||||
value="1"
|
||||
/>
|
||||
|
||||
<label class="flex w-full h-full select-none pointer-events-none absolute left-0 font-normal !overflow-visible truncate peer-placeholder-shown:text-blue-gray-500 leading-tight peer-focus:leading-tight peer-disabled:text-transparent peer-disabled:peer-placeholder-shown:text-blue-gray-500 transition-all -top-1.5 peer-placeholder-shown:text-sm text-[11px] peer-focus:text-[11px] before:content[' '] before:block before:box-border before:w-2.5 before:h-1.5 before:mt-[6.5px] before:mr-1 peer-placeholder-shown:before:border-transparent before:rounded-tl-md before:border-t peer-focus:before:border-t-2 before:border-l peer-focus:before:border-l-2 before:pointer-events-none before:transition-all peer-disabled:before:border-transparent after:content[' '] after:block after:flex-grow after:box-border after:w-2.5 after:h-1.5 after:mt-[6.5px] after:ml-1 peer-placeholder-shown:after:border-transparent after:rounded-tr-md after:border-t peer-focus:after:border-t-2 after:border-r peer-focus:after:border-r-2 after:pointer-events-none after:transition-all peer-disabled:after:border-transparent peer-placeholder-shown:leading-[3.75] text-gray-500 peer-focus:text-gray-900 before:border-blue-gray-200 peer-focus:before:!border-gray-900 after:border-blue-gray-200 peer-focus:after:!border-gray-900">
|
||||
"Username"
|
||||
</label>
|
||||
<p>"Input is: " {search_string}</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="grid w-1/3 gap-3 md:grid-cols-3 m-auto">
|
||||
<li>
|
||||
<input
|
||||
type="radio"
|
||||
id="hosting-small"
|
||||
name="hosting"
|
||||
value="hosting-small"
|
||||
class="hidden peer"
|
||||
required
|
||||
on:input=move |_| {
|
||||
set_size(0);
|
||||
}
|
||||
/>
|
||||
|
||||
<label for="hosting-small" class="hosting">
|
||||
<div class="block">
|
||||
<div class="w-full text-lg font-semibold">"256"</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
type="radio"
|
||||
id="hosting-big"
|
||||
name="hosting"
|
||||
value="hosting-big"
|
||||
class="hidden peer"
|
||||
checked="checked"
|
||||
on:input=move |_| {
|
||||
set_size(1);
|
||||
}
|
||||
/>
|
||||
|
||||
<label for="hosting-big" class="hosting">
|
||||
<div class="block">
|
||||
<div class="w-full text-lg font-semibold">"512"</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
<li>
|
||||
<input
|
||||
type="radio"
|
||||
id="hosting-biger"
|
||||
name="hosting"
|
||||
value="hosting-biger"
|
||||
class="hidden peer"
|
||||
on:input=move |_| {
|
||||
set_size(2);
|
||||
}
|
||||
/>
|
||||
|
||||
<label for="hosting-biger" class="hosting">
|
||||
<div class="block">
|
||||
<div class="w-full text-lg font-semibold">"1024"</div>
|
||||
</div>
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="main overflow-y-auto max-h-300" node_ref=el>
|
||||
<For each=move || all.get() key=|state| state.key.clone() let:child>
|
||||
<Pic width=child.width height=child.height scale=size url=child.url/>
|
||||
<For
|
||||
each=move || all.get()
|
||||
key=move |state| state.thumbs[size() as usize].clone()
|
||||
let:child
|
||||
>
|
||||
<Pic size=size.get() url=child.thumbs[size() as usize].clone() wp=child/>
|
||||
</For>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<p class="text-center">{move || page()}</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct PicStruct {
|
||||
key: String,
|
||||
width: i32,
|
||||
height: i32,
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
struct Wallpaper {
|
||||
pub struct Wallpaper {
|
||||
file_name: String,
|
||||
info: String,
|
||||
date_added: String,
|
||||
height: u64,
|
||||
width: u64,
|
||||
height: i32,
|
||||
width: i32,
|
||||
path: String,
|
||||
thumbs: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Name<'a> {
|
||||
first: &'a str,
|
||||
last: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Person<'a> {
|
||||
title: &'a str,
|
||||
name: Name<'a>,
|
||||
marketing: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Responsibility {
|
||||
marketing: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Record {
|
||||
#[allow(dead_code)]
|
||||
id: i32,
|
||||
}
|
||||
|
||||
use std::env;
|
||||
|
||||
#[server(GetPics, "/api")]
|
||||
pub async fn get_pics2(page: i32, size: f64) -> Result<Vec<PicStruct>, ServerFnError> {
|
||||
use image::GenericImageView;
|
||||
use imageinfo::ImageInfo;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[server(GetPicsSearch, "/api")]
|
||||
pub async fn get_pics(search_string: String) -> Result<Vec<Wallpaper>, ServerFnError> {
|
||||
let query = "
|
||||
SELECT * FROM wallpapers LIMIT 10;
|
||||
DEFINE ANALYZER book_analyzer TOKENIZERS blank,class,punct FILTERS snowball(english);
|
||||
DEFINE INDEX info_s ON wallpapers FIELDS info SEARCH ANALYZER book_analyzer BM25(1.2,0.75);
|
||||
SELECT *
|
||||
FROM wallpapers
|
||||
WHERE info @0@ 'asdasd'
|
||||
LIMIT 10;
|
||||
";
|
||||
|
||||
let db = Surreal::new::<Ws>("127.0.0.1:8000")
|
||||
.await
|
||||
.expect("Couldnt connect to db server");
|
||||
println!("{search_string:#?}");
|
||||
db.set("page", search_string)
|
||||
.await
|
||||
.expect("Couldnt set war");
|
||||
// Select a specific namespace / database
|
||||
db.use_ns("test")
|
||||
.use_db("test")
|
||||
.await
|
||||
.expect("Couldnt find db");
|
||||
//let papers: Vec<Wallpaper> = db.select("wallpapers").await.expect("Err");
|
||||
//println!("{papers:#?}");
|
||||
|
||||
let mut res = db.query(query).await?;
|
||||
let pap: Vec<Wallpaper> = res.take(0)?;
|
||||
println!("{pap:#?}");
|
||||
let mut res = db.query(query).await.expect("Something");
|
||||
let pap: Vec<Wallpaper> = res.take(0).expect("Something");
|
||||
//println!("{pap:#?}");
|
||||
|
||||
let mut pics = Vec::new();
|
||||
Ok(pap)
|
||||
}
|
||||
|
||||
let folder_path = "./public";
|
||||
#[server(GetPics, "/api")]
|
||||
pub async fn get_pics2(page: i32) -> Result<Vec<Wallpaper>, ServerFnError> {
|
||||
let query = "
|
||||
SELECT * FROM wallpapers LIMIT 20 START $page;
|
||||
";
|
||||
|
||||
// Define the number of pictures per page
|
||||
let pics_per_page = 10;
|
||||
let db = Surreal::new::<Ws>("127.0.0.1:8000")
|
||||
.await
|
||||
.expect("Couldnt connect to db server");
|
||||
println!("{page:#?}");
|
||||
db.set("page", page * 20).await.expect("Couldnt set war");
|
||||
// Select a specific namespace / database
|
||||
db.use_ns("test")
|
||||
.use_db("test")
|
||||
.await
|
||||
.expect("Couldnt find db");
|
||||
|
||||
// Calculate the index to start from based on the page number
|
||||
let start_index = (page) * pics_per_page;
|
||||
let end_index = start_index + pics_per_page;
|
||||
let mut res = db.query(query).await.expect("Something");
|
||||
let pap: Vec<Wallpaper> = res.take(0).expect("Something");
|
||||
//println!("{pap:#?}");
|
||||
|
||||
// manage a vector with all the image paths
|
||||
let mut image_file_paths = Vec::<PathBuf>::new();
|
||||
for entry in fs::read_dir(folder_path)? {
|
||||
let entry = entry?;
|
||||
let file_path = entry.path();
|
||||
let file_name_str = file_path.file_name().unwrap_or_default().to_str().unwrap();
|
||||
if size == 0.5 {
|
||||
//skip 1024 and 512
|
||||
if file_name_str.contains("512x512") || file_name_str.contains("1024x1024") {
|
||||
continue;
|
||||
}
|
||||
} else if size == 1.0 {
|
||||
if file_name_str.contains("256x256") || file_name_str.contains("1024x1024") {
|
||||
println!("sdfasdf");
|
||||
continue;
|
||||
}
|
||||
} else if size == 1.5 {
|
||||
if file_name_str.contains("256x256") || file_name_str.contains("512x512") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
image_file_paths.push(file_path.clone());
|
||||
}
|
||||
|
||||
for (i, file_path) in image_file_paths.iter().enumerate() {
|
||||
if file_path.is_file() {
|
||||
if i < start_index as usize {
|
||||
continue;
|
||||
}
|
||||
let file = std::fs::File::open(file_path)?;
|
||||
let mut bufreader = std::io::BufReader::new(&file);
|
||||
let exifreader = exif::Reader::new();
|
||||
let exif = exifreader.read_from_container(&mut bufreader)?;
|
||||
for f in exif.fields() {
|
||||
println!(
|
||||
"{} {} {}",
|
||||
f.tag,
|
||||
f.ifd_num,
|
||||
f.display_value().with_unit(&exif)
|
||||
);
|
||||
}
|
||||
let file_name = file_path.file_name().unwrap_or_default();
|
||||
let file_name_str = file_name.to_str().unwrap();
|
||||
// Check if the file has a supported image extension
|
||||
if let Some(extension) = file_path.extension() {
|
||||
if let Some(extension_str) = extension.to_str() {
|
||||
if image::ImageFormat::from_extension(extension_str).is_some() {
|
||||
// Process the image
|
||||
let img = image::open(&file_path).expect("Failed to open image");
|
||||
let (x, y) = img.dimensions();
|
||||
|
||||
pics.push(PicStruct {
|
||||
key: file_name_str.to_string(), // Could not be unique if two images were created at exactly
|
||||
// the same time
|
||||
width: x as i32,
|
||||
height: y as i32,
|
||||
url: file_name.to_string_lossy().into(),
|
||||
});
|
||||
if i + 1 >= end_index as usize {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send different picture resolutions depending on selected size
|
||||
// sizes 256 512 1024
|
||||
|
||||
// Iterate over the entries in the folder
|
||||
/*for (index, entry) in fs::read_dir(folder_path)
|
||||
.expect("Failed to read directory")
|
||||
.enumerate()
|
||||
{
|
||||
if let Ok(entry) = entry {
|
||||
if index < start_index as usize {
|
||||
// Skip pictures before the start index
|
||||
continue;
|
||||
}
|
||||
|
||||
let file_path = entry.path();
|
||||
let file_name = file_path.file_name().unwrap_or_default();
|
||||
let file_name_str = file_name.to_str().unwrap();
|
||||
// Skip the wrong sizes
|
||||
if size == 0.5 {
|
||||
//skip 1024 and 512
|
||||
if file_name_str.contains("512x512") || file_name_str.contains("1024x1024") {
|
||||
continue;
|
||||
}
|
||||
} else if size == 1.0 {
|
||||
if file_name_str.contains("256x256") || file_name_str.contains("1024x1024") {
|
||||
continue;
|
||||
}
|
||||
} else if size == 1.5 {
|
||||
if file_name_str.contains("256x256") || file_name_str.contains("512x512") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the entry is a file
|
||||
if file_path.is_file() {
|
||||
// Check if the file has a supported image extension
|
||||
if let Some(extension) = file_path.extension() {
|
||||
if let Some(extension_str) = extension.to_str() {
|
||||
if image::ImageFormat::from_extension(extension_str).is_some() {
|
||||
// Process the image
|
||||
let img = image::open(&file_path).expect("Failed to open image");
|
||||
let (x, y) = img.dimensions();
|
||||
|
||||
pics.push(PicStruct {
|
||||
key: file_name_str.to_string(), // Could not be unique if two images were created at exactly
|
||||
// the same time
|
||||
width: x as i32,
|
||||
height: y as i32,
|
||||
url: file_name.to_string_lossy().into(),
|
||||
});
|
||||
|
||||
// Break if we have reached the end index
|
||||
if index + 1 >= end_index as usize {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
println!("{:#?}", pics);
|
||||
|
||||
Ok(pics)
|
||||
Ok(pap)
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Info(show: ReadSignal<bool>, set_show: WriteSignal<bool>) -> impl IntoView {
|
||||
fn Info(show: ReadSignal<bool>, set_show: WriteSignal<bool>, wp: Wallpaper) -> impl IntoView {
|
||||
view! {
|
||||
<Show when=move || show()>
|
||||
<div id="info-main" class="rounded">
|
||||
<button type="button" on:click=move |_| set_show(false)>
|
||||
<div id="info-main" class="rounded text-center">
|
||||
<button
|
||||
on:click=move |_| set_show(false)
|
||||
class="bg-blue-500 hover:bg-blue-400 text-white font-bold py-2 px-4 border-b-4 border-blue-700 hover:border-blue-500 rounded"
|
||||
>
|
||||
"Close"
|
||||
</button>
|
||||
<input type="text" id="country" name="country" value="Norway" readonly/>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="w-96">
|
||||
<div class="relative w-full min-w-[200px]">
|
||||
<textarea
|
||||
class="peer h-full min-h-[100px] w-full resize-none rounded-[7px] border border-blue-gray-200 border-t-transparent bg-transparent px-3 py-2.5 font-sans text-sm font-normal text-blue-gray-700 outline outline-0 transition-all placeholder-shown:border placeholder-shown:border-blue-gray-200 placeholder-shown:border-t-blue-gray-200 focus:border-2 focus:border-gray-900 focus:border-t-transparent focus:outline-0 disabled:resize-none disabled:border-0 disabled:bg-blue-gray-50"
|
||||
placeholder=" "
|
||||
prop:value=&wp.info
|
||||
></textarea>
|
||||
<label class="before:content[' '] after:content[' '] pointer-events-none absolute left-0 -top-1.5 flex h-full w-full select-none text-[11px] font-normal leading-tight text-blue-gray-400 transition-all before:pointer-events-none before:mt-[6.5px] before:mr-1 before:box-border before:block before:h-1.5 before:w-2.5 before:rounded-tl-md before:border-t before:border-l before:border-blue-gray-200 before:transition-all after:pointer-events-none after:mt-[6.5px] after:ml-1 after:box-border after:block after:h-1.5 after:w-2.5 after:flex-grow after:rounded-tr-md after:border-t after:border-r after:border-blue-gray-200 after:transition-all peer-placeholder-shown:text-sm peer-placeholder-shown:leading-[3.75] peer-placeholder-shown:text-blue-gray-500 peer-placeholder-shown:before:border-transparent peer-placeholder-shown:after:border-transparent peer-focus:text-[11px] peer-focus:leading-tight peer-focus:text-gray-900 peer-focus:before:border-t-2 peer-focus:before:border-l-2 peer-focus:before:border-gray-900 peer-focus:after:border-t-2 peer-focus:after:border-r-2 peer-focus:after:border-gray-900 peer-disabled:text-transparent peer-disabled:before:border-transparent peer-disabled:after:border-transparent peer-disabled:peer-placeholder-shown:text-blue-gray-500">
|
||||
Message
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Pic(width: i32, height: i32, url: String, scale: ReadSignal<f64>) -> impl IntoView {
|
||||
fn Pic(url: String, size: i32, wp: Wallpaper) -> impl IntoView {
|
||||
let (showInfo, set_showInfo) = create_signal(false);
|
||||
let mut w_url = url.clone();
|
||||
let ww_url = w_url.split_off(31);
|
||||
let asd = &url.chars().position(|c| c == 'x').unwrap();
|
||||
let wh = &url[(asd - 3)..(asd + 4)];
|
||||
println!("{wh:#?}");
|
||||
|
||||
//let w: i32 = (&wh[..3]).parse().unwrap_or(333);
|
||||
//let h: i32 = (&wh[4..]).parse().unwrap_or(333);
|
||||
let w: i32 = 256 as i32 * (2 as i32).pow(size as u32);
|
||||
let h: i32 = (&wh[4..]).parse().unwrap_or(333);
|
||||
|
||||
view! {
|
||||
<div
|
||||
class="pic-outer"
|
||||
// style="border:1px solid black;"
|
||||
style:width=move || format!("{}px", f64::from(width + 10))
|
||||
style:height=move || format!("{}px", f64::from(height + 10))
|
||||
style:width=move || format!("{}px", w + 10)
|
||||
style:height=move || format!("{}px", h + 10)
|
||||
>
|
||||
<div
|
||||
class="pic-inner"
|
||||
style=format!("background-image: url('{}'); background-size: cover;", url)
|
||||
style:width=move || format!("{}px", f64::from(width))
|
||||
style:height=move || format!("{}px", f64::from(height))
|
||||
style=format!("background-image: url('{}'); background-size: cover;", ww_url)
|
||||
style:width=move || format!("{}px", w)
|
||||
style:height=move || format!("{}px", h)
|
||||
>
|
||||
<div class="dropdown">
|
||||
<div class="dropdown w-25 relative">
|
||||
<button class="dropbtn">
|
||||
<i class="fa-solid fa-download"></i>
|
||||
</button>
|
||||
|
|
@ -364,12 +291,18 @@ fn Pic(width: i32, height: i32, url: String, scale: ReadSignal<f64>) -> impl Int
|
|||
<a href="#">4:3</a>
|
||||
</div>
|
||||
</div>
|
||||
<button id="info-button" on:click=move |_| set_showInfo(true)>
|
||||
<button
|
||||
id="info-button"
|
||||
on:click=move |_| {
|
||||
if showInfo.get() { set_showInfo(false) } else { set_showInfo(true) }
|
||||
}
|
||||
>
|
||||
|
||||
<i class="fa-regular fa-circle-question"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Info show=showInfo set_show=set_showInfo/>
|
||||
<Info show=showInfo set_show=set_showInfo wp=wp/>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
578
style/output.css
578
style/output.css
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
::before,
|
||||
::after {
|
||||
--tw-content: "";
|
||||
--tw-content: '';
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -46,8 +46,7 @@ html,
|
|||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
/* 3 */
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
|
||||
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
/* 4 */
|
||||
font-feature-settings: normal;
|
||||
/* 5 */
|
||||
|
|
@ -136,8 +135,7 @@ code,
|
|||
kbd,
|
||||
samp,
|
||||
pre {
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
||||
"Liberation Mono", "Courier New", monospace;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
/* 1 */
|
||||
font-feature-settings: normal;
|
||||
/* 2 */
|
||||
|
|
@ -236,9 +234,9 @@ select {
|
|||
*/
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
[type='button'],
|
||||
[type='reset'],
|
||||
[type='submit'] {
|
||||
-webkit-appearance: button;
|
||||
/* 1 */
|
||||
background-color: transparent;
|
||||
|
|
@ -285,7 +283,7 @@ Correct the cursor style of increment and decrement buttons in Safari.
|
|||
2. Correct the outline style in Safari.
|
||||
*/
|
||||
|
||||
[type="search"] {
|
||||
[type='search'] {
|
||||
-webkit-appearance: textfield;
|
||||
/* 1 */
|
||||
outline-offset: -2px;
|
||||
|
|
@ -378,8 +376,7 @@ textarea {
|
|||
2. Set the default placeholder color to the user's configured gray 400 color.
|
||||
*/
|
||||
|
||||
input::-moz-placeholder,
|
||||
textarea::-moz-placeholder {
|
||||
input::-moz-placeholder, textarea::-moz-placeholder {
|
||||
opacity: 1;
|
||||
/* 1 */
|
||||
color: #9ca3af;
|
||||
|
|
@ -447,9 +444,7 @@ video {
|
|||
display: none;
|
||||
}
|
||||
|
||||
*,
|
||||
::before,
|
||||
::after {
|
||||
*, ::before, ::after {
|
||||
--tw-border-spacing-x: 0;
|
||||
--tw-border-spacing-y: 0;
|
||||
--tw-translate-x: 0;
|
||||
|
|
@ -549,26 +544,216 @@ video {
|
|||
--tw-backdrop-sepia: ;
|
||||
}
|
||||
|
||||
.pointer-events-none {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.-top-1 {
|
||||
top: -0.25rem;
|
||||
}
|
||||
|
||||
.-top-1\.5 {
|
||||
top: -0.375rem;
|
||||
}
|
||||
|
||||
.left-0 {
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.m-3 {
|
||||
margin: 0.75rem;
|
||||
}
|
||||
|
||||
.m-auto {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.h-10 {
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.min-h-\[100px\] {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.w-1\/3 {
|
||||
width: 33.333333%;
|
||||
}
|
||||
|
||||
.w-72 {
|
||||
width: 18rem;
|
||||
}
|
||||
|
||||
.w-96 {
|
||||
width: 24rem;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.min-w-\[200px\] {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.select-none {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.resize-none {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.gap-3 {
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.\!overflow-visible {
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.overflow-y-auto {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.truncate {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.rounded-\[7px\] {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.border {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.border-b-4 {
|
||||
border-bottom-width: 4px;
|
||||
}
|
||||
|
||||
.border-blue-700 {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(29 78 216 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.border-t-transparent {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
.bg-blue-500 {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.bg-transparent {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.px-3 {
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
|
||||
.px-4 {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.py-2 {
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.py-2\.5 {
|
||||
padding-top: 0.625rem;
|
||||
padding-bottom: 0.625rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-\[11px\] {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.text-sm {
|
||||
font-size: 0.750rem;
|
||||
}
|
||||
|
||||
.font-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.font-normal {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.leading-tight {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.text-gray-500 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.text-white {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(255 255 255 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.outline {
|
||||
outline-style: solid;
|
||||
}
|
||||
|
||||
.outline-0 {
|
||||
outline-width: 0px;
|
||||
}
|
||||
|
||||
.transition-all {
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: Noto Sans Tai Tham;
|
||||
color: #eaf0f0;
|
||||
|
|
@ -588,6 +773,72 @@ body {
|
|||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.hosting {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(107 114 128 / var(--tw-text-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
|
||||
border-width: 1px;
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.hosting:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(209 213 219 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hosting {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(55 65 81 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.peer:checked ~ .hosting {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(59 130 246 / var(--tw-text-opacity));
|
||||
}
|
||||
}
|
||||
|
||||
.peer:checked ~ .hosting {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(37 99 235 / var(--tw-border-opacity));
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(37 99 235 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.hosting:hover {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(75 85 99 / var(--tw-text-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.hosting {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(156 163 175 / var(--tw-text-opacity));
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.hosting:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
|
||||
}
|
||||
}
|
||||
|
||||
.hosting {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pic-outer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
@ -609,7 +860,7 @@ body {
|
|||
}
|
||||
|
||||
.pic-inner:hover {
|
||||
transform: scale(0.98);
|
||||
transform: scale(0.99);
|
||||
}
|
||||
|
||||
#info-button {
|
||||
|
|
@ -643,7 +894,7 @@ body {
|
|||
|
||||
.dropdown {
|
||||
position: relative;
|
||||
width: 40px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
/* Dropdown Content (Hidden by Default) */
|
||||
|
|
@ -690,3 +941,298 @@ body {
|
|||
.dropdown:hover .dropdown-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.before\:pointer-events-none::before {
|
||||
content: var(--tw-content);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.before\:mr-1::before {
|
||||
content: var(--tw-content);
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.before\:mt-\[6\.5px\]::before {
|
||||
content: var(--tw-content);
|
||||
margin-top: 6.5px;
|
||||
}
|
||||
|
||||
.before\:box-border::before {
|
||||
content: var(--tw-content);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.before\:block::before {
|
||||
content: var(--tw-content);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.before\:h-1::before {
|
||||
content: var(--tw-content);
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
.before\:h-1\.5::before {
|
||||
content: var(--tw-content);
|
||||
height: 0.375rem;
|
||||
}
|
||||
|
||||
.before\:w-2::before {
|
||||
content: var(--tw-content);
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
.before\:w-2\.5::before {
|
||||
content: var(--tw-content);
|
||||
width: 0.625rem;
|
||||
}
|
||||
|
||||
.before\:rounded-tl-md::before {
|
||||
content: var(--tw-content);
|
||||
border-top-left-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.before\:border-l::before {
|
||||
content: var(--tw-content);
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
.before\:border-t::before {
|
||||
content: var(--tw-content);
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.before\:transition-all::before {
|
||||
content: var(--tw-content);
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.after\:pointer-events-none::after {
|
||||
content: var(--tw-content);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.after\:ml-1::after {
|
||||
content: var(--tw-content);
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.after\:mt-\[6\.5px\]::after {
|
||||
content: var(--tw-content);
|
||||
margin-top: 6.5px;
|
||||
}
|
||||
|
||||
.after\:box-border::after {
|
||||
content: var(--tw-content);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.after\:block::after {
|
||||
content: var(--tw-content);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.after\:h-1::after {
|
||||
content: var(--tw-content);
|
||||
height: 0.25rem;
|
||||
}
|
||||
|
||||
.after\:h-1\.5::after {
|
||||
content: var(--tw-content);
|
||||
height: 0.375rem;
|
||||
}
|
||||
|
||||
.after\:w-2::after {
|
||||
content: var(--tw-content);
|
||||
width: 0.5rem;
|
||||
}
|
||||
|
||||
.after\:w-2\.5::after {
|
||||
content: var(--tw-content);
|
||||
width: 0.625rem;
|
||||
}
|
||||
|
||||
.after\:flex-grow::after {
|
||||
content: var(--tw-content);
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.after\:rounded-tr-md::after {
|
||||
content: var(--tw-content);
|
||||
border-top-right-radius: 0.375rem;
|
||||
}
|
||||
|
||||
.after\:border-r::after {
|
||||
content: var(--tw-content);
|
||||
border-right-width: 1px;
|
||||
}
|
||||
|
||||
.after\:border-t::after {
|
||||
content: var(--tw-content);
|
||||
border-top-width: 1px;
|
||||
}
|
||||
|
||||
.after\:transition-all::after {
|
||||
content: var(--tw-content);
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
|
||||
.placeholder-shown\:border:-moz-placeholder-shown {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.placeholder-shown\:border:placeholder-shown {
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.hover\:border-blue-500:hover {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(59 130 246 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.hover\:bg-blue-400:hover {
|
||||
--tw-bg-opacity: 1;
|
||||
background-color: rgb(96 165 250 / var(--tw-bg-opacity));
|
||||
}
|
||||
|
||||
.focus\:border-2:focus {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.focus\:border-gray-900:focus {
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(17 24 39 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.focus\:border-t-transparent:focus {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
.focus\:outline-0:focus {
|
||||
outline-width: 0px;
|
||||
}
|
||||
|
||||
.disabled\:resize-none:disabled {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.disabled\:border-0:disabled {
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:text-sm {
|
||||
font-size: 0.750rem;
|
||||
}
|
||||
|
||||
.peer:placeholder-shown ~ .peer-placeholder-shown\:text-sm {
|
||||
font-size: 0.750rem;
|
||||
}
|
||||
|
||||
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:leading-\[3\.75\] {
|
||||
line-height: 3.75;
|
||||
}
|
||||
|
||||
.peer:placeholder-shown ~ .peer-placeholder-shown\:leading-\[3\.75\] {
|
||||
line-height: 3.75;
|
||||
}
|
||||
|
||||
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:before\:border-transparent::before {
|
||||
content: var(--tw-content);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.peer:placeholder-shown ~ .peer-placeholder-shown\:before\:border-transparent::before {
|
||||
content: var(--tw-content);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.peer:-moz-placeholder-shown ~ .peer-placeholder-shown\:after\:border-transparent::after {
|
||||
content: var(--tw-content);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.peer:placeholder-shown ~ .peer-placeholder-shown\:after\:border-transparent::after {
|
||||
content: var(--tw-content);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:text-\[11px\] {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:leading-tight {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:text-gray-900 {
|
||||
--tw-text-opacity: 1;
|
||||
color: rgb(17 24 39 / var(--tw-text-opacity));
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:before\:border-l-2::before {
|
||||
content: var(--tw-content);
|
||||
border-left-width: 2px;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:before\:border-t-2::before {
|
||||
content: var(--tw-content);
|
||||
border-top-width: 2px;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:before\:\!border-gray-900::before {
|
||||
content: var(--tw-content);
|
||||
--tw-border-opacity: 1 !important;
|
||||
border-color: rgb(17 24 39 / var(--tw-border-opacity)) !important;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:before\:border-gray-900::before {
|
||||
content: var(--tw-content);
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(17 24 39 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:after\:border-r-2::after {
|
||||
content: var(--tw-content);
|
||||
border-right-width: 2px;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:after\:border-t-2::after {
|
||||
content: var(--tw-content);
|
||||
border-top-width: 2px;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:after\:\!border-gray-900::after {
|
||||
content: var(--tw-content);
|
||||
--tw-border-opacity: 1 !important;
|
||||
border-color: rgb(17 24 39 / var(--tw-border-opacity)) !important;
|
||||
}
|
||||
|
||||
.peer:focus ~ .peer-focus\:after\:border-gray-900::after {
|
||||
content: var(--tw-content);
|
||||
--tw-border-opacity: 1;
|
||||
border-color: rgb(17 24 39 / var(--tw-border-opacity));
|
||||
}
|
||||
|
||||
.peer:disabled ~ .peer-disabled\:text-transparent {
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.peer:disabled ~ .peer-disabled\:before\:border-transparent::before {
|
||||
content: var(--tw-content);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.peer:disabled ~ .peer-disabled\:after\:border-transparent::after {
|
||||
content: var(--tw-content);
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.md\:grid-cols-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue