diff --git a/app/controllers/shared_collections_controller.ts b/app/controllers/shared_collections_controller.ts new file mode 100644 index 0000000..ac94ddf --- /dev/null +++ b/app/controllers/shared_collections_controller.ts @@ -0,0 +1,24 @@ +import { Visibility } from '#enums/visibility'; +import Collection from '#models/collection'; +import { getSharedCollectionValidator } from '#validators/shared_collection'; +import type { HttpContext } from '@adonisjs/core/http'; + +export default class SharedCollectionsController { + async index({ request, inertia }: HttpContext) { + const { params } = await request.validateUsing( + getSharedCollectionValidator + ); + + const collection = await this.getSharedCollectionById(params.id); + return inertia.render('shared', { collection }); + } + + private async getSharedCollectionById(id: Collection['id']) { + return await Collection.query() + .where('id', id) + .andWhere('visibility', Visibility.PUBLIC) + .preload('links') + .preload('author') + .firstOrFail(); + } +} diff --git a/app/models/collection.ts b/app/models/collection.ts index ac610d6..33e9853 100644 --- a/app/models/collection.ts +++ b/app/models/collection.ts @@ -21,7 +21,7 @@ export default class Collection extends AppBaseModel { @column() declare authorId: number; - @belongsTo(() => User, { foreignKey: 'author_id' }) + @belongsTo(() => User, { foreignKey: 'authorId' }) declare author: BelongsTo; @hasMany(() => Link) diff --git a/app/validators/shared_collection.ts b/app/validators/shared_collection.ts new file mode 100644 index 0000000..4b580eb --- /dev/null +++ b/app/validators/shared_collection.ts @@ -0,0 +1,11 @@ +import vine from '@vinejs/vine'; + +const params = vine.object({ + id: vine.number(), +}); + +export const getSharedCollectionValidator = vine.compile( + vine.object({ + params, + }) +); diff --git a/inertia/components/dashboard/collection/collection_container.tsx b/inertia/components/dashboard/collection/collection_container.tsx index b2a80ff..9c75e79 100644 --- a/inertia/components/dashboard/collection/collection_container.tsx +++ b/inertia/components/dashboard/collection/collection_container.tsx @@ -7,9 +7,10 @@ import Footer from '~/components/footer/footer'; import useActiveCollection from '~/hooks/use_active_collection'; export interface CollectionHeaderProps { - openNavigationItem: ReactNode; - openCollectionItem: ReactNode; showButtons: boolean; + showControls?: boolean; + openNavigationItem?: ReactNode; + openCollectionItem?: ReactNode; } const CollectionContainerStyle = styled.div({ diff --git a/inertia/components/dashboard/collection/header/collection_header.tsx b/inertia/components/dashboard/collection/header/collection_header.tsx index 6e37bb5..b947130 100644 --- a/inertia/components/dashboard/collection/header/collection_header.tsx +++ b/inertia/components/dashboard/collection/header/collection_header.tsx @@ -15,7 +15,7 @@ const CollectionHeaderWrapper = styled.div(({ theme }) => ({ minWidth: 0, width: '100%', paddingInline: `${paddingLeft} ${paddingRight}`, - marginBottom: 0, + marginBottom: '0.5em', [`@media (max-width: ${theme.media.tablet})`]: { paddingInline: 0, @@ -53,9 +53,10 @@ const LinksCount = styled.div(({ theme }) => ({ })); export default function CollectionHeader({ + showButtons, + showControls = true, openNavigationItem, openCollectionItem, - showButtons, }: CollectionHeaderProps) { const { t } = useTranslation('common'); const { activeCollection } = useActiveCollection(); @@ -75,7 +76,9 @@ export default function CollectionHeader({ visibility={visibility} /> - + {showControls && ( + + )} {showButtons && openCollectionItem && openCollectionItem} {activeCollection.description && } diff --git a/inertia/components/dashboard/link/link_list.tsx b/inertia/components/dashboard/link/link_list.tsx index e3a7716..e57326c 100644 --- a/inertia/components/dashboard/link/link_list.tsx +++ b/inertia/components/dashboard/link/link_list.tsx @@ -17,7 +17,13 @@ const LinkListStyle = styled.ul({ overflowY: 'scroll', }); -export default function LinkList({ links }: { links: Link[] }) { +export default function LinkList({ + links, + showControls = true, +}: { + links: Link[]; + showControls?: boolean; +}) { if (links.length === 0) { return ; } @@ -25,7 +31,7 @@ export default function LinkList({ links }: { links: Link[] }) { return ( {sortByCreationDate(links).map((link) => ( - + ))} ); diff --git a/inertia/components/dashboard/side_nav/favorite/favorite_item.tsx b/inertia/components/dashboard/side_nav/favorite/favorite_item.tsx index f195581..b6eb366 100644 --- a/inertia/components/dashboard/side_nav/favorite/favorite_item.tsx +++ b/inertia/components/dashboard/side_nav/favorite/favorite_item.tsx @@ -1,7 +1,7 @@ import styled from '@emotion/styled'; -import { ItemLink } from '~/components/dashboard/side_nav/nav_item'; +import { ItemExternalLink } from '~/components/dashboard/side_nav/nav_item'; -const FavoriteItem = styled(ItemLink)(({ theme }) => ({ +const FavoriteItem = styled(ItemExternalLink)(({ theme }) => ({ backgroundColor: theme.colors.secondary, })); diff --git a/inertia/components/dashboard/side_nav/nav_item.tsx b/inertia/components/dashboard/side_nav/nav_item.tsx index f4750fe..eac53ee 100644 --- a/inertia/components/dashboard/side_nav/nav_item.tsx +++ b/inertia/components/dashboard/side_nav/nav_item.tsx @@ -1,5 +1,6 @@ import styled from '@emotion/styled'; import { Link } from '@inertiajs/react'; +import ExternalLink from '~/components/common/external_link'; import { rgba } from '~/lib/color'; export const Item = styled.div(({ theme }) => ({ @@ -27,3 +28,4 @@ export const Item = styled.div(({ theme }) => ({ })); export const ItemLink = Item.withComponent(Link); +export const ItemExternalLink = Item.withComponent(ExternalLink); diff --git a/inertia/components/visibilty/visibilty.tsx b/inertia/components/visibilty/visibilty.tsx index 74c71d6..9ded5ab 100644 --- a/inertia/components/visibilty/visibilty.tsx +++ b/inertia/components/visibilty/visibilty.tsx @@ -3,10 +3,11 @@ import styled from '@emotion/styled'; import { IoEarthOutline } from 'react-icons/io5'; const VisibilityStyle = styled.span(({ theme }) => ({ + userSelect: 'none', fontWeight: 300, fontSize: '0.6em', - color: theme.colors.lightBlue, - border: `1px solid ${theme.colors.lightBlue}`, + color: theme.colors.primary, + border: `1px solid ${theme.colors.primary}`, borderRadius: '50px', padding: '0.15em 0.65em', display: 'flex', diff --git a/inertia/pages/dashboard.tsx b/inertia/pages/dashboard.tsx index 6e282a0..d5efd70 100644 --- a/inertia/pages/dashboard.tsx +++ b/inertia/pages/dashboard.tsx @@ -109,7 +109,6 @@ function DashboardPage(props: Readonly) { } }, [isMobile, isTablet, closeCollectionList, closeNavigation]); - console.log(isMobile, isTablet, isNavigationOpen, isCollectionListOpen); return ( ( + {} }} + > + + + +); + +SharedCollectionPage.layout = (page: ReactNode) => ( + +); +export default SharedCollectionPage; diff --git a/inertia/styles/themes/light_theme.ts b/inertia/styles/themes/light_theme.ts index e52bd7f..ad6cca9 100644 --- a/inertia/styles/themes/light_theme.ts +++ b/inertia/styles/themes/light_theme.ts @@ -23,7 +23,7 @@ export const lightTheme: Theme = { white: '#ffffff', lightGrey: '#dadce0', - grey: '#888888', + grey: '#777777', lightestBlue, lightBlue, diff --git a/start/routes.ts b/start/routes.ts index 9184beb..16f8902 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -1,7 +1,8 @@ +import './routes/admin.js'; import './routes/app.js'; import './routes/auth.js'; import './routes/collection.js'; import './routes/favicon.js'; import './routes/link.js'; import './routes/search.js'; -import './routes/admin.js'; +import './routes/shared_collection.js'; diff --git a/start/routes/collection.ts b/start/routes/collection.ts index 3fe1766..b43100f 100644 --- a/start/routes/collection.ts +++ b/start/routes/collection.ts @@ -3,9 +3,6 @@ import router from '@adonisjs/core/services/router'; const CollectionsController = () => import('#controllers/collections_controller'); -/** - * Routes for authenticated users - */ router .group(() => { router.get('/dashboard', [CollectionsController, 'index']).as('dashboard'); diff --git a/start/routes/shared_collection.ts b/start/routes/shared_collection.ts new file mode 100644 index 0000000..42bf6ec --- /dev/null +++ b/start/routes/shared_collection.ts @@ -0,0 +1,6 @@ +import router from '@adonisjs/core/services/router'; + +const SharedCollectionsController = () => + import('#controllers/shared_collections_controller'); + +router.get('/shared/:id', [SharedCollectionsController, 'index']).as('shared');