Skip to content

Commit

Permalink
feat(collection): add blog variant for collections (#924)
Browse files Browse the repository at this point in the history
## Problem
1. we want a blog variant with 2 col layout in `lg/md` and a singular column view on `sm` 

## Solution
1. add a separate `BlogCard` component together with styling changes for `CollectionResult`. the `CollectionResult` displays in a grid layout with 2 cols by default and transitions into a single column layout on small screens
2. for the `BlogCard`, the `image` is extracted to the top together w some spacing changes 
3. **NOTE:** i implemented this as a separate component for dev speed. it might be possible to combine the `BlogCard` and `CollectionCard` into a single component and use the `variant` to distinguish but it seemed premature because we haven't settled on the design yet (for the blog layout), so i opted to keep it separate + flexible first

## Notes
1. on medium to large views, i opted to remove the image totally rather than leave a placeholder image so that the text all aligns at the start. this was so that we could have correct spacing on small screens (as the `gap-3` of the containing div still applies when `display: none` was set on a fake `div`) - trying to figure out how to conditionally render but tw itself won't be able to do thsi

## Videos

https://github.com/user-attachments/assets/58a6f949-7015-4cd1-8a2f-e7ee564b6837

## Demo
https://test-isomer-next-staging.isomer.gov.sg/cls
  • Loading branch information
seaerchin authored Dec 20, 2024
1 parent c3b19ca commit 7691901
Show file tree
Hide file tree
Showing 31 changed files with 411 additions and 33 deletions.
1 change: 1 addition & 0 deletions apps/studio/prisma/generated/generatedEnums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const ResourceType = {
Page: "Page",
Folder: "Folder",
Collection: "Collection",
CollectionMeta: "CollectionMeta",
CollectionLink: "CollectionLink",
CollectionPage: "CollectionPage",
IndexPage: "IndexPage",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "ResourceType" ADD VALUE 'CollectionMeta';
7 changes: 6 additions & 1 deletion apps/studio/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ model Resource {
// This is required so prisma does not attempt to drop the custom index.
@@unique([siteId, parentId, permalink])
@@index([siteId, id, parentId]) // note: ordering is important here!
@@index([type])
@@index([type])
// NOTE: This is used to create a inverted index using text trigrams for the title
// so that we can perform searches on the title quickly
@@index([title(ops: raw("gin_trgm_ops"))], type: Gin, name: "resource_title_trgm_idx")
}

model Blob {
Expand All @@ -103,6 +107,7 @@ enum ResourceType {
Page
Folder
Collection
CollectionMeta // Can only ever be inside collection
CollectionLink // Can only ever be inside collection
CollectionPage // Can only live inside `Collection` resources
IndexPage // This denotes the index page of a folder or a collection
Expand Down
5 changes: 5 additions & 0 deletions apps/studio/prisma/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import type {
IsomerLayoutVariants as _IsomerLayoutVariants,
IsomerPageSchemaType as _IsomerPageSchemaType,
IsomerSchema as _IsomerSchema,
IsomerSiteConfigProps as _IsomerSiteConfigProps,
Expand All @@ -20,6 +21,10 @@ declare global {
// TODO: Rename all with XXXYYYJson instead of XXXJsonYYY
type SiteJsonConfig = Tagged<_IsomerSiteConfigProps, "JSONB">
type SiteThemeJson = Tagged<_IsomerSiteThemeProps, "JSONB">
type CollectionThemeJson = Tagged<
_IsomerLayoutVariants["collection"],
"JSONB"
>
type BlobJsonContent = Tagged<_IsomerSchema, "JSONB">
type NavbarJsonContent = Tagged<
_IsomerSiteWideComponentsProps["navBarItems"],
Expand Down
31 changes: 31 additions & 0 deletions apps/studio/public/assets/css/preview-tw.css
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,10 @@ video {
margin-right: -0.5rem;
}

.-mt-1 {
margin-top: -0.25rem;
}

.-mt-8 {
margin-top: -2rem;
}
Expand Down Expand Up @@ -2540,6 +2544,11 @@ video {
padding-right: 0.25rem;
}

.px-1\.5 {
padding-left: 0.375rem;
padding-right: 0.375rem;
}

.px-10 {
padding-left: 2.5rem;
padding-right: 2.5rem;
Expand Down Expand Up @@ -2590,6 +2599,16 @@ video {
padding-right: 1px;
}

.py-0 {
padding-top: 0px;
padding-bottom: 0px;
}

.py-0\.5 {
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}

.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
Expand Down Expand Up @@ -4696,6 +4715,10 @@ video {
justify-content: flex-start;
}

.sm\:gap-0 {
gap: 0px;
}

.sm\:gap-3 {
gap: 0.75rem;
}
Expand Down Expand Up @@ -4891,6 +4914,10 @@ video {
gap: 1rem;
}

.md\:gap-5 {
gap: 1.25rem;
}

.md\:gap-7 {
gap: 1.75rem;
}
Expand Down Expand Up @@ -4946,6 +4973,10 @@ video {
padding-bottom: 0.75rem;
}

.md\:pt-0 {
padding-top: 0px;
}

.md\:pt-16 {
padding-top: 4rem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const ERROR_COMPONENT_PROPS: Record<ResourceType, ErrorProps> = {
"To have access, ask your site admins to assign this collection to you",
buttonText: "Back to My Sites",
},
CollectionMeta: {
title: "You don't have access to edit this collection.",
description:
"To have access, ask your site admins to assign this collection to you",
buttonText: "Back to My Sites",
},
IndexPage: {
title: "You don't have access to edit this page.",
description:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ function ComponentSelector() {
return []
case ResourceType.Folder:
case ResourceType.FolderMeta:
case ResourceType.CollectionMeta:
throw new Error(`Unsupported resource type: ${type}`)
default:
const exhaustiveCheck: never = type
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { IconType } from "react-icons"
import { ResourceType } from "~prisma/generated/generatedEnums"
import {
BiCog,
BiData,
BiFile,
BiFolder,
Expand All @@ -14,6 +15,7 @@ export const ICON_MAPPINGS: Record<ResourceType, IconType> = {
[ResourceType.Folder]: BiFolder,
[ResourceType.Collection]: BiData,
[ResourceType.CollectionPage]: BiFile,
[ResourceType.CollectionMeta]: BiCog,
[ResourceType.CollectionLink]: BiLink,
[ResourceType.RootPage]: BiHomeAlt,
[ResourceType.IndexPage]: BiFile,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const useIsActive = (
case ResourceType.CollectionLink:
return siteProps.linkId === currentResourceId
case ResourceType.FolderMeta:
case ResourceType.CollectionMeta:
// TODO: Not implemented yet
return false
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HStack, Icon, Text, VStack } from "@chakra-ui/react"
import { Link } from "@opengovsg/design-system-react"
import { ResourceType } from "~prisma/generated/generatedEnums"
import {
BiCog,
BiData,
BiFile,
BiFolder,
Expand Down Expand Up @@ -43,6 +44,8 @@ export const TitleCell = ({
return BiFolder
case ResourceType.Collection:
return BiData
case ResourceType.CollectionMeta:
return BiCog
case ResourceType.CollectionPage:
return BiFile
case ResourceType.CollectionLink:
Expand Down
3 changes: 2 additions & 1 deletion apps/studio/src/server/modules/page/page.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ export const pageRouter = router({
type !== ResourceType.CollectionPage &&
type !== ResourceType.RootPage &&
type !== ResourceType.IndexPage &&
type !== ResourceType.FolderMeta
type !== ResourceType.FolderMeta &&
type !== ResourceType.CollectionMeta
) {
throw new TRPCError({
code: "NOT_FOUND",
Expand Down
3 changes: 3 additions & 0 deletions apps/studio/src/server/modules/resource/resource.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ export const resourceRouter = router({
.select(["title", "permalink", "type", "id"])
.where("Resource.type", "!=", ResourceType.RootPage)
.where("Resource.type", "!=", ResourceType.FolderMeta)
.where("Resource.type", "!=", ResourceType.CollectionMeta)
.where("Resource.siteId", "=", Number(siteId))
.$narrowType<{
type: Extract<
Expand Down Expand Up @@ -336,6 +337,7 @@ export const resourceRouter = router({
.where("Resource.siteId", "=", siteId)
.where("Resource.type", "!=", ResourceType.RootPage)
.where("Resource.type", "!=", ResourceType.FolderMeta)
.where("Resource.type", "!=", ResourceType.CollectionMeta)
.select((eb) => [eb.fn.countAll().as("totalCount")])

if (resourceId) {
Expand All @@ -356,6 +358,7 @@ export const resourceRouter = router({
.where("Resource.siteId", "=", siteId)
.where("Resource.type", "!=", ResourceType.RootPage)
.where("Resource.type", "!=", ResourceType.FolderMeta)
.where("Resource.type", "!=", ResourceType.CollectionMeta)
.orderBy("Resource.updatedAt", "desc")
.orderBy("Resource.title", "asc")
.offset(offset)
Expand Down
6 changes: 4 additions & 2 deletions apps/studio/src/server/modules/resource/resource.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ export const getFullPageById = async (
return publishedBlob
}

// There are 6 types of pages this get query supports:
// Page, CollectionPage, RootPage, IndexPage, CollectionLink, FolderMeta
// There are 7 types of pages this get query supports:
// Page, CollectionPage, RootPage, IndexPage, CollectionLink, FolderMeta, CollectionMeta
export const getPageById = (
db: SafeKysely,
args: { resourceId: number; siteId: number },
Expand All @@ -145,6 +145,7 @@ export const getPageById = (
eb("type", "=", ResourceType.IndexPage),
eb("type", "=", ResourceType.CollectionLink),
eb("type", "=", ResourceType.FolderMeta),
eb("type", "=", ResourceType.CollectionMeta),
]),
)
.select(defaultResourceSelect)
Expand Down Expand Up @@ -309,6 +310,7 @@ export const getLocalisedSitemap = async (
return fb("Resource.parentId", "=", String(resource.parentId))
})
.where("Resource.type", "!=", ResourceType.FolderMeta)
.where("Resource.type", "!=", ResourceType.CollectionMeta)
.select(defaultResourceSelect),
)
// Step 3: Combine all the resources in a single array
Expand Down
1 change: 1 addition & 0 deletions apps/studio/src/utils/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const getResourceSubpath = (resourceType: ResourceType) => {
case ResourceType.Collection:
return "collections"
case ResourceType.FolderMeta:
case ResourceType.CollectionMeta:
// TODO: Not implemented yet
return ""
default:
Expand Down
5 changes: 3 additions & 2 deletions apps/studio/src/utils/sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { IsomerSitemap } from "@opengovsg/isomer-components"
import type { Resource } from "@prisma/client"
import { ResourceType } from "~prisma/generated/generatedEnums"

import type { Resource } from "~prisma/generated/selectableTypes"
import { INDEX_PAGE_PERMALINK } from "~/constants/sitemap"

type ResourceDto = Omit<
Expand All @@ -27,7 +27,8 @@ const getSitemapTreeFromArray = (
return (
resource.parentId === null &&
resource.type !== ResourceType.RootPage &&
resource.type !== ResourceType.FolderMeta
resource.type !== ResourceType.FolderMeta &&
resource.type !== ResourceType.CollectionMeta
)
}
return (
Expand Down
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 7691901

Please sign in to comment.