Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(interface): dedicated create and edit library pages #113

Merged
merged 10 commits into from
Apr 9, 2023
Merged
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
"editor.defaultFormatter": "rust-lang.rust-analyzer"
},
"tailwindCSS.experimental.classRegex": [["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]],
"tailwindCSS.classAttributes": ["class", "className", ".*CLASSES", ".*VARIANTS"]
"tailwindCSS.classAttributes": ["class", "className", ".*CLASSES", ".*VARIANTS"],
"typescript.tsdk": "node_modules/typescript/lib"
}
53 changes: 21 additions & 32 deletions apps/desktop/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,34 +1,23 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": [
"vite/client"
],
"outDir": "../../.moon/cache/types/apps/desktop",
"paths": {
"@stump/client": [
"../../packages/client/src/index.ts"
],
"@stump/client/*": [
"../../packages/client/src/*"
],
"@stump/interface": [
"../../packages/interface/src/index.ts"
],
"@stump/interface/*": [
"../../packages/interface/src/*"
]
}
},
"include": [
"src"
],
"references": [
{
"path": "../../packages/client"
},
{
"path": "../../packages/interface"
}
]
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["vite/client"],
"jsx": "preserve",
"outDir": "../../.moon/cache/types/apps/desktop",
"paths": {
"@stump/client": ["../../packages/client/src/index.ts"],
"@stump/client/*": ["../../packages/client/src/*"],
"@stump/interface": ["../../packages/interface/src/index.ts"],
"@stump/interface/*": ["../../packages/interface/src/*"]
}
},
"include": ["src"],
"references": [
{
"path": "../../packages/client"
},
{
"path": "../../packages/interface"
}
]
}
31 changes: 24 additions & 7 deletions apps/server/src/routers/api/v1/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::{path, str::FromStr};
use tracing::{debug, error, trace};

