This commit is contained in:
@@ -145,7 +145,7 @@ fn main() {
|
|||||||
|
|
||||||
let new_picture = NewPicture {
|
let new_picture = NewPicture {
|
||||||
filepath: filepath.clone(),
|
filepath: filepath.clone(),
|
||||||
created_at: created_at.clone(),
|
created_at,
|
||||||
focal_length: pe.focal_length.clone(),
|
focal_length: pe.focal_length.clone(),
|
||||||
shutter_speed: pe.shutter_speed.clone(),
|
shutter_speed: pe.shutter_speed.clone(),
|
||||||
width: pe.width,
|
width: pe.width,
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub fn establish_connection() -> PgConnection {
|
|||||||
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
|
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_picture<'a>(conn: &PgConnection, new_picture: NewPicture) -> usize {
|
pub fn create_picture(conn: &PgConnection, new_picture: NewPicture) -> usize {
|
||||||
use schema::pictures;
|
use schema::pictures;
|
||||||
|
|
||||||
diesel::insert_into(pictures::table)
|
diesel::insert_into(pictures::table)
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ use common::OutputPicture;
|
|||||||
|
|
||||||
type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
|
type DbPool = r2d2::Pool<ConnectionManager<PgConnection>>;
|
||||||
|
|
||||||
// type DbError = Box<dyn std::error::Error + Send + Sync>;
|
|
||||||
|
|
||||||
#[get("/api/pictures/")]
|
#[get("/api/pictures/")]
|
||||||
async fn get_pictures(pool: web::Data<DbPool>) -> Result<impl Responder> {
|
async fn get_pictures(pool: web::Data<DbPool>) -> Result<impl Responder> {
|
||||||
let conn = pool.get().unwrap();
|
let conn = pool.get().unwrap();
|
||||||
@@ -91,10 +89,8 @@ async fn main() -> std::io::Result<()> {
|
|||||||
let port = 8081;
|
let port = 8081;
|
||||||
log::info!("starting HTTP server at http://{}:{}", host, port);
|
log::info!("starting HTTP server at http://{}:{}", host, port);
|
||||||
|
|
||||||
// Start HTTP server
|
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
App::new()
|
App::new()
|
||||||
// set up DB pool to be used with web::Data<Pool> extractor
|
|
||||||
.app_data(web::Data::new(pool.clone()))
|
.app_data(web::Data::new(pool.clone()))
|
||||||
.wrap(middleware::Logger::default())
|
.wrap(middleware::Logger::default())
|
||||||
.service(get_pictures)
|
.service(get_pictures)
|
||||||
@@ -106,9 +102,6 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.static_resources_location("./dist")
|
.static_resources_location("./dist")
|
||||||
.finish(),
|
.finish(),
|
||||||
)
|
)
|
||||||
// .service(fs::Files::new("/", STATIC_FILES_PATH).index_file("index.html"))
|
|
||||||
// .service(get_user)
|
|
||||||
// .service(add_user)
|
|
||||||
})
|
})
|
||||||
.bind((host, port))?
|
.bind((host, port))?
|
||||||
.run()
|
.run()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct OutputPicture {
|
pub struct OutputPicture {
|
||||||
pub thumbnail: Option<String>,
|
pub thumbnail: Option<String>,
|
||||||
pub width: u32,
|
pub width: u32,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<link data-trunk rel="copy-file" href="src/yew.svg"/>
|
<link data-trunk rel="copy-file" href="src/yew.svg"/>
|
||||||
<base data-trunk-public-url/>
|
<base data-trunk-public-url/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="has-navbar-fixed-top">
|
||||||
<link data-trunk rel="rust" href="Cargo.toml" data-wasm-opt="z" data-bin="frontend" data-cargo-features="demo-abc,demo-xyz"/>
|
<link data-trunk rel="rust" href="Cargo.toml" data-wasm-opt="z" data-bin="frontend" data-cargo-features="demo-abc,demo-xyz"/>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
use crate::gallery::Picture;
|
use crate::gallery::Picture;
|
||||||
use common::OutputPicture;
|
use common::OutputPicture;
|
||||||
use pathfinding::prelude::dijkstra;
|
|
||||||
use weblog::console_log;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
|
|
||||||
use yew::{function_component, html};
|
use yew::{function_component, html};
|
||||||
|
|
||||||
use super::layout::*;
|
use super::layout::{compute_row_layout, Rect};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Properties, PartialEq)]
|
#[derive(Clone, Debug, Properties, PartialEq)]
|
||||||
pub struct GridProps {
|
pub struct GridProps {
|
||||||
@@ -20,19 +18,31 @@ pub struct GridProps {
|
|||||||
pub fn grid(props: &GridProps) -> Html {
|
pub fn grid(props: &GridProps) -> Html {
|
||||||
let target_height = 300;
|
let target_height = 300;
|
||||||
let container_width = if props.width == 0 { 0 } else { props.width - 4 };
|
let container_width = if props.width == 0 { 0 } else { props.width - 4 };
|
||||||
let limit_node_search = find_ideal_node_search(target_height, container_width);
|
|
||||||
let margin = 2;
|
let margin = 2;
|
||||||
let dimensions = compute_row_layout(
|
let dimensions = compute_row_layout(
|
||||||
container_width,
|
container_width,
|
||||||
limit_node_search,
|
|
||||||
target_height,
|
target_height,
|
||||||
margin,
|
margin,
|
||||||
&props.pictures,
|
&props
|
||||||
|
.pictures
|
||||||
|
.iter()
|
||||||
|
.map(|p| Rect {
|
||||||
|
width: p.width,
|
||||||
|
height: p.height,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
);
|
);
|
||||||
let dimensions = if let Some(d) = dimensions {
|
let dimensions = if let Some(d) = dimensions {
|
||||||
d
|
d
|
||||||
} else {
|
} else {
|
||||||
props.pictures.iter().map(|p| (p.width, p.height)).collect()
|
props
|
||||||
|
.pictures
|
||||||
|
.iter()
|
||||||
|
.map(|p| Rect {
|
||||||
|
width: p.width,
|
||||||
|
height: p.height,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
};
|
};
|
||||||
html! {
|
html! {
|
||||||
<div style={
|
<div style={
|
||||||
@@ -42,7 +52,7 @@ pub fn grid(props: &GridProps) -> Html {
|
|||||||
"flex-direction: row;",
|
"flex-direction: row;",
|
||||||
)}>
|
)}>
|
||||||
{ props.pictures.iter().zip(dimensions).map(|(p, d)|
|
{ props.pictures.iter().zip(dimensions).map(|(p, d)|
|
||||||
html!{<Picture margin={margin} picture={p.clone()} width={d.0} height={d.1} />}
|
html!{<Picture margin={margin} picture={p.clone()} width={d.width} height={d.height} />}
|
||||||
).collect::<Html>()}
|
).collect::<Html>()}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
use common::OutputPicture;
|
|
||||||
use pathfinding::prelude::dijkstra;
|
use pathfinding::prelude::dijkstra;
|
||||||
use weblog::console_log;
|
|
||||||
|
|
||||||
pub fn get_common_height(row: &[OutputPicture], container_width: u32, margin: u32) -> f32 {
|
pub struct Rect {
|
||||||
|
pub width: u32,
|
||||||
|
pub height: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_common_height(row: &[Rect], container_width: u32, margin: u32) -> f32 {
|
||||||
let row_width: u32 = container_width - row.len() as u32 * (margin * 2);
|
let row_width: u32 = container_width - row.len() as u32 * (margin * 2);
|
||||||
let total_aspect_ratio: f32 = row
|
let total_aspect_ratio: f32 = row
|
||||||
.iter()
|
.iter()
|
||||||
@@ -12,7 +15,7 @@ pub fn get_common_height(row: &[OutputPicture], container_width: u32, margin: u3
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn cost(
|
pub fn cost(
|
||||||
photos: &[OutputPicture],
|
photos: &[Rect],
|
||||||
i: usize,
|
i: usize,
|
||||||
j: usize,
|
j: usize,
|
||||||
width: u32,
|
width: u32,
|
||||||
@@ -26,14 +29,14 @@ pub fn cost(
|
|||||||
pub fn make_successors(
|
pub fn make_successors(
|
||||||
target_height: u32,
|
target_height: u32,
|
||||||
container_width: u32,
|
container_width: u32,
|
||||||
photos: &Vec<OutputPicture>,
|
photos: &Vec<Rect>,
|
||||||
limit_node_search: usize,
|
node_search_limit: usize,
|
||||||
margin: u32,
|
margin: u32,
|
||||||
) -> Vec<Vec<(usize, u32)>> {
|
) -> Vec<Vec<(usize, u32)>> {
|
||||||
let mut results = vec![Vec::new(); photos.len()];
|
let mut results = vec![Vec::new(); photos.len()];
|
||||||
(0..photos.len()).for_each(|start| {
|
(0..photos.len()).for_each(|start| {
|
||||||
for j in start + 1..photos.len() + 1 {
|
for j in start + 1..photos.len() + 1 {
|
||||||
if j - start > limit_node_search {
|
if j - start > node_search_limit {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
results[start].push((
|
results[start].push((
|
||||||
@@ -45,29 +48,28 @@ pub fn make_successors(
|
|||||||
results
|
results
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_ideal_node_search(target_row_height: u32, container_width: u32) -> usize {
|
pub fn calc_node_search_limit(target_row_height: u32, container_width: u32) -> usize {
|
||||||
let row_aspect_ratio = container_width as f32 / target_row_height as f32;
|
let row_aspect_ratio = container_width as f32 / target_row_height as f32;
|
||||||
(row_aspect_ratio / 1.5) as usize + 8
|
(row_aspect_ratio / 1.5) as usize + 8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_row_layout(
|
pub fn compute_row_layout(
|
||||||
container_width: u32,
|
container_width: u32,
|
||||||
limit_node_search: usize,
|
|
||||||
target_height: u32,
|
target_height: u32,
|
||||||
margin: u32,
|
margin: u32,
|
||||||
photos: &Vec<OutputPicture>,
|
photos: &Vec<Rect>,
|
||||||
) -> Option<Vec<(u32, u32)>> {
|
) -> Option<Vec<Rect>> {
|
||||||
console_log!("compute row layout for width: {}", container_width);
|
|
||||||
|
|
||||||
if photos.is_empty() {
|
if photos.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let node_search_limit = calc_node_search_limit(target_height, container_width);
|
||||||
|
|
||||||
let successors = make_successors(
|
let successors = make_successors(
|
||||||
target_height,
|
target_height,
|
||||||
container_width,
|
container_width,
|
||||||
photos,
|
photos,
|
||||||
limit_node_search,
|
node_search_limit,
|
||||||
margin,
|
margin,
|
||||||
);
|
);
|
||||||
let path = dijkstra(&0, |p| successors[*p].clone(), |p| *p == photos.len());
|
let path = dijkstra(&0, |p| successors[*p].clone(), |p| *p == photos.len());
|
||||||
@@ -76,13 +78,16 @@ pub fn compute_row_layout(
|
|||||||
} else {
|
} else {
|
||||||
(Vec::new(), 0)
|
(Vec::new(), 0)
|
||||||
};
|
};
|
||||||
let mut dimensions: Vec<(u32, u32)> = Vec::with_capacity(photos.len());
|
let mut dimensions: Vec<Rect> = Vec::with_capacity(photos.len());
|
||||||
for i in 1..path.len() {
|
for i in 1..path.len() {
|
||||||
let row = &photos[path[i - 1]..path[i]];
|
let row = &photos[path[i - 1]..path[i]];
|
||||||
let height = get_common_height(row, container_width, margin) as u32;
|
let height = get_common_height(row, container_width, margin) as u32;
|
||||||
(path[i - 1]..path[i]).for_each(|j| {
|
(path[i - 1]..path[i]).for_each(|j| {
|
||||||
let ratio = photos[j].width as f32 / photos[j].height as f32;
|
let ratio = photos[j].width as f32 / photos[j].height as f32;
|
||||||
dimensions.push(((height as f32 * ratio) as u32, height));
|
dimensions.push(Rect {
|
||||||
|
width: (height as f32 * ratio) as u32,
|
||||||
|
height,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Some(dimensions)
|
Some(dimensions)
|
||||||
|
|||||||
@@ -3,18 +3,18 @@
|
|||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||||
|
|
||||||
mod gallery;
|
|
||||||
|
|
||||||
use common::OutputPicture;
|
|
||||||
use console_error_panic_hook::set_once as set_panic_hook;
|
use console_error_panic_hook::set_once as set_panic_hook;
|
||||||
use gloo_net::http::Request;
|
use gloo_net::http::Request;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use yew_hooks::prelude::*;
|
use yew_hooks::prelude::*;
|
||||||
|
// use weblog::console_log;
|
||||||
|
|
||||||
use ybc::NavbarFixed::Top;
|
use ybc::NavbarFixed::Top;
|
||||||
use ybc::TileCtx::{Ancestor, Child, Parent};
|
use ybc::TileCtx::{Ancestor, Child, Parent};
|
||||||
use ybc::TileSize::*;
|
use ybc::TileSize::*;
|
||||||
|
|
||||||
|
mod gallery;
|
||||||
|
use common::OutputPicture;
|
||||||
use gallery::Grid;
|
use gallery::Grid;
|
||||||
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
@@ -47,14 +47,22 @@ fn app() -> Html {
|
|||||||
}
|
}
|
||||||
let navbrand = html! {
|
let navbrand = html! {
|
||||||
<ybc::NavbarItem>
|
<ybc::NavbarItem>
|
||||||
<ybc::Title classes={classes!("has-text-white")} size={ybc::HeaderSize::Is4}>{"Photos"}</ybc::Title>
|
<ybc::Title
|
||||||
|
classes={classes!("has-text-white")}
|
||||||
|
size={ybc::HeaderSize::Is4}>
|
||||||
|
{"Photos"}
|
||||||
|
</ybc::Title>
|
||||||
</ybc::NavbarItem>
|
</ybc::NavbarItem>
|
||||||
};
|
};
|
||||||
let navstart = html! {};
|
let navstart = html! {};
|
||||||
let navend = html! {
|
let navend = html! {
|
||||||
<>
|
<>
|
||||||
<ybc::NavbarItem>
|
<ybc::NavbarItem>
|
||||||
<ybc::ButtonAnchor classes={classes!("is-black", "is-outlined")} rel={String::from("noopener noreferrer")} target={String::from("_blank")} href="https://github.com/thedodd/trunk">
|
<ybc::ButtonAnchor
|
||||||
|
classes={classes!("is-outlined")}
|
||||||
|
rel={String::from("noopener noreferrer")}
|
||||||
|
target={String::from("_blank")}
|
||||||
|
href="">
|
||||||
{"Photos"}
|
{"Photos"}
|
||||||
</ybc::ButtonAnchor>
|
</ybc::ButtonAnchor>
|
||||||
</ybc::NavbarItem>
|
</ybc::NavbarItem>
|
||||||
@@ -71,12 +79,18 @@ fn app() -> Html {
|
|||||||
{navstart}
|
{navstart}
|
||||||
{navend}
|
{navend}
|
||||||
/>
|
/>
|
||||||
<ybc::Container fluid=true>
|
<ybc::Container fluid=true classes={classes!("is-centered")}>
|
||||||
<ybc::Tile ctx={Ancestor}>
|
<ybc::Tile ctx={Ancestor}>
|
||||||
<ybc::Tile ctx={Parent} vertical=true size={Twelve}>
|
<ybc::Tile ctx={Parent} vertical=true size={Twelve}>
|
||||||
<ybc::Tile ctx={Child} classes={classes!("box")}>
|
<ybc::Tile ctx={Child} classes={classes!("box")}>
|
||||||
<div ref={node} style={"position: 'relative'"} >
|
<div ref={node} style={
|
||||||
<Grid pictures={(*pictures).clone()} width={size.0} />
|
concat!(
|
||||||
|
"position: 'relative';",
|
||||||
|
)}>
|
||||||
|
<Grid
|
||||||
|
pictures={(*pictures).clone()}
|
||||||
|
width={size.0}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</ybc::Tile>
|
</ybc::Tile>
|
||||||
</ybc::Tile>
|
</ybc::Tile>
|
||||||
@@ -95,15 +109,5 @@ fn main() {
|
|||||||
set_panic_hook();
|
set_panic_hook();
|
||||||
snippetTest();
|
snippetTest();
|
||||||
|
|
||||||
// Show off some feature flag enabling patterns.
|
|
||||||
#[cfg(feature = "demo-abc")]
|
|
||||||
{
|
|
||||||
// ConsoleService::log("feature `demo-abc` enabled");
|
|
||||||
}
|
|
||||||
#[cfg(feature = "demo-xyz")]
|
|
||||||
{
|
|
||||||
// ConsoleService::log("feature `demo-xyz` enabled");
|
|
||||||
}
|
|
||||||
|
|
||||||
yew::start_app::<App>();
|
yew::start_app::<App>();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user