From 1568e48eeae1fa4f0e97219060a8150a222a9fb1 Mon Sep 17 00:00:00 2001 From: realaravinth Date: Sun, 20 Mar 2022 21:48:11 +0530 Subject: [PATCH] feat: raw and single page views for gist files --- src/pages/gists/view.rs | 72 +++++++++++++++++++++-- src/pages/routes.rs | 30 ++++++++-- static/cache/css/main.css | 24 +++++++- templates/pages/auth/base.html | 2 +- templates/pages/gists/view/_filename.html | 8 ++- templates/pages/gists/view/_text.html | 10 +++- templates/pages/gists/view/index.html | 16 ++--- 7 files changed, 134 insertions(+), 28 deletions(-) diff --git a/src/pages/gists/view.rs b/src/pages/gists/view.rs index e0b083f..1297706 100644 --- a/src/pages/gists/view.rs +++ b/src/pages/gists/view.rs @@ -71,6 +71,69 @@ pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(post_comment); } +#[derive(Serialize, Debug, Clone, PartialEq)] +pub struct HTMLFileInfo { + pub f: FileInfo, + pub raw: String, + pub highlighted_link: String, +} + +impl HTMLFileInfo { + pub fn new(mut f: FileInfo, owner: &str, gist_public_id: &str) -> Self { + f.generate(); + let owner = owner.to_string(); + let gist = gist_public_id.into(); + let raw_component = GetFilePath { + username: owner, + gist, + file: f.filename, + }; + let raw = crate::V1_API_ROUTES.gist.get_file_route(&raw_component); + let highlighted_link = PAGES.gist.get_file_route(&raw_component); + f.filename = raw_component.file; + Self { + f, + raw, + highlighted_link, + } + } +} + +#[derive(Serialize, Debug, Clone, PartialEq)] +pub struct HTMLGistInfo { + pub files: Vec, + pub description: Option, + pub owner: String, + pub created: i64, + pub updated: i64, + pub visibility: GistVisibility, + pub id: String, +} + +impl From for HTMLGistInfo { + fn from(mut g: GistInfo) -> Self { + let mut files = Vec::with_capacity(g.files.len()); + g.files + .drain(..) + .for_each(|f| files.push(HTMLFileInfo::new(f, &g.owner, &g.id))); + Self { + files, + description: g.description, + owner: g.owner, + created: g.created, + updated: g.updated, + visibility: g.visibility, + id: g.id, + } + } +} + +impl GenerateHTML for HTMLFileInfo { + fn generate(&mut self) { + self.f.generate(); + } +} + #[derive(Clone)] pub struct ViewGist { ctx: RefCell, @@ -85,7 +148,7 @@ impl CtxError for ViewGist { #[derive(Debug, Default, Clone, Serialize)] pub struct PreviewPayload<'a> { - pub gist: Option<&'a GistInfo>, + pub gist: Option<&'a HTMLGistInfo>, pub comments: Option<&'a Vec>, } @@ -143,7 +206,7 @@ async fn view_util( ) -> PageResult { let username = id.identity(); - let map_err = |e: ServiceError, gist: Option<&GistInfo>| -> PageError { + let map_err = |e: ServiceError, gist: Option<&HTMLGistInfo>| -> PageError { PageError::new( ViewGist::new( username.as_deref(), @@ -168,12 +231,13 @@ async fn view_util( } } - let mut gist = data + let gist = data .gist_preview(db.as_ref(), &mut GistID::ID(&path.gist)) .await .map_err(|e| map_err(e, None))?; - gist.files.iter_mut().for_each(|file| file.generate()); + //gist.files.iter_mut().for_each(|file| file.generate()); + let gist: HTMLGistInfo = gist.into(); let comments = db.get_comments_on_gist(&path.gist).await.map_err(|e| { let e: ServiceError = e.into(); diff --git a/src/pages/routes.rs b/src/pages/routes.rs index f045df9..93b940e 100644 --- a/src/pages/routes.rs +++ b/src/pages/routes.rs @@ -17,7 +17,7 @@ use actix_auth_middleware::{Authentication, GetLoginRoute}; use serde::*; -pub use crate::api::v1::routes::PostCommentPath; +pub use crate::api::v1::routes::{GetFilePath, PostCommentPath}; /// constant [Pages](Pages) instance pub const PAGES: Pages = Pages::new(); @@ -87,20 +87,24 @@ pub struct Gists { pub view_gist: &'static str, /// post comment on gist pub post_comment: &'static str, + /// get file + pub get_file: &'static str, } impl Gists { /// create new instance of Gists route pub const fn new() -> Self { - let profile = "/{username}"; - let view_gist = "/{username}/{gist}"; - let post_comment = "/{username}/{gist}/comment"; + let profile = "/~{username}"; + let view_gist = "/~{username}/{gist}"; + let post_comment = "/~{username}/{gist}/comment"; + let get_file = "/~{username}/{gist}/contents/{file}"; let new = "/"; Self { profile, new, view_gist, post_comment, + get_file, } } @@ -122,6 +126,15 @@ impl Gists { .replace("{username}", &components.username) .replace("{gist}", &components.gist) } + + /// get file routes with placeholders replaced with values provided. + /// filename is auto-escaped using [urlencoding::encode] + pub fn get_file_route(&self, components: &GetFilePath) -> String { + self.get_file + .replace("{username}", &components.username) + .replace("{gist}", &components.gist) + .replace("{file}", &urlencoding::encode(&components.file)) + } } pub fn get_auth_middleware() -> Authentication { @@ -149,9 +162,11 @@ mod tests { fn gist_route_substitution_works() { const NAME: &str = "bob"; const GIST: &str = "foo"; + const FILE: &str = "README.md"; let get_profile = format!("/{NAME}"); let view_gist = format!("/{NAME}/{GIST}"); let post_comment = format!("/{NAME}/{GIST}/comment"); + let get_file = format!("/{NAME}/{GIST}/contents/{FILE}"); let profile_component = GistProfilePathComponent { username: NAME }; @@ -173,5 +188,12 @@ mod tests { post_comment, PAGES.gist.get_post_comment_route(&post_comment_path) ); + + let file_component = GetFilePath { + username: NAME.into(), + gist: GIST.into(), + file: FILE.into(), + }; + assert_eq!(get_file, PAGES.gist.get_file_route(&file_component)); } } diff --git a/static/cache/css/main.css b/static/cache/css/main.css index dc0f67b..3516875 100644 --- a/static/cache/css/main.css +++ b/static/cache/css/main.css @@ -119,12 +119,14 @@ main { display: flex; flex-direction: column; - /* align-items: center; - */ justify-content: space-evenly; } +.auth__main { + flex-direction: row; +} + .main { min-height: 80vh; align-items: center; @@ -340,10 +342,26 @@ pre { overflow-x: scroll; } -.gist__filename { +.gist__filename-container { padding: 8px; background: #eeee; margin-bottom: 10px; + display: flex; + justify-content: space-between; +} + +.gist__filename-name { + font-weight: 600; + color: #333; +} + +.gist__file-anchor { + color: rgb(0, 86, 179); + margin-right: 5px; +} + +.gist__filename-raw { + margin-left: 10px; } .gist__meta-container { diff --git a/templates/pages/auth/base.html b/templates/pages/auth/base.html index 1240522..4acc92f 100644 --- a/templates/pages/auth/base.html +++ b/templates/pages/auth/base.html @@ -3,7 +3,7 @@ {% block nav %} {% include "pub_nav" %} {% endblock %} {% block main %} -
+

