Add router
This commit is contained in:
parent
f6d4e7c556
commit
8c94eb5252
@ -7,7 +7,8 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use static_serve::embed_assets;
|
use static_serve::embed_assets;
|
||||||
|
|
||||||
use crate::{routes::template_ctx::TemplateCtx, state::AppState};
|
use crate::routes::router::Router as InternalRouter;
|
||||||
|
use crate::state::AppState;
|
||||||
|
|
||||||
mod migrations;
|
mod migrations;
|
||||||
mod models;
|
mod models;
|
||||||
@ -46,12 +47,12 @@ pub fn build_app(state: AppState) -> Router {
|
|||||||
#[derive(Template, WebTemplate)]
|
#[derive(Template, WebTemplate)]
|
||||||
#[template(path = "404.html")]
|
#[template(path = "404.html")]
|
||||||
struct NotFoundTemplate {
|
struct NotFoundTemplate {
|
||||||
pub ctx: TemplateCtx,
|
pub router: InternalRouter,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn error_handler(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
pub async fn error_handler(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
||||||
NotFoundTemplate {
|
NotFoundTemplate {
|
||||||
ctx: TemplateCtx {
|
router: InternalRouter {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,9 +13,7 @@ use serde::Deserialize;
|
|||||||
use serde_with::{NoneAsEmptyString, serde_as};
|
use serde_with::{NoneAsEmptyString, serde_as};
|
||||||
use snafu::prelude::*;
|
use snafu::prelude::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{models::book::Model as BookModel, routes::router::Router, state::error::CSVSnafu};
|
||||||
models::book::Model as BookModel, routes::template_ctx::TemplateCtx, state::error::CSVSnafu,
|
|
||||||
};
|
|
||||||
use crate::{models::user::Model as UserModel, state::error::IOSnafu};
|
use crate::{models::user::Model as UserModel, state::error::IOSnafu};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -57,7 +55,7 @@ struct BookIndexTemplate {
|
|||||||
current_page: u64,
|
current_page: u64,
|
||||||
total_page: u64,
|
total_page: u64,
|
||||||
base_query: String,
|
base_query: String,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn index(
|
pub async fn index(
|
||||||
@ -130,7 +128,7 @@ pub async fn index(
|
|||||||
current_page: books_paginate.current_page,
|
current_page: books_paginate.current_page,
|
||||||
total_page: books_paginate.total_page,
|
total_page: books_paginate.total_page,
|
||||||
base_query,
|
base_query,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -142,7 +140,7 @@ struct ShowBookTemplate {
|
|||||||
book: BookModel,
|
book: BookModel,
|
||||||
owner: UserModel,
|
owner: UserModel,
|
||||||
current_holder: Option<UserModel>,
|
current_holder: Option<UserModel>,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn show(
|
pub async fn show(
|
||||||
@ -175,7 +173,7 @@ pub async fn show(
|
|||||||
book,
|
book,
|
||||||
owner,
|
owner,
|
||||||
current_holder,
|
current_holder,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -210,7 +208,7 @@ pub async fn create(
|
|||||||
#[template(path = "books/new.html")]
|
#[template(path = "books/new.html")]
|
||||||
struct NewBookTemplate {
|
struct NewBookTemplate {
|
||||||
users: Vec<UserModel>,
|
users: Vec<UserModel>,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
@ -223,7 +221,7 @@ pub async fn new(
|
|||||||
|
|
||||||
Ok(NewBookTemplate {
|
Ok(NewBookTemplate {
|
||||||
users,
|
users,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -234,7 +232,7 @@ pub async fn new(
|
|||||||
struct EditBookTemplate {
|
struct EditBookTemplate {
|
||||||
users: Vec<UserModel>,
|
users: Vec<UserModel>,
|
||||||
book: BookModel,
|
book: BookModel,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit(
|
pub async fn edit(
|
||||||
@ -253,7 +251,7 @@ pub async fn edit(
|
|||||||
Ok(EditBookTemplate {
|
Ok(EditBookTemplate {
|
||||||
users,
|
users,
|
||||||
book,
|
book,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
pub mod book;
|
pub mod book;
|
||||||
pub mod template_ctx;
|
pub mod router;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
|||||||
54
src/routes/router.rs
Normal file
54
src/routes/router.rs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#[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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +0,0 @@
|
|||||||
#[derive(Clone)]
|
|
||||||
pub struct TemplateCtx {
|
|
||||||
pub base_path: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TemplateCtx {
|
|
||||||
pub fn asset(&self, path: &str) -> String {
|
|
||||||
if self.base_path.is_empty() || self.base_path == "/" {
|
|
||||||
format!("/{}", path)
|
|
||||||
} else {
|
|
||||||
format!("{}/{}", self.base_path.trim_end_matches('/'), path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
book::BookOperator,
|
book::BookOperator,
|
||||||
user::{self, UserOperator},
|
user::{self, UserOperator},
|
||||||
},
|
},
|
||||||
routes::template_ctx::TemplateCtx,
|
routes::router::Router,
|
||||||
state::{
|
state::{
|
||||||
AppState,
|
AppState,
|
||||||
error::{AppStateError, BookSnafu, UserSnafu},
|
error::{AppStateError, BookSnafu, UserSnafu},
|
||||||
@ -28,7 +28,7 @@ use crate::{
|
|||||||
struct UsersIndexTemplate {
|
struct UsersIndexTemplate {
|
||||||
users_with_books_number: Vec<UserWithBookNumber>,
|
users_with_books_number: Vec<UserWithBookNumber>,
|
||||||
query: IndexQuery,
|
query: IndexQuery,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserWithBookNumber {
|
pub struct UserWithBookNumber {
|
||||||
@ -88,7 +88,7 @@ pub async fn index(
|
|||||||
Ok(UsersIndexTemplate {
|
Ok(UsersIndexTemplate {
|
||||||
users_with_books_number: result,
|
users_with_books_number: result,
|
||||||
query,
|
query,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -140,7 +140,7 @@ pub async fn delete(
|
|||||||
#[template(path = "users/edit.html")]
|
#[template(path = "users/edit.html")]
|
||||||
struct EditTemplate {
|
struct EditTemplate {
|
||||||
user: user::Model,
|
user: user::Model,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn edit(
|
pub async fn edit(
|
||||||
@ -154,7 +154,7 @@ pub async fn edit(
|
|||||||
|
|
||||||
Ok(EditTemplate {
|
Ok(EditTemplate {
|
||||||
user,
|
user,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -163,12 +163,12 @@ pub async fn edit(
|
|||||||
#[derive(Template, WebTemplate)]
|
#[derive(Template, WebTemplate)]
|
||||||
#[template(path = "users/new.html")]
|
#[template(path = "users/new.html")]
|
||||||
struct NewTemplate {
|
struct NewTemplate {
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn new(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
pub async fn new(State(state): State<AppState>) -> impl axum::response::IntoResponse {
|
||||||
NewTemplate {
|
NewTemplate {
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: state.config.base_path,
|
base_path: state.config.base_path,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use snafu::prelude::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{book::BookError, user::UserError},
|
models::{book::BookError, user::UserError},
|
||||||
routes::template_ctx::TemplateCtx,
|
routes::router::Router,
|
||||||
state::config::ConfigError,
|
state::config::ConfigError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ pub enum AppStateError {
|
|||||||
#[template(path = "error.html")]
|
#[template(path = "error.html")]
|
||||||
struct ErrorTemplate {
|
struct ErrorTemplate {
|
||||||
state: AppStateErrorContext,
|
state: AppStateErrorContext,
|
||||||
ctx: TemplateCtx,
|
router: Router,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AppStateErrorContext {
|
struct AppStateErrorContext {
|
||||||
@ -68,7 +68,7 @@ impl IntoResponse for AppStateError {
|
|||||||
let error_context = AppStateErrorContext::from(self);
|
let error_context = AppStateErrorContext::from(self);
|
||||||
ErrorTemplate {
|
ErrorTemplate {
|
||||||
state: error_context,
|
state: error_context,
|
||||||
ctx: TemplateCtx {
|
router: Router {
|
||||||
base_path: "".to_string(),
|
base_path: "".to_string(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,6 @@
|
|||||||
<div class="mt-4 text-center">
|
<div class="mt-4 text-center">
|
||||||
<h1>{{ t!("error.error_404.title") }}</h1>
|
<h1>{{ t!("error.error_404.title") }}</h1>
|
||||||
<h2 class="fst-italic">{{ t!("error.error_404.subtitle") }}</h2>
|
<h2 class="fst-italic">{{ t!("error.error_404.subtitle") }}</h2>
|
||||||
<a href="/" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
<a href="{{ router.root_path() }}" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -4,12 +4,12 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{% block title %}{{ t!("name") }}{% endblock %}</title>
|
<title>{% block title %}{{ t!("name") }}{% endblock %}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href='{{ ctx.asset("assets/css/bootstrap.css") }}'>
|
<link rel="stylesheet" href='{{ router.assets("assets/css/bootstrap.css") }}'>
|
||||||
<link rel="stylesheet" href='{{ ctx.asset("assets/css/main.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="icon" type="image/png" sizes="32x32" href="/assets/images/favicon.png">
|
||||||
|
|
||||||
<link rel="stylesheet" href='{{ ctx.asset("assets/css/fork-awesome.min.css") }}'>
|
<link rel="stylesheet" href='{{ router.assets("assets/css/fork-awesome.min.css") }}'>
|
||||||
<link rel="icon" type="image/x-icon" href='{{ ctx.asset("assets/images/favicon.ico") }}'>
|
<link rel="icon" type="image/x-icon" href='{{ router.assets("assets/images/favicon.ico") }}'>
|
||||||
{% block extra_head %}{% endblock extra_head %}
|
{% block extra_head %}{% endblock extra_head %}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -26,7 +26,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src='{{ ctx.asset("assets/js/bootstrap.min.js") }}'></script>
|
<script src='{{ router.assets("assets/js/bootstrap.min.js") }}'></script>
|
||||||
<script src='{{ ctx.asset("assets/js/script.js") }}'></script>
|
<script src='{{ router.assets("assets/js/script.js") }}'></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
{{ typography::heading(t!("book.edit.title")) }}
|
{{ typography::heading(t!("book.edit.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form method="post" action="/books/{{ book.id }}">
|
<form method="post" action="{{ router.update_book_path(&book.id) }}">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="title">{{ t!("book.attributes.title") }}</label>
|
<label class="form-label" for="title">{{ t!("book.attributes.title") }}</label>
|
||||||
<input type="text" name="title" class="form-control" value="{{ book.title }}" required>
|
<input type="text" name="title" class="form-control" value="{{ book.title }}" required>
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
{{ typography::heading(t!("book.new.title")) }}
|
{{ typography::heading(t!("book.new.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form method="post" action="/books">
|
<form method="post" action="{{ router.create_book_path() }}">
|
||||||
{{ form_helpers::input("title", t!("book.attributes.title"), is_required = true, placeholder = "Ex: La Petite Dernière") }}
|
{{ 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") }}
|
{{ form_helpers::input("authors", t!("book.attributes.authors"), is_required = true, placeholder = "Ex: Fatima Daas") }}
|
||||||
|
|
||||||
|
|||||||
@ -18,9 +18,9 @@
|
|||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% if show %}
|
{% if show %}
|
||||||
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}">{{ t!("common.show") }}</a></li>
|
<li><a class="dropdown-item" href="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}">{{ t!("common.show") }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}/edit">{{ t!("common.edit") }}</a></li>
|
<li><a class="dropdown-item" href="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}/edit">{{ t!("common.edit") }}</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteUserModal{{ book.id }}">{{ t!("common.delete") }}</a>
|
<a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteUserModal{{ book.id }}">{{ t!("common.delete") }}</a>
|
||||||
</li>
|
</li>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t!("common.close") }}</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ t!("common.close") }}</button>
|
||||||
<form method="post" action="/{{ sub_path }}/{{ book.id }}/delete" class="m-0">
|
<form method="post" action="{{ router.root_path() }}{{ sub_path }}/{{ book.id }}/delete" class="m-0">
|
||||||
<input class="btn btn-danger" type="submit" value='{{ t!("common.delete") }}'>
|
<input class="btn btn-danger" type="submit" value='{{ t!("common.delete") }}'>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,6 +12,6 @@
|
|||||||
<p>{{ error }}</p>
|
<p>{{ error }}</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<a href="/" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
<a href="{{ router.root_path() }}" class="mt-3 btn btn-info">{{ t!("error.error_404.button") }}</a>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% call typography::heading(t!("book.index.title")) %}
|
{% call typography::heading(t!("book.index.title")) %}
|
||||||
<a href="/books/download_csv?{{ base_query }}" class="btn btn-info">
|
<a href="{{ router.download_csv_book_path() }}?{{ base_query }}" class="btn btn-info">
|
||||||
<i class="fa fa-download me-2" aria-hidden="true"></i> {{ t!("common.download") }} (csv)
|
<i class="fa fa-download me-2" aria-hidden="true"></i> {{ t!("common.download") }} (csv)
|
||||||
</a>
|
</a>
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
@ -87,7 +87,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-1 d-flex align-items-end">
|
<div class="col-md-1 d-flex align-items-end">
|
||||||
<a href="/" class="btn btn-light">{{ t!("common.reset") }}</a>
|
<a href="{{ router.root_path() }}" class="btn btn-light">{{ t!("common.reset") }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -98,7 +98,7 @@
|
|||||||
<div class="d-flex flex-column align-items-center justify-content-center">
|
<div class="d-flex flex-column align-items-center justify-content-center">
|
||||||
<h2>{{ t!("common.no_result") }}</h2>
|
<h2>{{ t!("common.no_result") }}</h2>
|
||||||
|
|
||||||
<a class="btn btn-success text-white text-nowrap mt-3" href="/books/new">
|
<a class="btn btn-success text-white text-nowrap mt-3" href="{{ router.new_book_path() }}">
|
||||||
{{ t!("book.new.button_short") }}
|
{{ t!("book.new.button_short") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -142,19 +142,19 @@
|
|||||||
<nav aria-label="Page navigation">
|
<nav aria-label="Page navigation">
|
||||||
<ul class="pagination">
|
<ul class="pagination">
|
||||||
<li class="page-item {% if current_page <= 1 %}disabled{% endif %}">
|
<li class="page-item {% if current_page <= 1 %}disabled{% endif %}">
|
||||||
<a class="page-link" href="/?{{ base_query }}page={% if current_page > 1 %}{{ current_page - 1 }}{% else %}1{% endif %}">{{ t!("common.prev") }}</a>
|
<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>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% for page in 1..(total_page + 1) %}
|
{% for page in 1..(total_page + 1) %}
|
||||||
{% if page >= current_page - 1 && page <= current_page + 1 %}
|
{% if page >= current_page - 1 && page <= current_page + 1 %}
|
||||||
<li class="page-item {% if page == current_page %}active{% endif %}">
|
<li class="page-item {% if page == current_page %}active{% endif %}">
|
||||||
<a class="page-link" href="/?{{ base_query }}page={{ page }}">{{ page }}</a>
|
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={{ page }}">{{ page }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
|
<li class="page-item {% if current_page == total_page %}disabled{% endif %}">
|
||||||
<a class="page-link" href="/?{{ base_query }}page={{ current_page + 1 }}">{{ t!("common.next") }}</a>
|
<a class="page-link" href="{{ router.root_path() }}?{{ base_query }}page={{ current_page + 1 }}">{{ t!("common.next") }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@ -2,4 +2,4 @@
|
|||||||
<div class="d-flex flex-column flex-sm-row gap-0 gap-sm-3 justify-content-center">
|
<div class="d-flex flex-column flex-sm-row gap-0 gap-sm-3 justify-content-center">
|
||||||
<p>{{ t!("footer.message") }}</p>
|
<p>{{ t!("footer.message") }}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<nav class="navbar navbar-expand-lg bg-body-tertiary fixed-top shadow">
|
<nav class="navbar navbar-expand-lg bg-body-tertiary fixed-top shadow">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">
|
<a class="navbar-brand" href="{{ router.root_path() }}">
|
||||||
{{ t!("name") }}
|
{{ t!("name") }}
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
@ -12,10 +12,10 @@
|
|||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav me-auto">
|
<ul class="navbar-nav me-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/">{{ t!("nav.books") }}</a>
|
<a class="nav-link" href="{{ router.root_path() }}">{{ t!("nav.books") }}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="/users">{{ t!("nav.users") }}</a>
|
<a class="nav-link" href="{{ router.index_user_path() }}">{{ t!("nav.users") }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="d-flex align-items-center gap-2 py-3">
|
<div class="d-flex align-items-center gap-2 py-3">
|
||||||
@ -24,7 +24,7 @@
|
|||||||
<option value="dark">{{ t!("theme.dark") }}</option>
|
<option value="dark">{{ t!("theme.dark") }}</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<a class="btn btn-success text-white text-nowrap" href="/books/new">
|
<a class="btn btn-success text-white text-nowrap" href="{{ router.new_book_path() }}">
|
||||||
{{ t!("book.new.button_short") }}
|
{{ t!("book.new.button_short") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
{{ typography::heading(t!("user.edit.title")) }}
|
{{ typography::heading(t!("user.edit.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form action="/users/{{ user.id }}" method="post">
|
<form action="{{ router.update_user_path(&user.id) }}" method="post">
|
||||||
<div class="row align-items-end">
|
<div class="row align-items-end">
|
||||||
<div class="col-md-10">
|
<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) }}
|
{{ form_helpers::input("name", t!("user.attributes.name"), value = user.name, is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% block main %}
|
||||||
{% call typography::heading(t!("user.index.title")) %}
|
{% call typography::heading(t!("user.index.title")) %}
|
||||||
<a class="btn-success btn" href="/users/new">{{ t!("user.index.button") }}</a>
|
<a class="btn-success btn" href="{{ router.new_user_path() }}">{{ t!("user.index.button") }}</a>
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
@ -42,7 +42,7 @@
|
|||||||
<div class="d-flex flex-column align-items-center justify-content-center">
|
<div class="d-flex flex-column align-items-center justify-content-center">
|
||||||
<h2>{{ t!("common.no_result") }}</h2>
|
<h2>{{ t!("common.no_result") }}</h2>
|
||||||
|
|
||||||
<a class="btn btn-success text-white text-nowrap mt-3" href="//new">
|
<a class="btn btn-success text-white text-nowrap mt-3" href="{{ router.new_user_path() }}">
|
||||||
{{ t!("user.index.button") }}
|
{{ t!("user.index.button") }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
{{ typography::heading(t!("user.new.title")) }}
|
{{ typography::heading(t!("user.new.title")) }}
|
||||||
|
|
||||||
{% call cards::card() %}
|
{% call cards::card() %}
|
||||||
<form action="/users" method="post">
|
<form action="{{ router.create_user_path() }}" method="post">
|
||||||
<div class="row align-items-end">
|
<div class="row align-items-end">
|
||||||
<div class="col-md-10">
|
<div class="col-md-10">
|
||||||
{{ form_helpers::input("name", t!("user.attributes.name"), is_required = true, placeholder = "Ex: Kropotkine", margin_bottom = false) }}
|
{{ 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