Merge pull request 'User Authentication and Other fixes' (#1) from user-auth into main
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
DATABASE_URL="sqlite:../data-debug/db/sqlite.db?mode=rwc"
|
||||||
|
IMAGES_DIR="../data-debug/images"
|
||||||
|
CORS_URL="*"
|
||||||
|
MEILI_URL="http://localhost:7700"
|
||||||
|
MEILI_KEY="asdasdasd"
|
||||||
|
BACKEND_URL="http://localhost:8081"
|
||||||
@@ -10,6 +10,7 @@ images/*
|
|||||||
data/*
|
data/*
|
||||||
data-debug/*
|
data-debug/*
|
||||||
booksman.tar
|
booksman.tar
|
||||||
|
frontend/node_modules/
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
# Cargo.lock
|
# Cargo.lock
|
||||||
|
|||||||
Generated
+500
-137
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ booksman-orm = { path = "../orm" }
|
|||||||
booksman-search = { path = "../search" }
|
booksman-search = { path = "../search" }
|
||||||
migration = { path = "../migration" }
|
migration = { path = "../migration" }
|
||||||
entity = { path = "../entity" }
|
entity = { path = "../entity" }
|
||||||
axum = "^0.5"
|
axum = "^0.6"
|
||||||
axum-extra = { version = "^0.3", features = ["spa"] }
|
axum-extra = { version = "^0.3", features = ["spa"] }
|
||||||
clap = { version = "^3", features = ["derive"] }
|
clap = { version = "^3", features = ["derive"] }
|
||||||
dotenvy = "0.15.0"
|
dotenvy = "0.15.0"
|
||||||
@@ -27,9 +27,16 @@ tracing = "^0.1"
|
|||||||
tracing-subscriber = "^0.3"
|
tracing-subscriber = "^0.3"
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
axum-login = "0.4"
|
||||||
|
axum-macros = "0.3"
|
||||||
|
#features = ["sqlite"]
|
||||||
|
|
||||||
|
[dependencies.rand]
|
||||||
|
version = "0.8.5"
|
||||||
|
features = ["min_const_gen"]
|
||||||
|
|
||||||
[dependencies.sea-orm]
|
[dependencies.sea-orm]
|
||||||
version = "^0.9.2" # sea-orm version
|
version = "^0.10.6" # sea-orm version
|
||||||
features = [
|
features = [
|
||||||
"debug-print",
|
"debug-print",
|
||||||
"runtime-tokio-native-tls",
|
"runtime-tokio-native-tls",
|
||||||
|
|||||||
+785
-362
File diff suppressed because it is too large
Load Diff
@@ -13,4 +13,4 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
|
||||||
[dependencies.sea-orm]
|
[dependencies.sea-orm]
|
||||||
version = "^0.9.2" # sea-orm version
|
version = "^0.10.6" # sea-orm version
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book")]
|
#[sea_orm(table_name = "book")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
@@ -19,12 +19,15 @@ pub struct Model {
|
|||||||
pub time_added: Option<String>,
|
pub time_added: Option<String>,
|
||||||
pub rating: Option<i32>,
|
pub rating: Option<i32>,
|
||||||
pub comments: Option<String>,
|
pub comments: Option<String>,
|
||||||
|
pub user_id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
#[sea_orm(has_many = "super::book_author::Entity")]
|
#[sea_orm(has_many = "super::book_author::Entity")]
|
||||||
BookAuthor,
|
BookAuthor,
|
||||||
|
#[sea_orm(has_many = "super::book_isbn::Entity")]
|
||||||
|
BookIsbn,
|
||||||
#[sea_orm(has_many = "super::book_person::Entity")]
|
#[sea_orm(has_many = "super::book_person::Entity")]
|
||||||
BookPerson,
|
BookPerson,
|
||||||
#[sea_orm(has_many = "super::book_place::Entity")]
|
#[sea_orm(has_many = "super::book_place::Entity")]
|
||||||
@@ -33,8 +36,14 @@ pub enum Relation {
|
|||||||
BookSubject,
|
BookSubject,
|
||||||
#[sea_orm(has_many = "super::book_time::Entity")]
|
#[sea_orm(has_many = "super::book_time::Entity")]
|
||||||
BookTime,
|
BookTime,
|
||||||
#[sea_orm(has_many = "super::book_isbn::Entity")]
|
#[sea_orm(
|
||||||
BookIsbn,
|
belongs_to = "super::user::Entity",
|
||||||
|
from = "Column::UserId",
|
||||||
|
to = "super::user::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
User,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::book_author::Entity> for Entity {
|
impl Related<super::book_author::Entity> for Entity {
|
||||||
@@ -43,6 +52,12 @@ impl Related<super::book_author::Entity> for Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::book_isbn::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::BookIsbn.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Related<super::book_person::Entity> for Entity {
|
impl Related<super::book_person::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::BookPerson.def()
|
Relation::BookPerson.def()
|
||||||
@@ -67,9 +82,9 @@ impl Related<super::book_time::Entity> for Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::book_isbn::Entity> for Entity {
|
impl Related<super::user::Entity> for Entity {
|
||||||
fn to() -> RelationDef {
|
fn to() -> RelationDef {
|
||||||
Relation::BookIsbn.def()
|
Relation::User.def()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book_author")]
|
#[sea_orm(table_name = "book_author")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book_isbn")]
|
#[sea_orm(table_name = "book_isbn")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book_person")]
|
#[sea_orm(table_name = "book_person")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book_place")]
|
#[sea_orm(table_name = "book_place")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book_subject")]
|
#[sea_orm(table_name = "book_subject")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
#[sea_orm(table_name = "book_time")]
|
#[sea_orm(table_name = "book_time")]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
@@ -9,3 +9,4 @@ pub mod book_person;
|
|||||||
pub mod book_place;
|
pub mod book_place;
|
||||||
pub mod book_subject;
|
pub mod book_subject;
|
||||||
pub mod book_time;
|
pub mod book_time;
|
||||||
|
pub mod user;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
pub use super::book::Entity as Book;
|
pub use super::book::Entity as Book;
|
||||||
pub use super::book_author::Entity as BookAuthor;
|
pub use super::book_author::Entity as BookAuthor;
|
||||||
@@ -7,3 +7,4 @@ pub use super::book_person::Entity as BookPerson;
|
|||||||
pub use super::book_place::Entity as BookPlace;
|
pub use super::book_place::Entity as BookPlace;
|
||||||
pub use super::book_subject::Entity as BookSubject;
|
pub use super::book_subject::Entity as BookSubject;
|
||||||
pub use super::book_time::Entity as BookTime;
|
pub use super::book_time::Entity as BookTime;
|
||||||
|
pub use super::user::Entity as User;
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6
|
||||||
|
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||||
|
#[sea_orm(table_name = "user")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i32,
|
||||||
|
pub user_name: Option<String>,
|
||||||
|
pub password_hash: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(has_many = "super::book::Entity")]
|
||||||
|
Book,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::book::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Book.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
@@ -1,3 +1 @@
|
|||||||
pub mod entities;
|
pub mod entities;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ async-std = { version = "^1", features = ["attributes", "tokio1"] }
|
|||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
|
||||||
[dependencies.sea-orm-migration]
|
[dependencies.sea-orm-migration]
|
||||||
version = "^0.9.2"
|
version = "^0.10.6"
|
||||||
features = [
|
features = [
|
||||||
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
|
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
|
||||||
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
|
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
|
||||||
|
|||||||
@@ -10,6 +10,30 @@ impl MigrationTrait for Migration {
|
|||||||
// Replace the sample below with your own migration scripts
|
// Replace the sample below with your own migration scripts
|
||||||
//todo!();
|
//todo!();
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(User::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(User::Id)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(User::UserName)
|
||||||
|
.string()
|
||||||
|
.unique_key()
|
||||||
|
.not_null(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(User::PasswordHash).string().not_null())
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
Table::create()
|
Table::create()
|
||||||
@@ -34,9 +58,19 @@ impl MigrationTrait for Migration {
|
|||||||
.col(ColumnDef::new(Book::TimeAdded).time())
|
.col(ColumnDef::new(Book::TimeAdded).time())
|
||||||
.col(ColumnDef::new(Book::Rating).integer())
|
.col(ColumnDef::new(Book::Rating).integer())
|
||||||
.col(ColumnDef::new(Book::Comments).string())
|
.col(ColumnDef::new(Book::Comments).string())
|
||||||
|
.col(ColumnDef::new(Book::UserId).integer().not_null())
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("FK_2e303c3a712662f1fc2a4d0aavc")
|
||||||
|
.from(Book::Table, Book::UserId)
|
||||||
|
.to(User::Table, User::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
|
.on_update(ForeignKeyAction::Cascade),
|
||||||
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await.expect("Migration failed");
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
@@ -62,7 +96,8 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await.expect("Migration failed");
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
@@ -88,7 +123,8 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await.expect("Migration failed");
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
@@ -114,7 +150,8 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await.expect("Migration failed");
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
@@ -140,7 +177,8 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await.expect("Migration failed");
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
@@ -166,7 +204,8 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.await.expect("Migration failed");
|
.await
|
||||||
|
.expect("Migration failed");
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
@@ -201,22 +240,28 @@ impl MigrationTrait for Migration {
|
|||||||
|
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(Book::Table).to_owned())
|
.drop_table(Table::drop().table(Book::Table).to_owned())
|
||||||
.await.expect("Drop failed");
|
.await
|
||||||
|
.expect("Drop failed");
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookAuthor::Table).to_owned())
|
.drop_table(Table::drop().table(BookAuthor::Table).to_owned())
|
||||||
.await.expect("Drop failed");
|
.await
|
||||||
|
.expect("Drop failed");
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookPerson::Table).to_owned())
|
.drop_table(Table::drop().table(BookPerson::Table).to_owned())
|
||||||
.await.expect("Drop failed");
|
.await
|
||||||
|
.expect("Drop failed");
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookPlace::Table).to_owned())
|
.drop_table(Table::drop().table(BookPlace::Table).to_owned())
|
||||||
.await.expect("Drop failed");
|
.await
|
||||||
|
.expect("Drop failed");
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookSubject::Table).to_owned())
|
.drop_table(Table::drop().table(BookSubject::Table).to_owned())
|
||||||
.await.expect("Drop failed");
|
.await
|
||||||
|
.expect("Drop failed");
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookTime::Table).to_owned())
|
.drop_table(Table::drop().table(BookTime::Table).to_owned())
|
||||||
.await.expect("Drop failed");
|
.await
|
||||||
|
.expect("Drop failed");
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookISBN::Table).to_owned())
|
.drop_table(Table::drop().table(BookISBN::Table).to_owned())
|
||||||
.await
|
.await
|
||||||
@@ -246,6 +291,7 @@ enum Book {
|
|||||||
TimeAdded,
|
TimeAdded,
|
||||||
Rating,
|
Rating,
|
||||||
Comments,
|
Comments,
|
||||||
|
UserId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Iden)]
|
#[derive(Iden)]
|
||||||
@@ -295,3 +341,11 @@ enum BookISBN {
|
|||||||
ISBN,
|
ISBN,
|
||||||
BookId,
|
BookId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum User {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
UserName,
|
||||||
|
PasswordHash,
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ publish = false
|
|||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
entity = { path = "../entity" }
|
entity = { path = "../entity" }
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
|
axum-login = "0.4"
|
||||||
|
axum = "^0.6"
|
||||||
|
eyre = "0.6.8"
|
||||||
|
|
||||||
[dependencies.sea-orm]
|
[dependencies.sea-orm]
|
||||||
version = "^0.9.2" # sea-orm version
|
version = "^0.10.6" # sea-orm version
|
||||||
features = [
|
features = [
|
||||||
"debug-print",
|
"debug-print",
|
||||||
"runtime-tokio-native-tls",
|
"runtime-tokio-native-tls",
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
mod mutation;
|
mod mutation;
|
||||||
mod query;
|
mod query;
|
||||||
|
mod userstore;
|
||||||
|
|
||||||
pub use mutation::*;
|
pub use mutation::*;
|
||||||
pub use query::*;
|
pub use query::*;
|
||||||
|
pub use userstore::*;
|
||||||
|
|
||||||
pub use sea_orm;
|
pub use sea_orm;
|
||||||
|
|||||||
+64
-41
@@ -1,15 +1,40 @@
|
|||||||
//use ::entity::entities::prelude::Book;
|
//use ::entity::entities::prelude::Book;
|
||||||
//use ::entity::entities::{prelude::*, *};
|
//use ::entity::entities::{prelude::*, *};
|
||||||
use ::entity::entities::{book::Entity as Book};
|
use ::entity::entities::book::Entity as Book;
|
||||||
|
use ::entity::entities::user::Entity as User;
|
||||||
//, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN};
|
//, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN};
|
||||||
use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn};
|
use ::entity::entities::{
|
||||||
|
book, book_author, book_isbn, book_person, book_place, book_subject, book_time, user,
|
||||||
|
};
|
||||||
use sea_orm::*;
|
use sea_orm::*;
|
||||||
//use ::entity::entities::prelude::Book;
|
//use ::entity::entities::prelude::Book;
|
||||||
|
|
||||||
pub struct Mutation;
|
pub struct Mutation;
|
||||||
|
|
||||||
impl Mutation {
|
impl Mutation {
|
||||||
pub async fn create_book(
|
pub async fn create_user(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: user::Model,
|
||||||
|
) -> Result<InsertResult<user::ActiveModel>, DbErr> {
|
||||||
|
let record = user::ActiveModel {
|
||||||
|
user_name: Set(form_data.user_name.to_owned()),
|
||||||
|
password_hash: Set(form_data.password_hash.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
User::insert(record).exec(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_user(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
|
let user: user::ActiveModel = User::find_by_id(id)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
.ok_or(DbErr::Custom("Cannot find user.".to_owned()))
|
||||||
|
.map(Into::into)?;
|
||||||
|
|
||||||
|
user.delete(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_book(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book::Model,
|
form_data: book::Model,
|
||||||
) -> Result<InsertResult<book::ActiveModel>, DbErr> {
|
) -> Result<InsertResult<book::ActiveModel>, DbErr> {
|
||||||
@@ -26,12 +51,13 @@ impl Mutation {
|
|||||||
time_added: Set(form_data.time_added.to_owned()),
|
time_added: Set(form_data.time_added.to_owned()),
|
||||||
rating: Set(form_data.rating.to_owned()),
|
rating: Set(form_data.rating.to_owned()),
|
||||||
comments: Set(form_data.comments.to_owned()),
|
comments: Set(form_data.comments.to_owned()),
|
||||||
|
user_id: Set(form_data.user_id.to_owned()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
Book::insert(record).exec(db).await
|
Book::insert(record).exec(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_book_author(
|
pub async fn create_book_author(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book_author::Model,
|
form_data: book_author::Model,
|
||||||
) -> Result<book_author::ActiveModel, DbErr> {
|
) -> Result<book_author::ActiveModel, DbErr> {
|
||||||
@@ -44,7 +70,7 @@ impl Mutation {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_book_person(
|
pub async fn create_book_person(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book_person::Model,
|
form_data: book_person::Model,
|
||||||
) -> Result<book_person::ActiveModel, DbErr> {
|
) -> Result<book_person::ActiveModel, DbErr> {
|
||||||
@@ -57,7 +83,7 @@ impl Mutation {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_book_place(
|
pub async fn create_book_place(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book_place::Model,
|
form_data: book_place::Model,
|
||||||
) -> Result<book_place::ActiveModel, DbErr> {
|
) -> Result<book_place::ActiveModel, DbErr> {
|
||||||
@@ -69,7 +95,7 @@ impl Mutation {
|
|||||||
.save(db)
|
.save(db)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
pub async fn create_book_subject(
|
pub async fn create_book_subject(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book_subject::Model,
|
form_data: book_subject::Model,
|
||||||
) -> Result<book_subject::ActiveModel, DbErr> {
|
) -> Result<book_subject::ActiveModel, DbErr> {
|
||||||
@@ -82,7 +108,7 @@ impl Mutation {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_book_time(
|
pub async fn create_book_time(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book_time::Model,
|
form_data: book_time::Model,
|
||||||
) -> Result<book_time::ActiveModel, DbErr> {
|
) -> Result<book_time::ActiveModel, DbErr> {
|
||||||
@@ -95,7 +121,7 @@ impl Mutation {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_book_isbn(
|
pub async fn create_book_isbn(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: book_isbn::Model,
|
form_data: book_isbn::Model,
|
||||||
) -> Result<book_isbn::ActiveModel, DbErr> {
|
) -> Result<book_isbn::ActiveModel, DbErr> {
|
||||||
@@ -113,7 +139,6 @@ impl Mutation {
|
|||||||
id: i32,
|
id: i32,
|
||||||
form_data: book::Model,
|
form_data: book::Model,
|
||||||
) -> Result<book::Model, DbErr> {
|
) -> Result<book::Model, DbErr> {
|
||||||
|
|
||||||
let book: book::ActiveModel = Book::find_by_id(id)
|
let book: book::ActiveModel = Book::find_by_id(id)
|
||||||
.one(db)
|
.one(db)
|
||||||
.await?
|
.await?
|
||||||
@@ -134,7 +159,10 @@ impl Mutation {
|
|||||||
time_added: Set(form_data.time_added.to_owned()),
|
time_added: Set(form_data.time_added.to_owned()),
|
||||||
rating: Set(form_data.rating.to_owned()),
|
rating: Set(form_data.rating.to_owned()),
|
||||||
comments: Set(form_data.comments.to_owned()),
|
comments: Set(form_data.comments.to_owned()),
|
||||||
}.update(db).await
|
user_id: Set(form_data.user_id.to_owned()),
|
||||||
|
}
|
||||||
|
.update(db)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_book(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
@@ -147,54 +175,49 @@ impl Mutation {
|
|||||||
book.delete(db).await
|
book.delete(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn delete_book_author(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book_author(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
book_author::Entity::delete_many().filter(
|
book_author::Entity::delete_many()
|
||||||
Condition::any()
|
.filter(Condition::any().add(book_author::Column::BookId.eq(id)))
|
||||||
.add(book_author::Column::BookId.eq(id))
|
.exec(db)
|
||||||
).exec(db).await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_book_person(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book_person(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
book_person::Entity::delete_many().filter(
|
book_person::Entity::delete_many()
|
||||||
Condition::any()
|
.filter(Condition::any().add(book_person::Column::BookId.eq(id)))
|
||||||
.add(book_person::Column::BookId.eq(id))
|
.exec(db)
|
||||||
).exec(db).await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn delete_book_place(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book_place(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
book_place::Entity::delete_many().filter(
|
book_place::Entity::delete_many()
|
||||||
Condition::any()
|
.filter(Condition::any().add(book_place::Column::BookId.eq(id)))
|
||||||
.add(book_place::Column::BookId.eq(id))
|
.exec(db)
|
||||||
).exec(db).await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn delete_book_subject(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book_subject(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
book_subject::Entity::delete_many().filter(
|
book_subject::Entity::delete_many()
|
||||||
Condition::any()
|
.filter(Condition::any().add(book_subject::Column::BookId.eq(id)))
|
||||||
.add(book_subject::Column::BookId.eq(id))
|
.exec(db)
|
||||||
).exec(db).await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_book_time(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book_time(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
book_time::Entity::delete_many().filter(
|
book_time::Entity::delete_many()
|
||||||
Condition::any()
|
.filter(Condition::any().add(book_time::Column::BookId.eq(id)))
|
||||||
.add(book_time::Column::BookId.eq(id))
|
.exec(db)
|
||||||
).exec(db).await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub async fn delete_book_isbn(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book_isbn(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
book_isbn::Entity::delete_many().filter(
|
book_isbn::Entity::delete_many()
|
||||||
Condition::any()
|
.filter(Condition::any().add(book_isbn::Column::BookId.eq(id)))
|
||||||
.add(book_isbn::Column::BookId.eq(id))
|
.exec(db)
|
||||||
).exec(db).await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_all_books(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
||||||
pub async fn delete_all_books(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
|
||||||
Book::delete_many().exec(db).await
|
Book::delete_many().exec(db).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+81
-59
@@ -1,34 +1,14 @@
|
|||||||
use ::entity::entities::book::Entity as Book;
|
use ::entity::entities::book::Entity as Book;
|
||||||
|
use ::entity::entities::user::Entity as User;
|
||||||
|
|
||||||
//, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN};
|
//, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN};
|
||||||
use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn};
|
use ::entity::entities::{
|
||||||
|
book, book_author, book_isbn, book_person, book_place, book_subject, book_time, user,
|
||||||
|
};
|
||||||
//use ::entity::entities::{prelude::*, *};
|
//use ::entity::entities::{prelude::*, *};
|
||||||
use sea_orm::*;
|
use sea_orm::*;
|
||||||
//use sea_query::Expr;
|
//use sea_query::Expr;
|
||||||
|
|
||||||
#[derive(FromQueryResult,Clone)]
|
|
||||||
pub struct BookAndMeta {
|
|
||||||
pub id: i32,
|
|
||||||
pub open_library_key: String,
|
|
||||||
pub title: String,
|
|
||||||
pub edition_count: i32,
|
|
||||||
pub first_publish_year: i32,
|
|
||||||
pub median_page_count: i32,
|
|
||||||
pub goodread_id: String,
|
|
||||||
pub description: String,
|
|
||||||
pub cover: String,
|
|
||||||
pub location: String,
|
|
||||||
pub time_added: String,
|
|
||||||
pub rating: i32,
|
|
||||||
pub comments: String,
|
|
||||||
pub author_name: String,
|
|
||||||
pub person: String,
|
|
||||||
pub place: String,
|
|
||||||
pub subject: String,
|
|
||||||
pub time: String,
|
|
||||||
pub isbn: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BookAndMetaV2 {
|
pub struct BookAndMetaV2 {
|
||||||
pub book: book::Model,
|
pub book: book::Model,
|
||||||
@@ -48,62 +28,104 @@ impl Query {
|
|||||||
Book::find_by_id(id).one(db).await
|
Book::find_by_id(id).one(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pub async fn find_bookplusmeta_by_id(db: &DbConn, id: i32) -> Result<Option<(book::Model, Vec<book_author::Model>, Vec<book_person::Model>)>, DbErr> {
|
pub async fn find_userid_by_name(
|
||||||
let book = Book::find_by_id(id).one(db).await?.unwrap();
|
db: &DbConn,
|
||||||
let authors = book.find_related(Author).all(db).await?;
|
name: String,
|
||||||
let persons = book.find_related(Person).all(db).await?;
|
) -> Result<Option<user::Model>, DbErr> {
|
||||||
Ok(Some((book, authors, persons)))
|
User::find()
|
||||||
|
.filter(user::Column::UserName.eq(name))
|
||||||
|
.one(db)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
pub async fn find_user_by_id(db: &DbConn, id: i32) -> Result<Option<user::Model>, DbErr> {
|
||||||
|
User::find_by_id(id).one(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn list_all_users(db: &DbConn) -> Result<Vec<user::Model>, DbErr> {
|
||||||
|
User::find().all(db).await
|
||||||
|
}
|
||||||
|
/* pub async fn find_bookplusmeta_by_id(db: &DbConn, id: i32) -> Result<Option<(book::Model, Vec<book_author::Model>, Vec<book_person::Model>)>, DbErr> {
|
||||||
|
let book = Book::find_by_id(id).one(db).await?.unwrap();
|
||||||
|
let authors = book.find_related(Author).all(db).await?;
|
||||||
|
let persons = book.find_related(Person).all(db).await?;
|
||||||
|
Ok(Some((book, authors, persons)))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// If ok, returns (post models, num pages).
|
/// If ok, returns (post models, num pages).
|
||||||
pub async fn find_books_in_page(
|
pub async fn find_books_in_page(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
page: usize,
|
page: u64,
|
||||||
posts_per_page: usize,
|
posts_per_page: u64,
|
||||||
) -> Result<(Vec<book::Model>, usize), DbErr> {
|
userid: i32,
|
||||||
|
sort: String,
|
||||||
|
) -> Result<(Vec<book::Model>, u64), DbErr> {
|
||||||
// Setup paginator
|
// Setup paginator
|
||||||
let paginator = Book::find()
|
if sort == "desc".to_string() {
|
||||||
.order_by_asc(book::Column::Id)
|
let paginator = Book::find()
|
||||||
.paginate(db, posts_per_page);
|
.filter(book::Column::UserId.eq(userid))
|
||||||
let num_pages = paginator.num_pages().await?;
|
.order_by_desc(book::Column::Id)
|
||||||
|
.paginate(db, posts_per_page);
|
||||||
|
let num_pages = paginator.num_pages().await?;
|
||||||
|
return paginator.fetch_page(page - 1).await.map(|p| (p, num_pages));
|
||||||
|
} else {
|
||||||
|
let paginator = Book::find()
|
||||||
|
.filter(book::Column::UserId.eq(userid))
|
||||||
|
.order_by_asc(book::Column::Id)
|
||||||
|
.paginate(db, posts_per_page);
|
||||||
|
let num_pages = paginator.num_pages().await?;
|
||||||
|
return paginator.fetch_page(page - 1).await.map(|p| (p, num_pages));
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch paginated posts
|
// Fetch paginated posts
|
||||||
paginator.fetch_page(page - 1).await.map(|p| (p, num_pages))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_books_plus_meta_in_page(
|
pub async fn find_books_plus_meta_in_page(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
page: usize,
|
page: usize,
|
||||||
posts_per_page: usize,
|
posts_per_page: usize,
|
||||||
) -> Result<(Vec<BookAndMetaV2>, usize), DbErr> {
|
userid: i32,
|
||||||
|
sort: String,
|
||||||
|
) -> Result<(Vec<BookAndMetaV2>, u64), DbErr> {
|
||||||
// Setup paginator
|
// Setup paginator
|
||||||
let books = Self::find_books_in_page(db,page,posts_per_page).await?;
|
let books = Self::find_books_in_page(
|
||||||
|
db,
|
||||||
|
page.try_into().unwrap(),
|
||||||
|
posts_per_page.try_into().unwrap(),
|
||||||
|
userid,
|
||||||
|
sort,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let book_ids: Vec<i32> = books.0.clone().into_iter().map(|b| b.id).collect();
|
let book_ids: Vec<i32> = books.0.clone().into_iter().map(|b| b.id).collect();
|
||||||
|
println!("SIZE IS {} and {:?}", book_ids.len(), book_ids);
|
||||||
let mut resbooks: Vec<BookAndMetaV2> = Vec::with_capacity(book_ids.len());
|
let mut resbooks: Vec<BookAndMetaV2> = Vec::with_capacity(book_ids.len());
|
||||||
for book in books.0.iter() {
|
for book in books.0.iter() {
|
||||||
let bauthors: Vec<book_author::Model> = book.find_related(book_author::Entity).all(db).await?;
|
let bauthors: Vec<book_author::Model> =
|
||||||
let bpersons: Vec<book_person::Model> = book.find_related(book_person::Entity).all(db).await?;
|
book.find_related(book_author::Entity).all(db).await?;
|
||||||
let bplaces: Vec<book_place::Model> = book.find_related(book_place::Entity).all(db).await?;
|
let bpersons: Vec<book_person::Model> =
|
||||||
let bsubjects: Vec<book_subject::Model> = book.find_related(book_subject::Entity).all(db).await?;
|
book.find_related(book_person::Entity).all(db).await?;
|
||||||
let btimes: Vec<book_time::Model> = book.find_related(book_time::Entity).all(db).await?;
|
let bplaces: Vec<book_place::Model> =
|
||||||
let bisbns: Vec<book_isbn::Model> = book.find_related(book_isbn::Entity).all(db).await?;
|
book.find_related(book_place::Entity).all(db).await?;
|
||||||
|
let bsubjects: Vec<book_subject::Model> =
|
||||||
|
book.find_related(book_subject::Entity).all(db).await?;
|
||||||
|
let btimes: Vec<book_time::Model> =
|
||||||
|
book.find_related(book_time::Entity).all(db).await?;
|
||||||
|
let bisbns: Vec<book_isbn::Model> =
|
||||||
|
book.find_related(book_isbn::Entity).all(db).await?;
|
||||||
|
|
||||||
let bookandmeta = BookAndMetaV2 {
|
let bookandmeta = BookAndMetaV2 {
|
||||||
book: (book.clone()),
|
book: (book.clone()),
|
||||||
authors: bauthors,
|
authors: bauthors,
|
||||||
persons: bpersons,
|
persons: bpersons,
|
||||||
places: bplaces,
|
places: bplaces,
|
||||||
subjects: bsubjects,
|
subjects: bsubjects,
|
||||||
times: btimes,
|
times: btimes,
|
||||||
isbns: bisbns
|
isbns: bisbns,
|
||||||
};
|
};
|
||||||
resbooks.push(bookandmeta);
|
resbooks.push(bookandmeta);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((resbooks,books.1))
|
Ok((resbooks, books.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use crate::Query;
|
||||||
|
use axum::async_trait;
|
||||||
|
use axum_login::{secrecy::SecretVec, AuthUser, UserStore};
|
||||||
|
use sea_orm::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AxumUser {
|
||||||
|
pub id: i32,
|
||||||
|
pub password_hash: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<T = ()> = std::result::Result<T, eyre::Error>;
|
||||||
|
|
||||||
|
impl<Role> AuthUser<Role> for AxumUser
|
||||||
|
where
|
||||||
|
Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn get_id(&self) -> String {
|
||||||
|
format!("{}", self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_password_hash(&self) -> axum_login::secrecy::SecretVec<u8> {
|
||||||
|
SecretVec::new(self.password_hash.clone().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct AxumUserStore {
|
||||||
|
conn: DatabaseConnection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AxumUserStore {
|
||||||
|
pub fn new(conn: &DatabaseConnection) -> Self {
|
||||||
|
Self { conn: conn.clone() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<Role> UserStore<Role> for AxumUserStore
|
||||||
|
where
|
||||||
|
Role: PartialOrd + PartialEq + Clone + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
type User = AxumUser;
|
||||||
|
|
||||||
|
async fn load_user(&self, user_id: &str) -> Result<Option<Self::User>> {
|
||||||
|
// my user id is a Vec<u8>, so it's stored base64 encoded
|
||||||
|
let id: i32 = user_id.parse().unwrap();
|
||||||
|
let user = Query::find_user_by_id(&self.conn, id).await?;
|
||||||
|
match user {
|
||||||
|
Some(u) => Ok(Some(AxumUser {
|
||||||
|
id: u.id,
|
||||||
|
password_hash: u.password_hash,
|
||||||
|
name: u.user_name.unwrap(),
|
||||||
|
})),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-22
@@ -1,6 +1,6 @@
|
|||||||
use meilisearch_sdk::client::*;
|
use meilisearch_sdk::client::*;
|
||||||
use meilisearch_sdk::search::*;
|
use meilisearch_sdk::search::*;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||||
pub struct BookMeili {
|
pub struct BookMeili {
|
||||||
@@ -25,35 +25,37 @@ pub struct BookMeili {
|
|||||||
pub isbn: Vec<String>,
|
pub isbn: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_or_update_book(book: BookMeili, client: &Client) {
|
pub async fn create_or_update_book(book: BookMeili, userid: i32, client: &Client) {
|
||||||
// An index is where the documents are stored.
|
// An index is where the documents are stored.
|
||||||
let books = client.index("books");
|
let books = client.index(format!("books{}", userid));
|
||||||
// Add some movies in the index. If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
|
// Add some movies in the index. If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
|
||||||
books.add_or_replace(&[
|
books.add_or_replace(&[book], Some("id")).await.unwrap();
|
||||||
book
|
|
||||||
], Some("id")).await.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn delete_book(bookid: i32, userid: i32, client: &Client) {
|
||||||
pub async fn delete_book(bookid: i32, client: &Client) {
|
|
||||||
// An index is where the documents are stored.
|
// An index is where the documents are stored.
|
||||||
let books = client.index("books");
|
let books = client.index(format!("books{}", userid));
|
||||||
books.delete_document(bookid).await.unwrap();
|
books.delete_document(bookid).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn search_book(
|
||||||
pub async fn search_book(search: &str, page: usize, client: &Client) -> Result<(Vec<BookMeili>, usize), meilisearch_sdk::errors::Error> {
|
search: &str,
|
||||||
|
page: usize,
|
||||||
|
userid: i32,
|
||||||
|
client: &Client,
|
||||||
|
) -> Result<(Vec<BookMeili>, usize), meilisearch_sdk::errors::Error> {
|
||||||
// An index is where the documents are stored.
|
// An index is where the documents are stored.
|
||||||
let books = client.index("books");
|
let books = client.index(format!("books{}", userid));
|
||||||
let results : SearchResults<BookMeili> = books.search().with_query(search).with_offset((page-1)*12)
|
let results: SearchResults<BookMeili> = books
|
||||||
.execute::<BookMeili>().await.unwrap();
|
.search()
|
||||||
|
.with_query(search)
|
||||||
|
.with_offset((page - 1) * 12)
|
||||||
|
.execute::<BookMeili>()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let formatted_results : Vec<BookMeili> = (results.hits).iter().map(|r| r.result.clone()).collect();
|
let formatted_results: Vec<BookMeili> =
|
||||||
//.iter()s.map(|r| r.formatted_result.unwrap()).collect();
|
(results.hits).iter().map(|r| r.result.clone()).collect();
|
||||||
return Ok((formatted_results, results.estimated_total_hits));
|
//.iter()s.map(|r| r.formatted_result.unwrap()).collect();
|
||||||
|
return Ok((formatted_results, results.estimated_total_hits));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
booksman_api::main();
|
booksman_api::main();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Generated
+2
-50
@@ -136,7 +136,6 @@ dependencies = [
|
|||||||
"serde-wasm-bindgen",
|
"serde-wasm-bindgen",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sycamore",
|
"sycamore",
|
||||||
"sycamore-router",
|
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wasm-logger",
|
"wasm-logger",
|
||||||
@@ -381,22 +380,6 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "minimal-lexical"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nom"
|
|
||||||
version = "7.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
"minimal-lexical",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.13.1"
|
version = "1.13.1"
|
||||||
@@ -565,9 +548,9 @@ checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sycamore"
|
name = "sycamore"
|
||||||
version = "0.8.0"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e4decd3fabbb4cfa8ef4d8b4469c7d35d65555806f6c6642a2733d892472ffa"
|
checksum = "67817393b3c9828db84614f64db9a1ebb94729ce3a3751c41e7ff23d3f8e7f00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -631,31 +614,6 @@ dependencies = [
|
|||||||
"smallvec",
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sycamore-router"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "123b34a150dac877d7bfae82dadfb0c586fd35a8f5fcdf1721dafa079fdc4c40"
|
|
||||||
dependencies = [
|
|
||||||
"sycamore",
|
|
||||||
"sycamore-router-macro",
|
|
||||||
"wasm-bindgen",
|
|
||||||
"web-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sycamore-router-macro"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "92914a2f809b636d245b28d8a734801ecb8ff9c4996bbe6ea4176582e12503eb"
|
|
||||||
dependencies = [
|
|
||||||
"nom",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"unicode-xid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sycamore-web"
|
name = "sycamore-web"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -728,12 +686,6 @@ version = "1.0.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8-width"
|
name = "utf8-width"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|||||||
+3
-3
@@ -23,13 +23,13 @@ wasm-logger = "0.2.0"
|
|||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde-wasm-bindgen = "0.4"
|
serde-wasm-bindgen = "0.4"
|
||||||
sycamore = {version = "0.8.0-beta.7", features = ["suspense"]}
|
sycamore = {version = "0.8.2", features = ["suspense"]}
|
||||||
sycamore-router = "0.8.0-beta.7"
|
#sycamore-router = "0.8.2"
|
||||||
wasm-bindgen = "0.2.79"
|
wasm-bindgen = "0.2.79"
|
||||||
#tokio = {version = "1.21.2", features = ["full"] }
|
#tokio = {version = "1.21.2", features = ["full"] }
|
||||||
#yew = "0.19.3"
|
#yew = "0.19.3"
|
||||||
#yew-router = "0.16.0"
|
#yew-router = "0.16.0"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
features = ["InputEvent", "KeyboardEvent", "Location", "Storage"]
|
features = ["InputEvent", "EventTarget", "MouseEvent", "KeyboardEvent", "Location", "Storage", "Element", "Window", "Document"]
|
||||||
version = "0.3.56"
|
version = "0.3.56"
|
||||||
|
|||||||
@@ -3,5 +3,12 @@ target = "index.html"
|
|||||||
dist = "../dist"
|
dist = "../dist"
|
||||||
public_url = "/assets/"
|
public_url = "/assets/"
|
||||||
|
|
||||||
|
|
||||||
|
[[hooks]]
|
||||||
|
stage = "build"
|
||||||
|
command = "sh"
|
||||||
|
command_arguments = ["-c", "npx tailwindcss -i src/tailwind.css -o $TRUNK_STAGING_DIR/tailwind.css"]
|
||||||
|
|
||||||
|
|
||||||
[[proxy]]
|
[[proxy]]
|
||||||
backend = "http://[::1]:8081/api/"
|
backend = "http://[::1]:8081/api/"
|
||||||
|
|||||||
@@ -36,179 +36,3 @@ body {
|
|||||||
overflow: auto; /* Enable scroll if needed */
|
overflow: auto; /* Enable scroll if needed */
|
||||||
background-color: #f1f1f1; /* Fallback color */
|
background-color: #f1f1f1; /* Fallback color */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Float three header columns side by side */
|
|
||||||
.header {
|
|
||||||
position: fixed; /* Stay in place */
|
|
||||||
overflow: hidden;
|
|
||||||
z-index: 1; /* Sit on top */
|
|
||||||
width: 100%;
|
|
||||||
top: 0; /* Position the navbar at the top of the page */
|
|
||||||
padding: 0 10px;
|
|
||||||
background-color: #f1f1f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
margin-top: 50px; /* Add a top margin to avoid content overlay */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Float three header columns side by side */
|
|
||||||
.header-column {
|
|
||||||
float: left;
|
|
||||||
width: 28%;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
/* Float three header columns side by side */
|
|
||||||
.header-page-column {
|
|
||||||
float: left;
|
|
||||||
margin-top: 0px;
|
|
||||||
width: 15%;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Float four columns side by side */
|
|
||||||
.column {
|
|
||||||
float: left;
|
|
||||||
width: 25%;
|
|
||||||
padding: 0 10px;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove extra left and right margins, due to padding in columns */
|
|
||||||
.row {margin: 0 -5px;}
|
|
||||||
|
|
||||||
/* Clear floats after the columns */
|
|
||||||
.row:after {
|
|
||||||
content: "";
|
|
||||||
display: table;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style the counter cards */
|
|
||||||
.card {
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); /* this adds the "card" effect */
|
|
||||||
padding: 16px;
|
|
||||||
text-align: left;
|
|
||||||
height: 400px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
background-color: #f1f1f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Style the counter cards */
|
|
||||||
.card-openlibrary {
|
|
||||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); /* this adds the "card" effect */
|
|
||||||
padding: 16px;
|
|
||||||
text-align: left;
|
|
||||||
height: 200px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
background-color: #f1f1f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card img {
|
|
||||||
float: right;
|
|
||||||
width: 100px;
|
|
||||||
padding: 0 20px 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-openlibrary img {
|
|
||||||
float: right;
|
|
||||||
width: 100px;
|
|
||||||
padding: 0 20px 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.card-title {
|
|
||||||
padding: 16px;
|
|
||||||
text-align: left;
|
|
||||||
width: 60%;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-authors {
|
|
||||||
padding: 16px;
|
|
||||||
text-align: left;
|
|
||||||
width: 60%;
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-desc {
|
|
||||||
padding: 2px;
|
|
||||||
text-align: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.input-field {
|
|
||||||
padding: 4px;
|
|
||||||
float: left;
|
|
||||||
text-align: left;
|
|
||||||
width: 50%;
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
.input-field label {
|
|
||||||
display: block;
|
|
||||||
vertical-align: middle;
|
|
||||||
min-width: 20%;
|
|
||||||
max-width: 20%;
|
|
||||||
width: 20%;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
.input-field textarea {
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
.input-buttons {
|
|
||||||
padding: 20px;
|
|
||||||
float: left;
|
|
||||||
text-align: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-info {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
.more-info img {
|
|
||||||
float: right;
|
|
||||||
width: 200px;
|
|
||||||
padding: 0 20px 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-info label {
|
|
||||||
display:inline-block;
|
|
||||||
text-align: left;
|
|
||||||
width: 20%;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-info-buttons {
|
|
||||||
padding: 20px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-input {
|
|
||||||
width: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Responsive columns - one column layout (vertical) on small screens */
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
.column {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 800px) {
|
|
||||||
.main {
|
|
||||||
margin-top: 80px; /* Add a top margin to avoid content overlay */
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-field {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+8
-3
@@ -2,9 +2,14 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="shortcut icon" type="image/x-icon" href="data:image/x-icon;,">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link data-trunk rel="css" href="css/index.css" />
|
<link rel="shortcut icon" type="image/x-icon" href="/images/favicon.svg">
|
||||||
<base data-trunk-public-url/>
|
<link data-trunk rel="css" href="css/index.css" />
|
||||||
|
<link data-trunk rel="copy-dir" href="static" />
|
||||||
|
<link rel="stylesheet" href="/assets/tailwind.css"/>
|
||||||
|
<link rel="stylesheet" href="/assets/static/fontawesome/css/fontawesome.css"/>
|
||||||
|
<link rel="stylesheet" href="/assets/static/fontawesome/css/solid.css"/>
|
||||||
|
<base data-trunk-public-url/>
|
||||||
<title>Book Manager</title>
|
<title>Book Manager</title>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body></body>
|
||||||
|
|||||||
Generated
+1368
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
|
"tailwindcss": "^3.2.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
+1771
-489
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
+7946
File diff suppressed because it is too large
Load Diff
+6
File diff suppressed because one or more lines are too long
+1516
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+6369
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||||
|
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
.far,
|
||||||
|
.fa-regular {
|
||||||
|
font-weight: 400; }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||||
|
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 6 Free';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
.fas,
|
||||||
|
.fa-solid {
|
||||||
|
font-weight: 900; }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}
|
||||||
+635
@@ -0,0 +1,635 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:root, :host {
|
||||||
|
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Solid';
|
||||||
|
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Regular';
|
||||||
|
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Light';
|
||||||
|
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Thin';
|
||||||
|
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
|
||||||
|
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
|
||||||
|
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; }
|
||||||
|
|
||||||
|
svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {
|
||||||
|
overflow: visible;
|
||||||
|
box-sizing: content-box; }
|
||||||
|
|
||||||
|
.svg-inline--fa {
|
||||||
|
display: var(--fa-display, inline-block);
|
||||||
|
height: 1em;
|
||||||
|
overflow: visible;
|
||||||
|
vertical-align: -.125em; }
|
||||||
|
.svg-inline--fa.fa-2xs {
|
||||||
|
vertical-align: 0.1em; }
|
||||||
|
.svg-inline--fa.fa-xs {
|
||||||
|
vertical-align: 0em; }
|
||||||
|
.svg-inline--fa.fa-sm {
|
||||||
|
vertical-align: -0.07143em; }
|
||||||
|
.svg-inline--fa.fa-lg {
|
||||||
|
vertical-align: -0.2em; }
|
||||||
|
.svg-inline--fa.fa-xl {
|
||||||
|
vertical-align: -0.25em; }
|
||||||
|
.svg-inline--fa.fa-2xl {
|
||||||
|
vertical-align: -0.3125em; }
|
||||||
|
.svg-inline--fa.fa-pull-left {
|
||||||
|
margin-right: var(--fa-pull-margin, 0.3em);
|
||||||
|
width: auto; }
|
||||||
|
.svg-inline--fa.fa-pull-right {
|
||||||
|
margin-left: var(--fa-pull-margin, 0.3em);
|
||||||
|
width: auto; }
|
||||||
|
.svg-inline--fa.fa-li {
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
top: 0.25em; }
|
||||||
|
.svg-inline--fa.fa-fw {
|
||||||
|
width: var(--fa-fw-width, 1.25em); }
|
||||||
|
|
||||||
|
.fa-layers svg.svg-inline--fa {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0; }
|
||||||
|
|
||||||
|
.fa-layers-text, .fa-layers-counter {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
text-align: center; }
|
||||||
|
|
||||||
|
.fa-layers {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: -.125em;
|
||||||
|
width: 1em; }
|
||||||
|
.fa-layers svg.svg-inline--fa {
|
||||||
|
-webkit-transform-origin: center center;
|
||||||
|
transform-origin: center center; }
|
||||||
|
|
||||||
|
.fa-layers-text {
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
-webkit-transform-origin: center center;
|
||||||
|
transform-origin: center center; }
|
||||||
|
|
||||||
|
.fa-layers-counter {
|
||||||
|
background-color: var(--fa-counter-background-color, #ff253a);
|
||||||
|
border-radius: var(--fa-counter-border-radius, 1em);
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: var(--fa-inverse, #fff);
|
||||||
|
line-height: var(--fa-counter-line-height, 1);
|
||||||
|
max-width: var(--fa-counter-max-width, 5em);
|
||||||
|
min-width: var(--fa-counter-min-width, 1.5em);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--fa-counter-padding, 0.25em 0.5em);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
-webkit-transform: scale(var(--fa-counter-scale, 0.25));
|
||||||
|
transform: scale(var(--fa-counter-scale, 0.25));
|
||||||
|
-webkit-transform-origin: top right;
|
||||||
|
transform-origin: top right; }
|
||||||
|
|
||||||
|
.fa-layers-bottom-right {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
top: auto;
|
||||||
|
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
-webkit-transform-origin: bottom right;
|
||||||
|
transform-origin: bottom right; }
|
||||||
|
|
||||||
|
.fa-layers-bottom-left {
|
||||||
|
bottom: var(--fa-bottom, 0);
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: auto;
|
||||||
|
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
-webkit-transform-origin: bottom left;
|
||||||
|
transform-origin: bottom left; }
|
||||||
|
|
||||||
|
.fa-layers-top-right {
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
right: var(--fa-right, 0);
|
||||||
|
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
-webkit-transform-origin: top right;
|
||||||
|
transform-origin: top right; }
|
||||||
|
|
||||||
|
.fa-layers-top-left {
|
||||||
|
left: var(--fa-left, 0);
|
||||||
|
right: auto;
|
||||||
|
top: var(--fa-top, 0);
|
||||||
|
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
transform: scale(var(--fa-layers-scale, 0.25));
|
||||||
|
-webkit-transform-origin: top left;
|
||||||
|
transform-origin: top left; }
|
||||||
|
|
||||||
|
.fa-1x {
|
||||||
|
font-size: 1em; }
|
||||||
|
|
||||||
|
.fa-2x {
|
||||||
|
font-size: 2em; }
|
||||||
|
|
||||||
|
.fa-3x {
|
||||||
|
font-size: 3em; }
|
||||||
|
|
||||||
|
.fa-4x {
|
||||||
|
font-size: 4em; }
|
||||||
|
|
||||||
|
.fa-5x {
|
||||||
|
font-size: 5em; }
|
||||||
|
|
||||||
|
.fa-6x {
|
||||||
|
font-size: 6em; }
|
||||||
|
|
||||||
|
.fa-7x {
|
||||||
|
font-size: 7em; }
|
||||||
|
|
||||||
|
.fa-8x {
|
||||||
|
font-size: 8em; }
|
||||||
|
|
||||||
|
.fa-9x {
|
||||||
|
font-size: 9em; }
|
||||||
|
|
||||||
|
.fa-10x {
|
||||||
|
font-size: 10em; }
|
||||||
|
|
||||||
|
.fa-2xs {
|
||||||
|
font-size: 0.625em;
|
||||||
|
line-height: 0.1em;
|
||||||
|
vertical-align: 0.225em; }
|
||||||
|
|
||||||
|
.fa-xs {
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 0.08333em;
|
||||||
|
vertical-align: 0.125em; }
|
||||||
|
|
||||||
|
.fa-sm {
|
||||||
|
font-size: 0.875em;
|
||||||
|
line-height: 0.07143em;
|
||||||
|
vertical-align: 0.05357em; }
|
||||||
|
|
||||||
|
.fa-lg {
|
||||||
|
font-size: 1.25em;
|
||||||
|
line-height: 0.05em;
|
||||||
|
vertical-align: -0.075em; }
|
||||||
|
|
||||||
|
.fa-xl {
|
||||||
|
font-size: 1.5em;
|
||||||
|
line-height: 0.04167em;
|
||||||
|
vertical-align: -0.125em; }
|
||||||
|
|
||||||
|
.fa-2xl {
|
||||||
|
font-size: 2em;
|
||||||
|
line-height: 0.03125em;
|
||||||
|
vertical-align: -0.1875em; }
|
||||||
|
|
||||||
|
.fa-fw {
|
||||||
|
text-align: center;
|
||||||
|
width: 1.25em; }
|
||||||
|
|
||||||
|
.fa-ul {
|
||||||
|
list-style-type: none;
|
||||||
|
margin-left: var(--fa-li-margin, 2.5em);
|
||||||
|
padding-left: 0; }
|
||||||
|
.fa-ul > li {
|
||||||
|
position: relative; }
|
||||||
|
|
||||||
|
.fa-li {
|
||||||
|
left: calc(var(--fa-li-width, 2em) * -1);
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
width: var(--fa-li-width, 2em);
|
||||||
|
line-height: inherit; }
|
||||||
|
|
||||||
|
.fa-border {
|
||||||
|
border-color: var(--fa-border-color, #eee);
|
||||||
|
border-radius: var(--fa-border-radius, 0.1em);
|
||||||
|
border-style: var(--fa-border-style, solid);
|
||||||
|
border-width: var(--fa-border-width, 0.08em);
|
||||||
|
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
|
||||||
|
|
||||||
|
.fa-pull-left {
|
||||||
|
float: left;
|
||||||
|
margin-right: var(--fa-pull-margin, 0.3em); }
|
||||||
|
|
||||||
|
.fa-pull-right {
|
||||||
|
float: right;
|
||||||
|
margin-left: var(--fa-pull-margin, 0.3em); }
|
||||||
|
|
||||||
|
.fa-beat {
|
||||||
|
-webkit-animation-name: fa-beat;
|
||||||
|
animation-name: fa-beat;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||||
|
|
||||||
|
.fa-bounce {
|
||||||
|
-webkit-animation-name: fa-bounce;
|
||||||
|
animation-name: fa-bounce;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
|
||||||
|
|
||||||
|
.fa-fade {
|
||||||
|
-webkit-animation-name: fa-fade;
|
||||||
|
animation-name: fa-fade;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||||
|
|
||||||
|
.fa-beat-fade {
|
||||||
|
-webkit-animation-name: fa-beat-fade;
|
||||||
|
animation-name: fa-beat-fade;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
|
||||||
|
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||||
|
|
||||||
|
.fa-flip {
|
||||||
|
-webkit-animation-name: fa-flip;
|
||||||
|
animation-name: fa-flip;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||||
|
|
||||||
|
.fa-shake {
|
||||||
|
-webkit-animation-name: fa-shake;
|
||||||
|
animation-name: fa-shake;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||||
|
|
||||||
|
.fa-spin {
|
||||||
|
-webkit-animation-name: fa-spin;
|
||||||
|
animation-name: fa-spin;
|
||||||
|
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
animation-delay: var(--fa-animation-delay, 0s);
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 2s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 2s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
|
||||||
|
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||||
|
|
||||||
|
.fa-spin-reverse {
|
||||||
|
--fa-animation-direction: reverse; }
|
||||||
|
|
||||||
|
.fa-pulse,
|
||||||
|
.fa-spin-pulse {
|
||||||
|
-webkit-animation-name: fa-spin;
|
||||||
|
animation-name: fa-spin;
|
||||||
|
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
animation-direction: var(--fa-animation-direction, normal);
|
||||||
|
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
animation-duration: var(--fa-animation-duration, 1s);
|
||||||
|
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||||
|
-webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
|
||||||
|
animation-timing-function: var(--fa-animation-timing, steps(8)); }
|
||||||
|
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.fa-beat,
|
||||||
|
.fa-bounce,
|
||||||
|
.fa-fade,
|
||||||
|
.fa-beat-fade,
|
||||||
|
.fa-flip,
|
||||||
|
.fa-pulse,
|
||||||
|
.fa-shake,
|
||||||
|
.fa-spin,
|
||||||
|
.fa-spin-pulse {
|
||||||
|
-webkit-animation-delay: -1ms;
|
||||||
|
animation-delay: -1ms;
|
||||||
|
-webkit-animation-duration: 1ms;
|
||||||
|
animation-duration: 1ms;
|
||||||
|
-webkit-animation-iteration-count: 1;
|
||||||
|
animation-iteration-count: 1;
|
||||||
|
transition-delay: 0s;
|
||||||
|
transition-duration: 0s; } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-beat {
|
||||||
|
0%, 90% {
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1); }
|
||||||
|
45% {
|
||||||
|
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
|
||||||
|
transform: scale(var(--fa-beat-scale, 1.25)); } }
|
||||||
|
|
||||||
|
@keyframes fa-beat {
|
||||||
|
0%, 90% {
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1); }
|
||||||
|
45% {
|
||||||
|
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
|
||||||
|
transform: scale(var(--fa-beat-scale, 1.25)); } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-bounce {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(0);
|
||||||
|
transform: scale(1, 1) translateY(0); }
|
||||||
|
10% {
|
||||||
|
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
|
||||||
|
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
|
||||||
|
30% {
|
||||||
|
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
|
||||||
|
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
|
||||||
|
50% {
|
||||||
|
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
|
||||||
|
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
|
||||||
|
57% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
|
||||||
|
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
|
||||||
|
64% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(0);
|
||||||
|
transform: scale(1, 1) translateY(0); }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(0);
|
||||||
|
transform: scale(1, 1) translateY(0); } }
|
||||||
|
|
||||||
|
@keyframes fa-bounce {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(0);
|
||||||
|
transform: scale(1, 1) translateY(0); }
|
||||||
|
10% {
|
||||||
|
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
|
||||||
|
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
|
||||||
|
30% {
|
||||||
|
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
|
||||||
|
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
|
||||||
|
50% {
|
||||||
|
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
|
||||||
|
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
|
||||||
|
57% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
|
||||||
|
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
|
||||||
|
64% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(0);
|
||||||
|
transform: scale(1, 1) translateY(0); }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: scale(1, 1) translateY(0);
|
||||||
|
transform: scale(1, 1) translateY(0); } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-fade {
|
||||||
|
50% {
|
||||||
|
opacity: var(--fa-fade-opacity, 0.4); } }
|
||||||
|
|
||||||
|
@keyframes fa-fade {
|
||||||
|
50% {
|
||||||
|
opacity: var(--fa-fade-opacity, 0.4); } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-beat-fade {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1); }
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
|
||||||
|
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
|
||||||
|
|
||||||
|
@keyframes fa-beat-fade {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1); }
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
|
||||||
|
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-flip {
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
|
||||||
|
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
|
||||||
|
|
||||||
|
@keyframes fa-flip {
|
||||||
|
50% {
|
||||||
|
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
|
||||||
|
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-shake {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(-15deg);
|
||||||
|
transform: rotate(-15deg); }
|
||||||
|
4% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg); }
|
||||||
|
8%, 24% {
|
||||||
|
-webkit-transform: rotate(-18deg);
|
||||||
|
transform: rotate(-18deg); }
|
||||||
|
12%, 28% {
|
||||||
|
-webkit-transform: rotate(18deg);
|
||||||
|
transform: rotate(18deg); }
|
||||||
|
16% {
|
||||||
|
-webkit-transform: rotate(-22deg);
|
||||||
|
transform: rotate(-22deg); }
|
||||||
|
20% {
|
||||||
|
-webkit-transform: rotate(22deg);
|
||||||
|
transform: rotate(22deg); }
|
||||||
|
32% {
|
||||||
|
-webkit-transform: rotate(-12deg);
|
||||||
|
transform: rotate(-12deg); }
|
||||||
|
36% {
|
||||||
|
-webkit-transform: rotate(12deg);
|
||||||
|
transform: rotate(12deg); }
|
||||||
|
40%, 100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg); } }
|
||||||
|
|
||||||
|
@keyframes fa-shake {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(-15deg);
|
||||||
|
transform: rotate(-15deg); }
|
||||||
|
4% {
|
||||||
|
-webkit-transform: rotate(15deg);
|
||||||
|
transform: rotate(15deg); }
|
||||||
|
8%, 24% {
|
||||||
|
-webkit-transform: rotate(-18deg);
|
||||||
|
transform: rotate(-18deg); }
|
||||||
|
12%, 28% {
|
||||||
|
-webkit-transform: rotate(18deg);
|
||||||
|
transform: rotate(18deg); }
|
||||||
|
16% {
|
||||||
|
-webkit-transform: rotate(-22deg);
|
||||||
|
transform: rotate(-22deg); }
|
||||||
|
20% {
|
||||||
|
-webkit-transform: rotate(22deg);
|
||||||
|
transform: rotate(22deg); }
|
||||||
|
32% {
|
||||||
|
-webkit-transform: rotate(-12deg);
|
||||||
|
transform: rotate(-12deg); }
|
||||||
|
36% {
|
||||||
|
-webkit-transform: rotate(12deg);
|
||||||
|
transform: rotate(12deg); }
|
||||||
|
40%, 100% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg); } }
|
||||||
|
|
||||||
|
@-webkit-keyframes fa-spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg); }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg); } }
|
||||||
|
|
||||||
|
@keyframes fa-spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg); }
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg);
|
||||||
|
transform: rotate(360deg); } }
|
||||||
|
|
||||||
|
.fa-rotate-90 {
|
||||||
|
-webkit-transform: rotate(90deg);
|
||||||
|
transform: rotate(90deg); }
|
||||||
|
|
||||||
|
.fa-rotate-180 {
|
||||||
|
-webkit-transform: rotate(180deg);
|
||||||
|
transform: rotate(180deg); }
|
||||||
|
|
||||||
|
.fa-rotate-270 {
|
||||||
|
-webkit-transform: rotate(270deg);
|
||||||
|
transform: rotate(270deg); }
|
||||||
|
|
||||||
|
.fa-flip-horizontal {
|
||||||
|
-webkit-transform: scale(-1, 1);
|
||||||
|
transform: scale(-1, 1); }
|
||||||
|
|
||||||
|
.fa-flip-vertical {
|
||||||
|
-webkit-transform: scale(1, -1);
|
||||||
|
transform: scale(1, -1); }
|
||||||
|
|
||||||
|
.fa-flip-both,
|
||||||
|
.fa-flip-horizontal.fa-flip-vertical {
|
||||||
|
-webkit-transform: scale(-1, -1);
|
||||||
|
transform: scale(-1, -1); }
|
||||||
|
|
||||||
|
.fa-rotate-by {
|
||||||
|
-webkit-transform: rotate(var(--fa-rotate-angle, none));
|
||||||
|
transform: rotate(var(--fa-rotate-angle, none)); }
|
||||||
|
|
||||||
|
.fa-stack {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
height: 2em;
|
||||||
|
position: relative;
|
||||||
|
width: 2.5em; }
|
||||||
|
|
||||||
|
.fa-stack-1x,
|
||||||
|
.fa-stack-2x {
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
margin: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: var(--fa-stack-z-index, auto); }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-1x {
|
||||||
|
height: 1em;
|
||||||
|
width: 1.25em; }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-stack-2x {
|
||||||
|
height: 2em;
|
||||||
|
width: 2.5em; }
|
||||||
|
|
||||||
|
.fa-inverse {
|
||||||
|
color: var(--fa-inverse, #fff); }
|
||||||
|
|
||||||
|
.sr-only,
|
||||||
|
.fa-sr-only {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border-width: 0; }
|
||||||
|
|
||||||
|
.sr-only-focusable:not(:focus),
|
||||||
|
.fa-sr-only-focusable:not(:focus) {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
padding: 0;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0, 0, 0, 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
border-width: 0; }
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-primary {
|
||||||
|
fill: var(--fa-primary-color, currentColor);
|
||||||
|
opacity: var(--fa-primary-opacity, 1); }
|
||||||
|
|
||||||
|
.svg-inline--fa .fa-secondary {
|
||||||
|
fill: var(--fa-secondary-color, currentColor);
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||||
|
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||||
|
|
||||||
|
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||||
|
opacity: var(--fa-primary-opacity, 1); }
|
||||||
|
|
||||||
|
.svg-inline--fa mask .fa-primary,
|
||||||
|
.svg-inline--fa mask .fa-secondary {
|
||||||
|
fill: black; }
|
||||||
|
|
||||||
|
.fad.fa-inverse,
|
||||||
|
.fa-duotone.fa-inverse {
|
||||||
|
color: var(--fa-inverse, #fff); }
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,26 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
|
||||||
|
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'FontAwesome';
|
||||||
|
font-display: block;
|
||||||
|
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
|
||||||
|
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
||||||
+2194
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,22 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 5 Brands';
|
||||||
|
font-display: block;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 5 Free';
|
||||||
|
font-display: block;
|
||||||
|
font-weight: 900;
|
||||||
|
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Font Awesome 5 Free';
|
||||||
|
font-display: block;
|
||||||
|
font-weight: 400;
|
||||||
|
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2022 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,13 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
'./src/**/*.rs',
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/forms'),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user