Compare commits
No commits in common. "main" and "add-empty-state" have entirely different histories.
main
...
add-empty-
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1 @@
|
||||
/target
|
||||
|
||||
.DS_Store
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
database_path = ""
|
||||
locale = "fr"
|
||||
base_url = ""
|
||||
|
||||
[listener]
|
||||
port = 8000
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
@ -1,13 +1,12 @@
|
||||
_version: 1
|
||||
name: "BookForge"
|
||||
|
||||
common:
|
||||
download: Download
|
||||
create: Create
|
||||
edit: Edit
|
||||
delete: Delete
|
||||
next: Next
|
||||
previous: Previous
|
||||
previous: Prev
|
||||
actions: Actions
|
||||
search: Search
|
||||
reset: Reset
|
||||
@ -16,77 +15,54 @@ common:
|
||||
close: Close
|
||||
confirmation: Confirmation
|
||||
are_you_sure: Are you sure?
|
||||
|
||||
nav:
|
||||
toggle: Toggle navigation
|
||||
books: Books
|
||||
users: Users
|
||||
|
||||
theme:
|
||||
light: Light
|
||||
dark: Dark
|
||||
|
||||
user:
|
||||
attributes:
|
||||
name: Name
|
||||
owner_books: Owned books
|
||||
owner_books: Owner books
|
||||
borrowed_books: Borrowed books
|
||||
|
||||
index:
|
||||
title_tag: Users list | BookForge
|
||||
title: All Users
|
||||
button: Add a user
|
||||
|
||||
button: Add User
|
||||
edit:
|
||||
title_tag: Edit user | BookForge
|
||||
title: Edit
|
||||
button: Edit user
|
||||
|
||||
new:
|
||||
title_tag: New user | BookForge
|
||||
title: New user
|
||||
button: Create user
|
||||
|
||||
title: New User
|
||||
button: Create User
|
||||
book:
|
||||
attributes:
|
||||
title: Title
|
||||
authors: Author(s)
|
||||
description: Description
|
||||
owner: Owner
|
||||
current_holder: Current holder
|
||||
current_holder: Current Holder
|
||||
comment: Comment
|
||||
|
||||
index:
|
||||
title_tag: Books list | BookForge
|
||||
title: All Books
|
||||
|
||||
new:
|
||||
title_tag: New book | BookForge
|
||||
title: New Book
|
||||
button: Create book
|
||||
button: Create Book
|
||||
button_short: Add book
|
||||
|
||||
edit:
|
||||
title_tag: Edit book | BookForge
|
||||
title: Edit book
|
||||
button: Edit book
|
||||
|
||||
title: Edit Book
|
||||
button: Edit Book
|
||||
show:
|
||||
title_tag: Details | BookForge
|
||||
book_details: Book details
|
||||
user_details: User details
|
||||
more_informations: More information
|
||||
|
||||
book_details: Book Details
|
||||
user_details: User Details
|
||||
more_informations: More Informations
|
||||
footer:
|
||||
message: Made with love & Fuck fascists!
|
||||
|
||||
message: Made with Love & Fuck a Fascist!
|
||||
error:
|
||||
error_404:
|
||||
title_tag: Error 404 | BookForge
|
||||
title: Oops! This page does not exist
|
||||
title: Oops ! This page does not exist
|
||||
subtitle: 404 NOT FOUND
|
||||
button: Back to home
|
||||
|
||||
generic:
|
||||
title_tag: Error | BookForge
|
||||
title: Oops! An error occurred
|
||||
|
||||
@ -28,17 +28,14 @@ user:
|
||||
owner_books: Livres possédés
|
||||
borrowed_books: Livres empruntés
|
||||
index:
|
||||
title_tag: Liste des utilisateur.ice.s | BookForge
|
||||
title: Tous les utilisateur.ice.s
|
||||
button: Ajouter un.e utilisateur.ice
|
||||
title: Tous les utilisateurs
|
||||
button: Ajouter un utilisateur
|
||||
edit:
|
||||
title_tag: Modifier l'utilisateur.ice | BookForge
|
||||
title: Modifier
|
||||
button: Modifier l'utilisateur.ice
|
||||
button: Modifier l'utilisateur
|
||||
new:
|
||||
title_tag: Nouvel utilisateur.ice | BookForge
|
||||
title: Nouvel utilisateur.ice
|
||||
button: Créer l'utilisateur.ice
|
||||
title: Nouvel utilisateur
|
||||
button: Créer l'utilisateur
|
||||
book:
|
||||
attributes:
|
||||
title: Titre
|
||||
@ -48,30 +45,24 @@ book:
|
||||
current_holder: Détenteur.ice actuel.le
|
||||
comment: Commentaire
|
||||
index:
|
||||
title_tag: Liste des livres | BookForge
|
||||
title: Tous les livres
|
||||
new:
|
||||
title_tag: Nouveau livre | BookForge
|
||||
title: Nouveau livre
|
||||
button: Créer le livre
|
||||
button_short: Ajouter un livre
|
||||
edit:
|
||||
title_tag: Modifier le livre | BookForge
|
||||
title: Modifier le livre
|
||||
button: Modifier le livre
|
||||
show:
|
||||
title_tag: Details | BookForge
|
||||
book_details: Détails du livre
|
||||
user_details: Détails de l'utilisateur.ice
|
||||
user_details: Détails de l'utilisateur
|
||||
more_informations: Plus d'informations
|
||||
footer:
|
||||
message: Fait avec amour & Nique les fachos !
|
||||
error:
|
||||
error_404:
|
||||
title_tag: Erreur 404 | BookForge
|
||||
title: Oups ! Cette page n'existe pas
|
||||
subtitle: 404 NOT FOUND
|
||||
button: Retour à l'accueil
|
||||
generic:
|
||||
title_tag: Erreur | BookForge
|
||||
title: Oups ! Une erreur s'est produite
|
||||
|
||||
14
src/lib.rs
14
src/lib.rs
@ -2,12 +2,10 @@ use askama::Template;
|
||||
use askama_web::WebTemplate;
|
||||
use axum::{
|
||||
Router,
|
||||
extract::State,
|
||||
routing::{get, post},
|
||||
};
|
||||
use static_serve::embed_assets;
|
||||
|
||||
use crate::routes::router::Router as InternalRouter;
|
||||
use crate::state::AppState;
|
||||
|
||||
mod migrations;
|
||||
@ -46,14 +44,8 @@ pub fn build_app(state: AppState) -> Router {
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "404.html")]
|
||||
struct NotFoundTemplate {
|
||||
pub router: InternalRouter,
|
||||
}
|
||||
struct NotFoundTemplate {}
|
||||
|
||||
pub async fn error_handler(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
||||
NotFoundTemplate {
|
||||
router: InternalRouter {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
}
|
||||
pub async fn error_handler() -> impl axum::response::IntoResponse {
|
||||
NotFoundTemplate {}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ use serde::Deserialize;
|
||||
use serde_with::{NoneAsEmptyString, serde_as};
|
||||
use snafu::prelude::*;
|
||||
|
||||
use crate::{models::book::Model as BookModel, routes::router::Router, state::error::CSVSnafu};
|
||||
use crate::{models::book::Model as BookModel, state::error::CSVSnafu};
|
||||
use crate::{models::user::Model as UserModel, state::error::IOSnafu};
|
||||
|
||||
use crate::{
|
||||
@ -55,7 +55,6 @@ struct BookIndexTemplate {
|
||||
current_page: u64,
|
||||
total_page: u64,
|
||||
base_query: String,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
pub async fn index(
|
||||
@ -74,7 +73,7 @@ pub async fn index(
|
||||
.context(UserSnafu)?;
|
||||
|
||||
// Get all Book filtered with query
|
||||
let books_paginate = BookOperator::new(state.clone())
|
||||
let books_paginate = BookOperator::new(state)
|
||||
.all_paginate(page, Some(query.clone()))
|
||||
.await
|
||||
.context(BookSnafu)?;
|
||||
@ -128,9 +127,6 @@ pub async fn index(
|
||||
current_page: books_paginate.current_page,
|
||||
total_page: books_paginate.total_page,
|
||||
base_query,
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -140,7 +136,6 @@ struct ShowBookTemplate {
|
||||
book: BookModel,
|
||||
owner: UserModel,
|
||||
current_holder: Option<UserModel>,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
pub async fn show(
|
||||
@ -173,9 +168,6 @@ pub async fn show(
|
||||
book,
|
||||
owner,
|
||||
current_holder,
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -208,23 +200,14 @@ pub async fn create(
|
||||
#[template(path = "books/new.html")]
|
||||
struct NewBookTemplate {
|
||||
users: Vec<UserModel>,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
pub async fn new(
|
||||
State(state): State<AppState>,
|
||||
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
||||
let users = UserOperator::new(state.clone())
|
||||
.all()
|
||||
.await
|
||||
.context(UserSnafu)?;
|
||||
let users = UserOperator::new(state).all().await.context(UserSnafu)?;
|
||||
|
||||
Ok(NewBookTemplate {
|
||||
users,
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
})
|
||||
Ok(NewBookTemplate { users })
|
||||
}
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
@ -232,7 +215,6 @@ pub async fn new(
|
||||
struct EditBookTemplate {
|
||||
users: Vec<UserModel>,
|
||||
book: BookModel,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
pub async fn edit(
|
||||
@ -243,18 +225,12 @@ pub async fn edit(
|
||||
.all()
|
||||
.await
|
||||
.context(UserSnafu)?;
|
||||
let book = BookOperator::new(state.clone())
|
||||
let book = BookOperator::new(state)
|
||||
.find_by_id(id)
|
||||
.await
|
||||
.context(BookSnafu)?;
|
||||
|
||||
Ok(EditBookTemplate {
|
||||
users,
|
||||
book,
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
})
|
||||
Ok(EditBookTemplate { users, book })
|
||||
}
|
||||
|
||||
pub async fn update(
|
||||
|
||||
@ -1,3 +1,2 @@
|
||||
pub mod book;
|
||||
pub mod router;
|
||||
pub mod user;
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
#[derive(Clone)]
|
||||
pub struct Router {
|
||||
pub base_path: String,
|
||||
}
|
||||
|
||||
impl Router {
|
||||
pub fn assets(&self, path: &str) -> String {
|
||||
if self.base_path.is_empty() || self.base_path == "/" {
|
||||
format!("/{}", path)
|
||||
} else {
|
||||
format!("{}/{}", self.base_path.trim_end_matches('/'), path)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_path(&self) -> String {
|
||||
format!("{}/", &self.base_path)
|
||||
}
|
||||
|
||||
// BOOKS ROUTES
|
||||
|
||||
pub fn new_book_path(&self) -> String {
|
||||
format!("{}/books/new", &self.base_path)
|
||||
}
|
||||
|
||||
pub fn create_book_path(&self) -> String {
|
||||
format!("{}/books", &self.base_path)
|
||||
}
|
||||
|
||||
pub fn update_book_path(&self, id: &i32) -> String {
|
||||
format!("{}/books/{}", &self.base_path, id)
|
||||
}
|
||||
|
||||
pub fn download_csv_book_path(&self) -> String {
|
||||
format!("{}/books/download_csv", &self.base_path)
|
||||
}
|
||||
|
||||
// USERS
|
||||
|
||||
pub fn index_user_path(&self) -> String {
|
||||
format!("{}/users", &self.base_path)
|
||||
}
|
||||
|
||||
pub fn new_user_path(&self) -> String {
|
||||
format!("{}/users/new", &self.base_path)
|
||||
}
|
||||
|
||||
pub fn create_user_path(&self) -> String {
|
||||
format!("{}/users", &self.base_path)
|
||||
}
|
||||
|
||||
pub fn update_user_path(&self, id: &i32) -> String {
|
||||
format!("{}/users/{}", &self.base_path, id)
|
||||
}
|
||||
}
|
||||
@ -16,7 +16,6 @@ use crate::{
|
||||
book::BookOperator,
|
||||
user::{self, UserOperator},
|
||||
},
|
||||
routes::router::Router,
|
||||
state::{
|
||||
AppState,
|
||||
error::{AppStateError, BookSnafu, UserSnafu},
|
||||
@ -28,7 +27,6 @@ use crate::{
|
||||
struct UsersIndexTemplate {
|
||||
users_with_books_number: Vec<UserWithBookNumber>,
|
||||
query: IndexQuery,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
pub struct UserWithBookNumber {
|
||||
@ -88,9 +86,6 @@ pub async fn index(
|
||||
Ok(UsersIndexTemplate {
|
||||
users_with_books_number: result,
|
||||
query,
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -140,36 +135,24 @@ pub async fn delete(
|
||||
#[template(path = "users/edit.html")]
|
||||
struct EditTemplate {
|
||||
user: user::Model,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
pub async fn edit(
|
||||
State(state): State<AppState>,
|
||||
Path(id): Path<i32>,
|
||||
) -> Result<impl axum::response::IntoResponse, AppStateError> {
|
||||
let user = UserOperator::new(state.clone())
|
||||
let user = UserOperator::new(state)
|
||||
.find_by_id(id)
|
||||
.await
|
||||
.context(UserSnafu)?;
|
||||
|
||||
Ok(EditTemplate {
|
||||
user,
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
})
|
||||
Ok(EditTemplate { user })
|
||||
}
|
||||
|
||||
#[derive(Template, WebTemplate)]
|
||||
#[template(path = "users/new.html")]
|
||||
struct NewTemplate {
|
||||
router: Router,
|
||||
}
|
||||
struct NewTemplate {}
|
||||
|
||||
pub async fn new(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
||||
NewTemplate {
|
||||
router: Router {
|
||||
base_path: state.config.base_path,
|
||||
},
|
||||
}
|
||||
pub async fn new() -> impl axum::response::IntoResponse {
|
||||
NewTemplate {}
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@ pub struct AppConfig {
|
||||
#[serde(default = "AppConfig::default_sqlite_path")]
|
||||
pub database_path: Utf8PathBuf,
|
||||
pub locale: String,
|
||||
pub base_path: String,
|
||||
pub listener: Listener,
|
||||
}
|
||||
|
||||
@ -41,7 +40,6 @@ impl Default for AppConfig {
|
||||
fn default() -> Self {
|
||||
AppConfig {
|
||||
database_path: Self::default_sqlite_path(),
|
||||
base_path: Self::default_base_path(),
|
||||
locale: Self::default_locale(),
|
||||
listener: Listener::default(),
|
||||
}
|
||||
@ -100,10 +98,6 @@ impl AppConfig {
|
||||
"en".to_string()
|
||||
}
|
||||
|
||||
fn default_base_path() -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
pub fn default_sqlite_path() -> Utf8PathBuf {
|
||||
Self::config_path().join("db.sqlite")
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ use snafu::prelude::*;
|
||||
|
||||
use crate::{
|
||||
models::{book::BookError, user::UserError},
|
||||
routes::router::Router,
|
||||
state::config::ConfigError,
|
||||
};
|
||||
|
||||
@ -48,7 +47,6 @@ pub enum AppStateError {
|
||||
#[template(path = "error.html")]
|
||||
struct ErrorTemplate {
|
||||
state: AppStateErrorContext,
|
||||
router: Router,
|
||||
}
|
||||
|
||||
struct AppStateErrorContext {
|
||||
@ -68,9 +66,6 @@ impl IntoResponse for AppStateError {
|
||||
let error_context = AppStateErrorContext::from(self);
|
||||
ErrorTemplate {
|
||||
state: error_context,
|
||||
router: Router {
|
||||
base_path: "".to_string(),
|
||||
},
|
||||
}
|
||||
.into_response()
|
||||
}
|
||||
|
||||
@ -1,13 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("error.error_404.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="mt-4 text-center">
|
||||
<h1>{{ t!("error.error_404.title") }}</h1>
|
||||
<h2 class="fst-italic">{{ t!("error.error_404.subtitle") }}</h2>
|
||||
<a href="{{ router.root_path() }}" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||
<a href="/" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -4,12 +4,11 @@
|
||||
<meta charset="utf-8">
|
||||
<title>{% block title %}{{ t!("name") }}{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href='{{ router.assets("assets/css/bootstrap.css") }}'>
|
||||
<link rel="stylesheet" href='{{ router.assets("assets/css/main.css") }}'>
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/images/favicon.png">
|
||||
<link rel="stylesheet" href="/assets/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="/assets/css/main.css">
|
||||
|
||||
<link rel="stylesheet" href='{{ router.assets("assets/css/fork-awesome.min.css") }}'>
|
||||
<link rel="icon" type="image/x-icon" href='{{ router.assets("assets/images/favicon.png") }}'>
|
||||
<link rel="stylesheet" href="/assets/css/fork-awesome.min.css">
|
||||
<link rel="icon" type="image/x-icon" href="/assets/images/favicon.ico">
|
||||
{% block extra_head %}{% endblock extra_head %}
|
||||
</head>
|
||||
|
||||
@ -26,7 +25,7 @@
|
||||
{% endblock %}
|
||||
</footer>
|
||||
|
||||
<script src='{{ router.assets("assets/js/bootstrap.min.js") }}'></script>
|
||||
<script src='{{ router.assets("assets/js/script.js") }}'></script>
|
||||
<script src="/assets/js/bootstrap.min.js"></script>
|
||||
<script src="/assets/js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@ -2,15 +2,11 @@
|
||||
{% import "components/typography.html" as typography %}
|
||||
{% import "components/cards.html" as cards %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("book.edit.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{{ typography::heading(t!("book.edit.title")) }}
|
||||
|
||||
{% call cards::card() %}
|
||||
<form method="post" action="{{ router.update_book_path(&book.id) }}">
|
||||
<form method="post" action="/books/{{ book.id }}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="title">{{ t!("book.attributes.title") }}</label>
|
||||
<input type="text" name="title" class="form-control" value="{{ book.title }}" required>
|
||||
|
||||
@ -3,15 +3,11 @@
|
||||
{% import "components/cards.html" as cards %}
|
||||
{% import "components/inputs.html" as form_helpers %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("book.new.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{{ typography::heading(t!("book.new.title")) }}
|
||||
|
||||
{% call cards::card() %}
|
||||
<form method="post" action="{{ router.create_book_path() }}">
|
||||
<form method="post" action="/books">
|
||||
{{ form_helpers::input("title", t!("book.attributes.title"), is_required = true, placeholder = "Ex: La Petite Dernière") }}
|
||||
{{ form_helpers::input("authors", t!("book.attributes.authors"), is_required = true, placeholder = "Ex: Fatima Daas") }}
|
||||
|
||||
|
||||
@ -4,16 +4,12 @@
|
||||
{% import "components/fields.html" as fields %}
|
||||
{% import "components/cards.html" as cards %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("book.show.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{{ typography::book_heading(book.title, book, show = false) }}
|
||||
|
||||
{% call cards::card() %}
|
||||
<div class="">
|
||||
<h5 class="fw-bold text-decoration-underline">{{ t!("book.show.book_details") }}</h5>
|
||||
<div class="mt-4">
|
||||
<h5 class="mt-4 fw-bold">{{ t!("book.show.book_details") }}</h5>
|
||||
{{ fields::field(t!("book.attributes.title"), book.title) }}
|
||||
{{ fields::field(t!("book.attributes.authors"), book.authors) }}
|
||||
|
||||
@ -24,7 +20,7 @@
|
||||
{{ fields::field(t!("book.attributes.description"), "-") }}
|
||||
{% endmatch %}
|
||||
|
||||
<h5 class="mt-50px fw-bold text-decoration-underline">{{ t!("book.show.user_details") }}</h5>
|
||||
<h5 class="mt-50px fw-bold">{{ t!("book.show.user_details") }}</h5>
|
||||
{{ fields::field(t!("book.attributes.owner"), owner.name) }}
|
||||
|
||||
{% match current_holder %}
|
||||
@ -35,7 +31,7 @@
|
||||
{% endmatch %}
|
||||
|
||||
|
||||
<h5 class="mt-50px fw-bold text-decoration-underline">{{ t!("book.show.more_informations") }}</h5>
|
||||
<h5 class="mt-50px fw-bold">{{ t!("book.show.more_informations") }}</h5>
|
||||
{% match book.comment %}
|
||||
{% when Some with (comment) %}
|
||||
{{ fields::field(t!("book.attributes.comment"), comment) }}
|
||||
|
||||
@ -18,9 +18,9 @@
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
{% if show %}
|
||||
<li><a class="dropdown-item" href="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}">{{ t!("common.show") }}</a></li>
|
||||
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}">{{ t!("common.show") }}</a></li>
|
||||
{% endif %}
|
||||
<li><a class="dropdown-item" href="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}/edit">{{ t!("common.edit") }}</a></li>
|
||||
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}/edit">{{ t!("common.edit") }}</a></li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteUserModal{{ book.id }}">{{ t!("common.delete") }}</a>
|
||||
</li>
|
||||
@ -40,7 +40,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t!("common.close") }}</button>
|
||||
<form method="post" action="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}/delete" class="m-0">
|
||||
<form method="post" action="/{{ sub_path }}/{{ book.id }}/delete" class="m-0">
|
||||
<input class="btn btn-danger" type="submit" value='{{ t!("common.delete") }}'>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@ -1,9 +1,4 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("error.generic.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="mt-4 text-center">
|
||||
<h1>{{ t!("error.generic.title") }}</h1>
|
||||
@ -12,6 +7,6 @@
|
||||
<p>{{ error }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<a href="{{ router.root_path() }}" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||
<a href="/" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -3,13 +3,9 @@
|
||||
{% import "components/dropdown.html" as dropdown %}
|
||||
{% import "components/cards.html" as cards %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("book.index.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% call typography::heading(t!("book.index.title")) %}
|
||||
<a href="{{ router.download_csv_book_path() }}?{{ base_query }}" class="btn btn-info">
|
||||
<a href="/books/download_csv?{{ base_query }}" class="btn btn-info">
|
||||
<i class="fa fa-download me-2" aria-hidden="true"></i> {{ t!("common.download") }} (csv)
|
||||
</a>
|
||||
{% endcall %}
|
||||
@ -87,7 +83,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-1 d-flex align-items-end">
|
||||
<a href="{{ router.root_path() }}" class="btn btn-light">{{ t!("common.reset") }}</a>
|
||||
<a href="/" class="btn btn-light">{{ t!("common.reset") }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -98,7 +94,7 @@
|
||||
<div class="d-flex flex-column align-items-center justify-content-center">
|
||||
<h2>{{ t!("common.no_result") }}</h2>
|
||||
|
||||
<a class="btn btn-success text-white text-nowrap mt-3" href="{{ router.new_book_path() }}">
|
||||
<a class="btn btn-success text-white text-nowrap mt-3" href="/books/new">
|
||||
{{ t!("book.new.button_short") }}
|
||||
</a>
|
||||
</div>
|
||||
@ -142,19 +138,19 @@
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination">
|
||||
<li class="page-item {% if current_page <= 1 %}disabled{% endif %}">
|
||||
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={% if current_page > 1 %}{{ current_page - 1 }}{% else %}1{% endif %}">{{ t!("common.previous") }}</a>
|
||||
<a class="page-link" href="/?{{ base_query }}page={% if current_page > 1 %}{{ current_page - 1 }}{% else %}1{% endif %}">{{ t!("common.prev") }}</a>
|
||||
</li>
|
||||
|
||||
{% for page in 1..(total_page + 1) %}
|
||||
{% if page >= current_page - 1 && page <= current_page + 1 %}
|
||||
<li class="page-item {% if page == current_page %}active{% endif %}">
|
||||
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={{ page }}">{{ page }}</a>
|
||||
<a class="page-link" href="/?{{ base_query }}page={{ page }}">{{ page }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
|
||||
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={{ current_page + 1 }}">{{ t!("common.next") }}</a>
|
||||
<a class="page-link" href="/?{{ base_query }}page={{ current_page + 1 }}">{{ t!("common.next") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
<div class="d-flex flex-column flex-sm-row gap-0 gap-sm-3 justify-content-center">
|
||||
<p>{{ t!("footer.message") }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,6 +1,6 @@
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary fixed-top shadow">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ router.root_path() }}">
|
||||
<a class="navbar-brand" href="/">
|
||||
{{ t!("name") }}
|
||||
</a>
|
||||
|
||||
@ -12,10 +12,10 @@
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ router.root_path() }}">{{ t!("nav.books") }}</a>
|
||||
<a class="nav-link" href="/">{{ t!("nav.books") }}</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ router.index_user_path() }}">{{ t!("nav.users") }}</a>
|
||||
<a class="nav-link" href="/users">{{ t!("nav.users") }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="d-flex align-items-center gap-2 py-3">
|
||||
@ -24,7 +24,7 @@
|
||||
<option value="dark">{{ t!("theme.dark") }}</option>
|
||||
</select>
|
||||
|
||||
<a class="btn btn-success text-white text-nowrap" href="{{ router.new_book_path() }}">
|
||||
<a class="btn btn-success text-white text-nowrap" href="/books/new">
|
||||
{{ t!("book.new.button_short") }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
{% import "components/typography.html" as typography %}
|
||||
{% import "components/cards.html" as cards %}
|
||||
{% import "components/inputs.html" as form_helpers %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("book.edit.title_tag") }}
|
||||
{% endblock %}
|
||||
o{% import "components/inputs.html" as form_helpers %}
|
||||
|
||||
{% block main %}
|
||||
{{ typography::heading(t!("user.edit.title")) }}
|
||||
|
||||
{% call cards::card() %}
|
||||
<form action="{{ router.update_user_path(&user.id) }}" method="post">
|
||||
<form action="/users/{{ user.id }}" method="post">
|
||||
<div class="row align-items-end">
|
||||
<div class="col-md-10">
|
||||
{{ form_helpers::input("name", t!("user.attributes.name"), value = user.name, is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
||||
|
||||
@ -4,13 +4,9 @@
|
||||
{% import "components/cards.html" as cards %}
|
||||
{% import "components/inputs.html" as form_helpers %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("user.index.title_tag") }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% call typography::heading(t!("user.index.title")) %}
|
||||
<a class="btn-success btn" href="{{ router.new_user_path() }}">{{ t!("user.index.button") }}</a>
|
||||
<a class="btn-success btn" href="/users/new">{{ t!("user.index.button") }}</a>
|
||||
{% endcall %}
|
||||
|
||||
{% call cards::card() %}
|
||||
@ -42,7 +38,7 @@
|
||||
<div class="d-flex flex-column align-items-center justify-content-center">
|
||||
<h2>{{ t!("common.no_result") }}</h2>
|
||||
|
||||
<a class="btn btn-success text-white text-nowrap mt-3" href="{{ router.new_user_path() }}">
|
||||
<a class="btn btn-success text-white text-nowrap mt-3" href="//new">
|
||||
{{ t!("user.index.button") }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
{% import "components/typography.html" as typography %}
|
||||
{% import "components/cards.html" as cards %}
|
||||
{% import "components/inputs.html" as form_helpers %}
|
||||
|
||||
{% block title %}
|
||||
{{ t!("user.new.title_tag") }}
|
||||
{% endblock %}
|
||||
o{% import "components/inputs.html" as form_helpers %}
|
||||
|
||||
{% block main %}
|
||||
{{ typography::heading(t!("user.new.title")) }}
|
||||
|
||||
{% call cards::card() %}
|
||||
<form action="{{ router.create_user_path() }}" method="post">
|
||||
<form action="/users" method="post">
|
||||
<div class="row align-items-end">
|
||||
<div class="col-md-10">
|
||||
{{ form_helpers::input("name", t!("user.attributes.name"), is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user