GitPad

diff --git a/templates/pages/gists/view/_filename.html b/templates/pages/gists/view/_filename.html index 6098ba1..a77b3bb 100644 --- a/templates/pages/gists/view/_filename.html +++ b/templates/pages/gists/view/_filename.html @@ -1,3 +1,7 @@ -
- {{ payload_file.filename }} + diff --git a/templates/pages/gists/view/_text.html b/templates/pages/gists/view/_text.html index a80a1dc..dd5d970 100644 --- a/templates/pages/gists/view/_text.html +++ b/templates/pages/gists/view/_text.html @@ -1,3 +1,7 @@ -{% if "text" in payload_file.content.file %} - {{ payload_file.content.file.text }} -{% endif %} +
+ {% include "gist_filename" %} + {% if "text" in payload_file.f.content.file %} + {{ payload_file.f.content.file.text }} + {% endif %} +
+ diff --git a/templates/pages/gists/view/index.html b/templates/pages/gists/view/index.html index 6ca9de9..953a554 100644 --- a/templates/pages/gists/view/index.html +++ b/templates/pages/gists/view/index.html @@ -7,18 +7,12 @@ {% include "gist_meta" %}
{% for payload_file in payload.gist.files %} - {% if "file" in payload_file.content %} -
- {% include "gist_filename" %} - {% include "gist_textfile" %} -
- {% elif "dir" in payload_file.content %} - {% for payload_file in payload_file.content.dir %} - {% if "file" in payload_file.content %} -
- {% include "gist_filename" %} + {% if "file" in payload_file.f.content %} + {% include "gist_textfile" %} + {% elif "dir" in payload_file.f.content %} + {% for payload_file in payload_file.f.content.dir %} + {% if "file" in payload_file.f.content %} {% include "gist_textfile" %} -
{% endif %} {% endfor %} {% endif %}