use stump_core::{
config::get_config_dir,
db::{
models::{
library_series_ids_media_ids_include, LibrariesStats, Library,
Expand All @@ -21,8 +22,8 @@ use stump_core::{
fs::{image, media_file},
job::LibraryScanJob,
prelude::{
CreateLibraryArgs, Pageable, Pagination, PaginationQuery, ScanQueryParam,
UpdateLibraryArgs,
ContentType, CreateLibraryArgs, Pageable, Pagination, PaginationQuery,
ScanQueryParam, UpdateLibraryArgs,
},
prisma::{
library::{self, WhereParam},
Expand Down Expand Up @@ -336,16 +337,32 @@ async fn get_library_thumbnail(
) -> ApiResult<ImageResponse> {
let db = ctx.get_db();

let webp_path = get_config_dir()
.join("thumbnails")
.join(format!("{}.webp", id));

if webp_path.exists() {
trace!("Found webp thumbnail for library {}", id);
return Ok((ContentType::WEBP, image::get_bytes(webp_path)?).into());
}

let library_series = db
.series()
.find_many(vec![series::library_id::equals(Some(id.clone()))])
.with(series::media::fetch(vec![]).order_by(media::name::order(Direction::Asc)))
.find_first(vec![series::library_id::equals(Some(id.clone()))])
.with(
series::media::fetch(vec![])
.take(1)
.order_by(media::name::order(Direction::Asc)),
)
.exec()
.await?;

// TODO: error handling
let series = library_series.first().expect("No series in library");
let media = series.media()?.first().expect("No media in series");
let series = library_series.ok_or_else(|| {
ApiError::NotFound("Library has no series to get thumbnail from".to_string())
})?;
let media = series.media()?.first().ok_or_else(|| {
ApiError::NotFound("Library has no media to get thumbnail from".to_string())
})?;

Ok(media_file::get_page(media.path.as_str(), 1)?.into())
}
Expand Down
1 change: 1 addition & 0 deletions apps/web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"types": [
"vite/client"
],
"jsx": "preserve",
"outDir": "../../.moon/cache/types/apps/web",
"paths": {
"@stump/client": [
Expand Down
5 changes: 4 additions & 1 deletion core/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ pub async fn create_client() -> prisma::PrismaClient {
.to_string();

let profile = std::env::var("STUMP_PROFILE").unwrap_or_else(|_| "debug".to_string());
let db_override = std::env::var("STUMP_DB_PATH").ok();

if profile == "release" {
if let Some(path) = db_override {
create_client_with_url(&format!("file:{}/stump.db", &path)).await
} else if profile == "release" {
trace!(
"Creating Prisma client with url: file:{}/stump.db",
&config_dir
Expand Down
4 changes: 2 additions & 2 deletions packages/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// TODO: remove these export *
export { authApi, authQueryKeys } from './auth'
export { API, apiIsInitialized, checkUrl, initializeApi, isUrl } from './axios'
export { epubApi, epubQueryKeys } from './epub'
export { epubApi, epubQueryKeys, getEpubResource } from './epub'
export { filesystemApi, filesystemQueryKeys } from './filesystem'
export * from './job'
export { libraryApi, libraryQueryKeys } from './library'
export { getLibraryThumbnail, libraryApi, libraryQueryKeys } from './library'
export * from './log'
export { getMediaPage, getMediaThumbnail, mediaApi, mediaQueryKeys } from './media'
export {
Expand Down
4 changes: 4 additions & 0 deletions packages/api/src/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export function getLibraryById(id: string): Promise<ApiResult<Library>> {
return API.get(`/libraries/${id}`)
}

export function getLibraryThumbnail(id: string): string {
return `${API.defaults.baseURL}/libraries/${id}/thumbnail`
}

export function getLibrarySeries(
id: string,
page: number,
Expand Down
11 changes: 4 additions & 7 deletions packages/client/src/queries/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,14 @@ import { useQueryParamStore } from '../stores'
export const refreshUseLibrary = (id: string) =>
invalidateQueries({ exact: true, queryKey: [libraryQueryKeys.getLibraryById, id] })

export function useLibrary(id: string, { enabled, ...options }: QueryOptions<Library> = {}) {
const { isLoading, data: library } = useQuery(
export function useLibraryByIdQuery(id: string, options?: QueryOptions<Library>) {
const { data, ...rest } = useQuery(
[libraryQueryKeys.getLibraryById, id],
() => libraryApi.getLibraryById(id).then((res) => res.data),
{
enabled: !!id || !!enabled,
...options,
},
options,
)

return { isLoading, library }
return { library: data, ...rest }
}

export interface UseLibrariesReturn {
Expand Down
3 changes: 0 additions & 3 deletions packages/components/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Components

> :warning: **This package is very early in development and is not actually ready for usage in Stump.**
> Once it is ready, Chakra UI will be phased out in favor of this package.

This package is the component library used throughout the Stump web and desktop interface(s). A vast majority of the foundational components come from [shadcn/ui](https://ui.shadcn.com/docs), a wonderful free and open source collection of React components build with [radix-ui](https://radix-ui.com/) and [TailwindCSS](https://tailwindcss.com/). Huge thanks to [shadcn](https://github.com/shadcn) for their work!

## Usage
Expand Down
2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,4 @@
"typescript": "^4.9.5",
"webpack": "5.76.3"
}
}
}
2 changes: 1 addition & 1 deletion packages/components/src/alert/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { type AlertProps, Alert } from './Alert'
export { Alert, type AlertProps } from './Alert'
3 changes: 3 additions & 0 deletions packages/components/src/badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import { cn } from '../utils'

export const BADGE_VARIANTS = {
default: 'bg-gray-100 dark:bg-gray-800 text-gray-800 dark:text-gray-100',
error: 'bg-red-100 text-red-800 dark:bg-red-700 dark:text-red-50',
primary: 'bg-brand-100 text-brand-800 dark:bg-brand-700 dark:text-brand-50',
secondary: 'bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-100',
success: 'bg-green-100 text-green-800 dark:bg-green-700 dark:text-green-50',
warning: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-700 dark:text-yellow-50',
}

const badgeVariants = cva('inline-flex items-center font-medium', {
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/badge/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { type BadgeProps, Badge } from './Badge'
export { Badge, type BadgeProps } from './Badge'
6 changes: 3 additions & 3 deletions packages/components/src/button/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { type ButtonProps, Button } from './Button'
export { type ButtonOrLinkProps, ButtonOrLink } from './ButtonOrLink'
export { type IconButtonProps, IconButton } from './IconButton'
export { Button, type ButtonProps } from './Button'
export { ButtonOrLink, type ButtonOrLinkProps } from './ButtonOrLink'
export { IconButton, type IconButtonProps } from './IconButton'
2 changes: 1 addition & 1 deletion packages/components/src/card/Card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default {
} as ComponentMeta<typeof Card>

const DemoChild = () => (
<div className="flex flex-col space-y-3 py-4 px-6 dark:text-gray-100">
<div className="flex flex-col space-y-3 px-6 py-4 dark:text-gray-100">
<div className="flex w-full items-center justify-between">
<span className="flex items-center space-x-3">
<Library className="h-5 w-5" />
Expand Down
18 changes: 17 additions & 1 deletion packages/components/src/card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// CardContent
// CardOverlay

import React from 'react'
import React, { forwardRef } from 'react'

import { cn } from '../utils'

Expand All @@ -22,3 +22,19 @@ export const Card = React.forwardRef<React.ElementRef<'div'>, CardProps>(
},
)
Card.displayName = 'Card'

export const CardGrid = forwardRef<HTMLDivElement, React.ComponentPropsWithoutRef<'div'>>(
({ className, ...props }, ref) => {
return (
<div
ref={ref}
className={cn(
'4xl:grid-cols-8 grid grid-cols-2 items-start justify-center gap-4 sm:grid-cols-3 md:justify-start lg:grid-cols-4 xl:grid-cols-5 xl:gap-4 2xl:grid-cols-7 2xl:gap-2',
className,
)}
{...props}
/>
)
},
)
CardGrid.displayName = 'CardGrid'
1 change: 0 additions & 1 deletion packages/components/src/card/EntityCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
import { cva, VariantProps } from 'class-variance-authority'
import React, { forwardRef, Fragment } from 'react'
import { Link } from 'react-router-dom'
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/card/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { type CardProps, Card } from './Card'
export { Card, CardGrid, type CardProps } from './Card'
export { EntityCard } from './EntityCard'
export { type HoverCardProps, HoverCard } from './HoverCard'
export { HoverCard, type HoverCardProps } from './HoverCard'
2 changes: 1 addition & 1 deletion packages/components/src/command/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { type CommandProps, Command } from './primitives'
export { Command, type CommandProps } from './primitives'
4 changes: 2 additions & 2 deletions packages/components/src/command/primitives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const CommandGroup = React.forwardRef<
<CommandPrimitive.Group
ref={ref}
className={cn(
'overflow-hidden py-3 px-2 text-gray-800 dark:text-gray-400 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pb-1.5 [&_[cmdk-group-heading]]:text-sm [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-gray-900 [&_[cmdk-group-heading]]:dark:text-gray-300',
'overflow-hidden px-2 py-3 text-gray-800 dark:text-gray-400 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:pb-1.5 [&_[cmdk-group-heading]]:text-sm [&_[cmdk-group-heading]]:font-semibold [&_[cmdk-group-heading]]:text-gray-900 [&_[cmdk-group-heading]]:dark:text-gray-300',
className,
)}
{...props}
Expand Down Expand Up @@ -115,7 +115,7 @@ const CommandItem = React.forwardRef<
<CommandPrimitive.Item
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-md py-1.5 px-2 text-sm font-medium outline-none aria-selected:bg-gray-75 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:aria-selected:bg-gray-700',
'relative flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm font-medium outline-none aria-selected:bg-gray-75 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:aria-selected:bg-gray-700',
className,
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/context-menu/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { type ContextMenuProps, ContextMenu } from './ContextMenu'
export { ContextMenu, type ContextMenuProps } from './ContextMenu'
4 changes: 2 additions & 2 deletions packages/components/src/context-menu/primitives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const ContextMenuPrimitiveSubTrigger = React.forwardRef<
<ContextMenu.SubTrigger
ref={ref}
className={cn(
'flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-gray-75 data-[state=open]:bg-gray-75 dark:focus:bg-gray-700 dark:data-[state=open]:bg-gray-700',
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm font-medium outline-none focus:bg-gray-75 data-[state=open]:bg-gray-75 dark:focus:bg-gray-700 dark:data-[state=open]:bg-gray-700',
inset && 'pl-8',
className,
)}
Expand Down Expand Up @@ -76,7 +76,7 @@ const ContextMenuPrimitiveItem = React.forwardRef<
<ContextMenu.Item
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-gray-75 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-700',
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm font-medium outline-none focus:bg-gray-75 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-700',
inset && 'pl-8',
className,
)}
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/dialog/primitives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const DialogOverlay = React.forwardRef<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
className={cn(
'fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out',
'fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=closed]:fade-out data-[state=open]:fade-in',
className,
)}
{...props}
Expand Down Expand Up @@ -119,7 +119,7 @@ const DialogClose = React.forwardRef<
<DialogPrimitive.Close
ref={ref}
className={cn(
'absolute top-4 right-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-brand-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 dark:text-gray-100 dark:focus:ring-brand-400 dark:focus:ring-offset-gray-900 dark:data-[state=open]:bg-gray-800',
'absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-brand-400 focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-gray-100 dark:text-gray-100 dark:focus:ring-brand-400 dark:focus:ring-offset-gray-900 dark:data-[state=open]:bg-gray-800',
className,
)}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/dropdown/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Button } from '../button/Button'
import { cn } from '../utils'
import { GenericMenu } from '.'
import {
type DropdownContentProps,
Dropdown,
DropdownContent,
type DropdownContentProps,
DropdownGroup,
DropdownItem,
DropdownLabel,
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/dropdown/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { type DropdownMenuProps, DropdownMenu } from './DropdownMenu'
export { DropdownMenu, type DropdownMenuProps } from './DropdownMenu'
export {
Dropdown,
DropdownCheckboxItem,
Expand Down
6 changes: 3 additions & 3 deletions packages/components/src/dropdown/primitives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const DropdownSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
'flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-gray-75 data-[state=open]:bg-gray-100/80 dark:focus:bg-gray-700 dark:data-[state=open]:bg-gray-650/75',
'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm font-medium outline-none focus:bg-gray-75 data-[state=open]:bg-gray-100/80 dark:focus:bg-gray-700 dark:data-[state=open]:bg-gray-650/75',
inset && 'pl-8',
className,
)}
Expand Down Expand Up @@ -64,7 +64,7 @@ const DropdownContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-gray-100 bg-white p-1 text-gray-800 shadow-md animate-in data-[side=right]:slide-in-from-left-2 data-[side=left]:slide-in-from-right-2 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-150',
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-gray-100 bg-white p-1 text-gray-800 shadow-md animate-in data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-gray-800 dark:bg-gray-800 dark:text-gray-150',
className,
)}
{...props}
Expand All @@ -82,7 +82,7 @@ const DropdownItem = React.forwardRef<
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
'relative flex cursor-default select-none items-center rounded-sm py-1.5 px-2 text-sm font-medium outline-none focus:bg-gray-75 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-700',
'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm font-medium outline-none focus:bg-gray-75 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-gray-700',
inset && 'pl-8',
className,
)}
Expand Down
Loading