forked from realaravinth/libmedium
implement rendering on medium-formatted data
This commit is contained in:
parent
63bd10688c
commit
f0853a4a64
9 changed files with 333 additions and 68 deletions
112
Cargo.lock
generated
112
Cargo.lock
generated
|
@ -381,6 +381,19 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits 0.2.14",
|
||||||
|
"time 0.1.44",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "3.8.1"
|
version = "3.8.1"
|
||||||
|
@ -545,6 +558,18 @@ dependencies = [
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filetime"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "firestorm"
|
name = "firestorm"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
@ -764,6 +789,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "home"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -886,6 +920,12 @@ version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.24"
|
version = "0.1.24"
|
||||||
|
@ -943,6 +983,7 @@ dependencies = [
|
||||||
"actix-rt",
|
"actix-rt",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"actix-web-codegen 0.5.0-beta.4",
|
"actix-web-codegen 0.5.0-beta.4",
|
||||||
|
"chrono",
|
||||||
"config",
|
"config",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"graphql_client",
|
"graphql_client",
|
||||||
|
@ -951,6 +992,7 @@ dependencies = [
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
"sailfish",
|
||||||
"serde 1.0.130",
|
"serde 1.0.130",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"url",
|
"url",
|
||||||
|
@ -1086,6 +1128,16 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-integer"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"num-traits 0.2.14",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.1.43"
|
version = "0.1.43"
|
||||||
|
@ -1276,9 +1328,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.32"
|
version = "1.0.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
@ -1444,6 +1496,43 @@ version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sailfish"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "816920a08514d9741242b3efe70c16c350ed548bc4a5ba03426e56faf9d45f77"
|
||||||
|
dependencies = [
|
||||||
|
"itoap",
|
||||||
|
"ryu",
|
||||||
|
"sailfish-macros",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sailfish-compiler"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4276e7b848bde8e7813d534f014bc35ce5acd2b9e2b6b075727113fcf478ba63"
|
||||||
|
dependencies = [
|
||||||
|
"filetime",
|
||||||
|
"home",
|
||||||
|
"memchr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"yaml-rust",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sailfish-macros"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6bba2458ef07ae12c9aed2edb866c3db2f9c21cf19a2c3f2613b2982bc1a4a46"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"sailfish-compiler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
|
@ -1693,9 +1782,9 @@ checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.81"
|
version = "1.0.80"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
|
checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1737,6 +1826,17 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.2.27"
|
version = "0.2.27"
|
||||||
|
@ -1973,9 +2073,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.10.2+wasi-snapshot-preview1"
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
|
|
|
@ -31,7 +31,10 @@ lazy_static = "1.4"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
derive_more = "0.99"
|
derive_more = "0.99"
|
||||||
|
sailfish = "0.3.2"
|
||||||
|
|
||||||
num_cpus = "1.13"
|
num_cpus = "1.13"
|
||||||
reqwest = { version = "0.11.6", features = ["json"] }
|
reqwest = { version = "0.11.6", features = ["json"] }
|
||||||
graphql_client = { version = "0.10.0", features = ["reqwest"]}
|
graphql_client = { version = "0.10.0", features = ["reqwest"]}
|
||||||
|
|
||||||
|
chrono = "0.4.19"
|
||||||
|
|
1
sailfish.yml
Normal file
1
sailfish.yml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
delimiter: "."
|
153
src/proxy.rs
153
src/proxy.rs
|
@ -14,11 +14,13 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
use std::ops::{Bound, RangeBounds};
|
||||||
|
|
||||||
use actix_web::{web, HttpResponse, Responder};
|
use actix_web::{web, HttpResponse, Responder};
|
||||||
use graphql_client::{reqwest::post_graphql, GraphQLQuery};
|
use graphql_client::{reqwest::post_graphql, GraphQLQuery};
|
||||||
use serde::{Deserialize, Serialize};
|
use sailfish::TemplateOnce;
|
||||||
|
|
||||||
use crate::SETTINGS;
|
use crate::AppData;
|
||||||
|
|
||||||
pub mod routes {
|
pub mod routes {
|
||||||
pub struct Proxy {
|
pub struct Proxy {
|
||||||
|
@ -41,6 +43,58 @@ pub mod routes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// credits @carlomilanesi:
|
||||||
|
// https://users.rust-lang.org/t/how-to-get-a-substring-of-a-string/1351/11
|
||||||
|
trait StringUtils {
|
||||||
|
fn substring(&self, start: usize, len: usize) -> &str;
|
||||||
|
fn slice(&self, range: impl RangeBounds<usize>) -> &str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringUtils for str {
|
||||||
|
fn substring(&self, start: usize, len: usize) -> &str {
|
||||||
|
let mut char_pos = 0;
|
||||||
|
let mut byte_start = 0;
|
||||||
|
let mut it = self.chars();
|
||||||
|
loop {
|
||||||
|
if char_pos == start {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(c) = it.next() {
|
||||||
|
char_pos += 1;
|
||||||
|
byte_start += c.len_utf8();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char_pos = 0;
|
||||||
|
let mut byte_end = byte_start;
|
||||||
|
loop {
|
||||||
|
if char_pos == len {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(c) = it.next() {
|
||||||
|
char_pos += 1;
|
||||||
|
byte_end += c.len_utf8();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&self[byte_start..byte_end]
|
||||||
|
}
|
||||||
|
fn slice(&self, range: impl RangeBounds<usize>) -> &str {
|
||||||
|
let start = match range.start_bound() {
|
||||||
|
Bound::Included(bound) | Bound::Excluded(bound) => *bound,
|
||||||
|
Bound::Unbounded => 0,
|
||||||
|
};
|
||||||
|
let len = match range.end_bound() {
|
||||||
|
Bound::Included(bound) => *bound + 1,
|
||||||
|
Bound::Excluded(bound) => *bound,
|
||||||
|
Bound::Unbounded => self.len(),
|
||||||
|
} - start;
|
||||||
|
self.substring(start, len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(GraphQLQuery)]
|
#[derive(GraphQLQuery)]
|
||||||
#[graphql(
|
#[graphql(
|
||||||
schema_path = "schemas/schema.graphql",
|
schema_path = "schemas/schema.graphql",
|
||||||
|
@ -49,44 +103,39 @@ pub mod routes {
|
||||||
)]
|
)]
|
||||||
struct GetPost;
|
struct GetPost;
|
||||||
|
|
||||||
|
#[derive(TemplateOnce)]
|
||||||
|
#[template(path = "index.html")]
|
||||||
|
pub struct Post {
|
||||||
|
pub data: get_post::GetPostPost,
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[my_codegen::get(path = "crate::V1_API_ROUTES.proxy.page")]
|
#[my_codegen::get(path = "crate::V1_API_ROUTES.proxy.page")]
|
||||||
async fn page(path: web::Path<(String, String)>) -> impl Responder {
|
async fn page(path: web::Path<(String, String)>, data: AppData) -> impl Responder {
|
||||||
let post_id = path.1.split("-").last();
|
let post_id = path.1.split("-").last();
|
||||||
if post_id.is_none() {
|
if post_id.is_none() {
|
||||||
return HttpResponse::BadRequest();
|
return HttpResponse::BadRequest().finish();
|
||||||
}
|
}
|
||||||
let id = post_id.unwrap().to_string();
|
let id = post_id.unwrap().to_string();
|
||||||
|
|
||||||
let vars = get_post::Variables { id };
|
let vars = get_post::Variables { id: id.clone() };
|
||||||
|
|
||||||
const URL: &str = "https://medium.com/_/graphql";
|
const URL: &str = "https://medium.com/_/graphql";
|
||||||
|
|
||||||
let client = reqwest::Client::new();
|
let res = post_graphql::<GetPost, _>(&data.client, URL, vars)
|
||||||
let res = post_graphql::<GetPost, _>(&client, URL, vars)
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("{:?}", res);
|
|
||||||
|
|
||||||
let response_data: get_post::ResponseData = res.data.expect("missing response data");
|
let response_data: get_post::ResponseData = res.data.expect("missing response data");
|
||||||
for p in response_data
|
|
||||||
.post
|
|
||||||
.unwrap()
|
|
||||||
.content
|
|
||||||
.unwrap()
|
|
||||||
.body_model
|
|
||||||
.unwrap()
|
|
||||||
.paragraphs
|
|
||||||
.unwrap()
|
|
||||||
.iter()
|
|
||||||
{
|
|
||||||
println!("paragraph content: {:?}", p.as_ref().unwrap());
|
|
||||||
}
|
|
||||||
// .bodyModel
|
|
||||||
// .paragraphs
|
|
||||||
// .iter();
|
|
||||||
// println!("{:?}", response_data);
|
|
||||||
|
|
||||||
|
let page = Post {
|
||||||
|
id,
|
||||||
|
data: response_data.post.unwrap(),
|
||||||
|
}
|
||||||
|
.render_once()
|
||||||
|
.unwrap();
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
|
.content_type("text/html; charset=utf-8")
|
||||||
|
.body(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||||
|
@ -97,42 +146,22 @@ pub fn services(cfg: &mut web::ServiceConfig) {
|
||||||
mod tests {
|
mod tests {
|
||||||
use actix_web::{http::StatusCode, test, App};
|
use actix_web::{http::StatusCode, test, App};
|
||||||
|
|
||||||
use crate::services;
|
use crate::{services, Data};
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
use super::*;
|
#[actix_rt::test]
|
||||||
|
async fn deploy_update_works() {
|
||||||
|
let data = Data::new();
|
||||||
|
let app = test::init_service(App::new().app_data(data.clone()).configure(services)).await;
|
||||||
|
let urls = vec![
|
||||||
|
"/@ftrain/big-data-small-effort-b62607a43a8c",
|
||||||
|
"/geekculture/rest-api-best-practices-decouple-long-running-tasks-from-http-request-processing-9fab2921ace8",
|
||||||
|
"/illumination/5-bugs-that-turned-into-features-e9a0e972a4e7",
|
||||||
|
];
|
||||||
|
|
||||||
// #[actix_rt::test]
|
for uri in urls.iter() {
|
||||||
// async fn deploy_update_works() {
|
let resp =
|
||||||
// let app = test::init_service(App::new().configure(services)).await;
|
test::call_service(&app, test::TestRequest::get().uri(uri).to_request()).await;
|
||||||
//
|
assert_eq!(resp.status(), StatusCode::OK);
|
||||||
// let page = page.unwrap();
|
}
|
||||||
//
|
}
|
||||||
// let mut payload = ProxyEvent {
|
|
||||||
// secret: page.secret.clone(),
|
|
||||||
// branch: page.branch.clone(),
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// let resp = test::call_service(
|
|
||||||
// &app,
|
|
||||||
// test::TestRequest::post()
|
|
||||||
// .uri(V1_API_ROUTES.deploy.update)
|
|
||||||
// .set_json(&payload)
|
|
||||||
// .to_request(),
|
|
||||||
// )
|
|
||||||
// .await;
|
|
||||||
// assert_eq!(resp.status(), StatusCode::OK);
|
|
||||||
//
|
|
||||||
// payload.secret = page.branch.clone();
|
|
||||||
//
|
|
||||||
// let resp = test::call_service(
|
|
||||||
// &app,
|
|
||||||
// test::TestRequest::post()
|
|
||||||
// .uri(V1_API_ROUTES.deploy.update)
|
|
||||||
// .set_json(&payload)
|
|
||||||
// .to_request(),
|
|
||||||
// )
|
|
||||||
// .await;
|
|
||||||
// assert_eq!(resp.status(), StatusCode::NOT_FOUND);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
9
templates/img.html
Normal file
9
templates/img.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<. let metadata = p.metadata.as_ref().unwrap(); .>
|
||||||
|
<!-- TODO deal with layouts
|
||||||
|
height="<.= metadata.original_height.>"
|
||||||
|
width="<.= metadata.original_width.>"
|
||||||
|
-->
|
||||||
|
<img
|
||||||
|
src="https://miro.medium.com/<.= metadata.id .>"
|
||||||
|
alt="<.= p.text .>"
|
||||||
|
/>
|
37
templates/index.html
Normal file
37
templates/index.html
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title><.= data.title .></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="container">
|
||||||
|
<h1><.= data.title .></h1>
|
||||||
|
<. use chrono::{TimeZone, Utc}; .>
|
||||||
|
<. let dt = Utc.timestamp_millis(data.created_at); .>
|
||||||
|
<p class="meta">
|
||||||
|
<a href="https://medium.com/u/<.= data.creator.id .>" rel="noreferrer">
|
||||||
|
<.= data.creator.name .></a
|
||||||
|
>
|
||||||
|
on <.= dt.format("%b %e, %Y").to_string() .>
|
||||||
|
</p>
|
||||||
|
<article>
|
||||||
|
<. let paragraphs = data.content.body_model.paragraphs; .>
|
||||||
|
<. for (pindex, p) in paragraphs.iter().enumerate() {.>
|
||||||
|
<. if pindex == 1 && p.type_ == "H3" {.>
|
||||||
|
<. continue; .>
|
||||||
|
<.}.>
|
||||||
|
<. if p.type_ == "IMG" {.>
|
||||||
|
<. include!("./img.html"); .>
|
||||||
|
<.} else if p.type_ == "P" {.>
|
||||||
|
<. include!("./p.html"); .>
|
||||||
|
<.}.>
|
||||||
|
<.}.>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
<. include!("./main.css"); .>
|
||||||
|
</style>
|
||||||
|
</html>
|
27
templates/main.css
Normal file
27
templates/main.css
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
width: 60%;
|
||||||
|
margin: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
margin: auto;
|
||||||
|
max-width: 80%;
|
||||||
|
/*! display: block; */
|
||||||
|
}
|
15
templates/matcher.rs
Normal file
15
templates/matcher.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
match p.type_.as_str() {
|
||||||
|
"IMG" => {
|
||||||
|
include!("./img.html");
|
||||||
|
},
|
||||||
|
_ => unimplemented!(),
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//<. match p.type_ { .>
|
||||||
|
// <. "IMG" => { .>
|
||||||
|
// <. include!("./img.html") .>
|
||||||
|
// <. }, .>
|
||||||
|
// <. _ => log::error("Unable to find paragraph render class. Post ID: {}. Paragraph item {:?}", id, p),
|
||||||
|
// <. } .>
|
||||||
|
//
|
44
templates/p.html
Normal file
44
templates/p.html
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<p>
|
||||||
|
<. if p.markups.is_empty() {.>
|
||||||
|
<.= p.text .>
|
||||||
|
<.} else {.>
|
||||||
|
<. let mut cur: usize = 0; .>
|
||||||
|
<. for markup in &p.markups {.>
|
||||||
|
<.= &p.text.substring(cur, (markup.start -1) as usize) .>
|
||||||
|
<. cur = (markup.end + 1) as usize; .>
|
||||||
|
<. let text = &p.text.substring(markup.start as usize, markup.end as usize); .>
|
||||||
|
<. if markup.type_ == "A" {.>
|
||||||
|
<. if let Some(anchor_type) = &markup.anchor_type {.>
|
||||||
|
<. if anchor_type == "LINK" {.>
|
||||||
|
<a rel="noreferrer" href="<.= markup.href.as_ref().unwrap() .>"><.= text .></a>
|
||||||
|
<.} else if anchor_type == "USER" {.>
|
||||||
|
<a
|
||||||
|
rel="noreferrer"
|
||||||
|
href="https://medium.com/u/<.= markup.user_id.as_ref().unwrap() .>"
|
||||||
|
>
|
||||||
|
<.= text .>
|
||||||
|
</a>
|
||||||
|
<.} else {.>
|
||||||
|
<. log::error!("unknown markup.anchor_type: {:?} post id {}", anchor_type, id); .>
|
||||||
|
<span><.= text .></span>
|
||||||
|
<.}.>
|
||||||
|
<.}.>
|
||||||
|
<.} else if markup.type_ == "EM" {.>
|
||||||
|
<em><.= text .></em>
|
||||||
|
<.} else if markup.type_ == "STRONG" {.>
|
||||||
|
<strong><.= text .></strong>
|
||||||
|
<.} else if markup.type_ == "CODE" {.>
|
||||||
|
<code><.= text .></code>
|
||||||
|
<.} else {.>
|
||||||
|
<. log::error!("unknown markup.type_: {:?} post id {}", markup.type_, id); .>
|
||||||
|
<span><.= text .></span>
|
||||||
|
<.}.>
|
||||||
|
|
||||||
|
<. if cur < p.text.len() {.>
|
||||||
|
<.= p.text.slice(cur..) .>
|
||||||
|
<.}.>
|
||||||
|
<.}.>
|
||||||
|
|
||||||
|
<.}.>
|
||||||
|
</p>
|
||||||
|
<!-- markup.type_ = [ "CODE", "A", "EM", "STRONG" -->
|
Loading…
Reference in a new issue