mirror of https://github.com/realaravinth/gitpad
feat: raw and single page views for gist files
parent
13388326ef
commit
1568e48eea
|
@ -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<HTMLFileInfo>,
|
||||
pub description: Option<String>,
|
||||
pub owner: String,
|
||||
pub created: i64,
|
||||
pub updated: i64,
|
||||
pub visibility: GistVisibility,
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
impl From<GistInfo> 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<Context>,
|
||||
|
@ -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<GistComment>>,
|
||||
}
|
||||
|
||||
|
@ -143,7 +206,7 @@ async fn view_util(
|
|||
) -> PageResult<ViewGist, ViewGist> {
|
||||
let username = id.identity();
|
||||
|
||||
let map_err = |e: ServiceError, gist: Option<&GistInfo>| -> PageError<ViewGist> {
|
||||
let map_err = |e: ServiceError, gist: Option<&HTMLGistInfo>| -> PageError<ViewGist> {
|
||||
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();
|
||||
|
|
|
@ -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<Pages> {
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
{% block nav %} {% include "pub_nav" %} {% endblock %}
|
||||
{% block main %}
|
||||
<main>
|
||||
<main class="auth__main">
|
||||
<section class="main">
|
||||
<div class="title">
|
||||
<h1>GitPad</h1>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
<div class="gist__filename">
|
||||
<a href="">{{ payload_file.filename }}</a>
|
||||
<div class="gist__filename-container">
|
||||
<a class="gist__filename-name" href="#{{ payload_file.f.filename }}"><span class="gist__file-anchor">#</span>{{ payload_file.f.filename }}</a>
|
||||
<span>
|
||||
<a class="gist__filename-link" href="{{ payload_file.highlighted_link }}">Link</a>
|
||||
<a class="gist__filename-raw" href="{{ payload_file.raw }}">Raw</a>
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
{% if "text" in payload_file.content.file %}
|
||||
{{ payload_file.content.file.text }}
|
||||
{% endif %}
|
||||
<div id="{{ payload_file.f.filename }}" class="gist_file">
|
||||
{% include "gist_filename" %}
|
||||
{% if "text" in payload_file.f.content.file %}
|
||||
{{ payload_file.f.content.file.text }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -7,18 +7,12 @@
|
|||
{% include "gist_meta" %}
|
||||
<div class="gist__data-container">
|
||||
{% for payload_file in payload.gist.files %}
|
||||
{% if "file" in payload_file.content %}
|
||||
<div class="gist_file">
|
||||
{% include "gist_filename" %}
|
||||
{% include "gist_textfile" %}
|
||||
</div>
|
||||
{% elif "dir" in payload_file.content %}
|
||||
{% for payload_file in payload_file.content.dir %}
|
||||
{% if "file" in payload_file.content %}
|
||||
<div class="gist_file">
|
||||
{% 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" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
|
Loading…
Reference in New Issue