feat: initialize thoughts-frontend with Next.js, TypeScript, and ESLint

- Add ESLint configuration for Next.js and TypeScript support.
- Create Next.js configuration file with standalone output option.
- Initialize package.json with scripts for development, build, and linting.
- Set up PostCSS configuration for Tailwind CSS.
- Add SVG assets for UI components.
- Create TypeScript configuration for strict type checking and module resolution.
This commit is contained in:
2025-09-05 17:14:45 +02:00
parent 6bd06ff2c8
commit e5747eaaf3
104 changed files with 7484 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
use axum::{extract::rejection::JsonRejection, http::StatusCode};
use sea_orm::DbErr;
use app::error::UserError;
use super::traits::HTTPError;
impl HTTPError for JsonRejection {
fn to_status_code(&self) -> StatusCode {
match self {
JsonRejection::JsonSyntaxError(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::BAD_REQUEST,
}
}
}
impl HTTPError for DbErr {
fn to_status_code(&self) -> StatusCode {
match self {
DbErr::ConnectionAcquire(_) => StatusCode::INTERNAL_SERVER_ERROR,
_ => StatusCode::INTERNAL_SERVER_ERROR, // TODO:: more granularity
}
}
}
impl HTTPError for UserError {
fn to_status_code(&self) -> StatusCode {
match self {
UserError::NotFound => StatusCode::NOT_FOUND,
}
}
}

View File

@@ -0,0 +1,10 @@
pub struct ApiError(pub(super) anyhow::Error);
impl<E> From<E> for ApiError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}

View File

@@ -0,0 +1,36 @@
use axum::{
extract::rejection::JsonRejection,
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use sea_orm::DbErr;
use app::error::UserError;
use super::{ApiError, HTTPError};
use crate::models::ApiErrorResponse;
impl IntoResponse for ApiError {
fn into_response(self) -> Response {
let err = self.0;
let (status, message) = if let Some(err) = err.downcast_ref::<DbErr>() {
tracing::error!(%err, "error from db:");
(err.to_status_code(), "DB error".to_string()) // hide the detail
} else if let Some(err) = err.downcast_ref::<UserError>() {
(err.to_status_code(), err.to_string())
} else if let Some(err) = err.downcast_ref::<JsonRejection>() {
tracing::error!(%err, "error from extractor:");
(err.to_status_code(), err.to_string())
} else {
tracing::error!(%err, "error from other source:");
(
StatusCode::INTERNAL_SERVER_ERROR,
"Unknown error".to_string(),
)
};
(status, Json(ApiErrorResponse { message })).into_response()
}
}

View File

@@ -0,0 +1,7 @@
mod adapter;
mod core;
mod handler;
mod traits;
pub use core::ApiError;
pub use traits::HTTPError;

View File

@@ -0,0 +1,5 @@
use axum::http::StatusCode;
pub trait HTTPError {
fn to_status_code(&self) -> StatusCode;
}