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

bugfix artwork slug #132

Merged
merged 26 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
58bb905
Merge pull request #116 from goodeats/dev
goodeats May 22, 2024
a0cb327
readme update
goodeats May 23, 2024
72d5b6a
Merge pull request #118 from goodeats/117-readme-update
goodeats May 23, 2024
73d1384
redirect from auth routes and others that are accessible
goodeats May 23, 2024
da4ceaa
remix dev tools highlighted that resource route components exposed th…
goodeats May 23, 2024
5f1ded4
a few more exposed routes now guarded by auth
goodeats May 23, 2024
c97cb1d
now that first user has been created, new users will no longer be adm…
goodeats May 23, 2024
85c5cef
removed failed tests from preventing users from access to the app
goodeats May 23, 2024
05716dc
Merge pull request #119 from goodeats/108-prevent-new-users-after-dep…
goodeats May 23, 2024
c550046
marketing components more human-readable for what they are
goodeats May 23, 2024
9b0b0bc
marketing components more human-readable for what they are -- for art…
goodeats May 23, 2024
4061398
landing page has content from first user (me)
goodeats May 23, 2024
53ee1b2
Merge pull request #121 from goodeats/120-user-details-for-landing-page
goodeats May 23, 2024
974bf34
landing page has user image instead of svg logo
goodeats May 23, 2024
53fb483
no coming soon button for visitors
goodeats May 23, 2024
708e8c2
Merge pull request #123 from goodeats/122-landing-page-personal-image…
goodeats May 23, 2024
7a2f0fd
can toggle artwork version starred in nav
goodeats May 23, 2024
654799b
added starred and published to artwork versions; can toggle starred f…
goodeats May 23, 2024
85849a1
bugfix and eslint was dragging cursor so reinstalled deps
goodeats May 23, 2024
1e42019
canvas component pulled out so it can be loaded in starred versions t…
goodeats May 23, 2024
1519de9
wrap artwork canvas component in relative div so it fits in its conta…
goodeats May 24, 2024
e752342
displaying grid of published artwork versions on landing page
goodeats May 24, 2024
fdc293a
slightly adjusting user details section
goodeats May 24, 2024
c303f4a
seed artwork version designs improved; displaying a reasonably better…
goodeats May 24, 2024
2933c99
Merge pull request #126 from goodeats/124-star-and-publish-artwork-ve…
goodeats May 24, 2024
ce125df
fixed param
goodeats May 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,12 @@ FLY_APP_NAME="fly-app-name-1234"
# set false for staging via fly secrets
# https://github.com/epicweb-dev/epic-stack/blob/main/docs/deployment.md
ALLOW_INDEXING="true"

# dev admin user settings
ADMIN_EMAIL="[email protected]"
ADMIN_PASSWORD="" # GitGuardian will flag this and fail so anything you want
ADMIN_NAME="Pat"
ADMIN_USERNAME="pat" # must be lowercase
ADMIN_BIO="Welcome to my digital gallery."
ADMIN_SM_INSTAGRAM_URL="https://www.instagram.com/pppaaattt.xyz"
ADMIN_SM_GITHUB_URL="https://github.com/goodeats"
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# [Epic PPPAAATTT](https://github.com/goodeats/epic-pppaaattt)

Drawing generative geometric shapes on a canvas

Progress: 🚧 Constructing MVP... 🚧
A generative art generator with various product-building demonstrations of web development

## GETTING STARTED

Expand All @@ -11,7 +9,7 @@ To get started with this project, follow these steps:
1. Clone the repository to your local machine.
2. Navigate to the project directory.
3. Run `npm install` to install the necessary dependencies.
4. Copy environment variables `cp .env.example .env`
4. Copy environment variables `cp .env.example .env` (make changes to ADMIN env variables to your suiting, for instance GitGuardian won't let me commit a fake password)
5. Run `npm run setup`
6. Start the development server by running `npm run dev`.

Expand All @@ -25,10 +23,12 @@ Please keep in mind this is a personal project, not yet intended for a wide audi
- add a layer, which will adopt the artwork design attributes
- click on the layer name to select it and adjust the designs from there
- move up/down, make visible/invisible, add/remove designs and layers to create different outputs on the artwork
- creating a new version will save your progress
- creating a new branch will allow you to explore a different creative pursuit

## TECH STACK

- Framework (full-stack): [Remix Run](https://remix.run/) | [Epic Stack](https://github.com/epicweb-dev/epic-stack)
- Framework (full-stack): [Remix Run](https://remix.run/) | [Epic Stack](https://github.com/epicweb-dev/epic-stack) | [Vite](https://remix.run/blog/remix-heart-vite)
- DB: [SQLite](https://www.sqlite.org/index.html)
- ORM: [Prisma](https://www.prisma.io/)
- UI: [tailwindcss](https://tailwindcss.com/) | [Radix](https://www.radix-ui.com/) | [shadcn/ui](https://ui.shadcn.com/)
Expand All @@ -38,13 +38,11 @@ Please keep in mind this is a personal project, not yet intended for a wide audi

- this is a project built for personal use in developing a project to achieve my artistic goals: rapid development and deployment of unique artistic projects in the marketplace
- foregoing tests a bit to get the MVP out
- I recently discovered the Figma UI and feel that dashboard is a good representation of how I want to build this
- I took inspiration from the Figma dashboard UI for setting up how I want to build art generators

## ROADMAP

- version history to save instances of artworks if I like the designs
- connect to shopify products
- migrate to [vite](https://remix.run/blog/remix-heart-vite)
- import/export image assets to modify pixels into art
- import/export design types and layers
- shareable links -- use [v0](v0.dev) as a guide
7 changes: 5 additions & 2 deletions app/components/layout/card/dashboard-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
CardTitle,
} from '#app/components/ui/card'
import { Icon, type IconName } from '#app/components/ui/icon'
import { cn } from '#app/utils/misc'
import { createContainerComponent } from '../utils'

const DashboardCardWrapper = createContainerComponent({
Expand All @@ -34,17 +35,19 @@ const DashboardCard = ({
title,
description,
children,
className,
}: {
title: string
description: string
children: React.ReactNode
className?: string
}) => {
// - fixed width to indicate a smaller card
// - more space between cards on larger screens
const className = 'mb-2 w-80 lg:mb-6'
const cardClassName = cn('mb-2 w-80 lg:mb-6', className)

return (
<Card className={className}>
<Card className={cardClassName}>
<CardHeader>
<CardTitle>{title}</CardTitle>
<CardDescription>{description}</CardDescription>
Expand Down
83 changes: 83 additions & 0 deletions app/components/layout/marketing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { cn } from '#app/utils/misc'
import { createContainerComponent } from './utils'

const MarketingMainLayout = createContainerComponent({
defaultTagName: 'main',
defaultClassName: 'font-poppins grid h-full place-items-center',
displayName: 'MarketingMainLayout',
})

const MarketingContentSection = createContainerComponent({
defaultTagName: 'div',
defaultClassName:
'grid place-items-center px-4 py-16 xl:grid-cols-2 xl:gap-4',
displayName: 'MarketingContentSection',
})

const MarketingDetailsSection = createContainerComponent({
defaultTagName: 'div',
defaultClassName:
'mb-4 flex max-w-lg flex-col items-center text-left xl:order-2 xl:mt-16 xl:items-start xl:self-start',
displayName: 'MarketingDetailsSection',
})

const MarketingLogoLink = createContainerComponent({
defaultTagName: 'a',
defaultClassName:
'animate-slide-top [animation-fill-mode:backwards] xl:animate-slide-left xl:[animation-delay:0.5s] xl:[animation-fill-mode:backwards]',
displayName: 'MarketingLogoLink',
})

const MarketingLogoImage = createContainerComponent({
defaultTagName: 'img',
defaultClassName: 'h-52 w-52 rounded-full object-cover',
displayName: 'MarketingLogoImage',
})

const MarketingHeader = createContainerComponent({
defaultTagName: 'h1',
defaultClassName:
'mt-8 animate-slide-top text-4xl font-medium text-foreground [animation-delay:0.3s] [animation-fill-mode:backwards] md:text-5xl xl:mt-4 xl:animate-slide-left xl:text-6xl xl:[animation-delay:0.8s] xl:[animation-fill-mode:backwards]',
displayName: 'MarketingHeader',
})

const MarketingContent = createContainerComponent({
defaultTagName: 'p',
defaultClassName:
'mt-6 animate-slide-top text-xl/7 text-muted-foreground [animation-delay:0.8s] [animation-fill-mode:backwards] xl:mt-8 xl:animate-slide-left xl:text-xl/6 xl:leading-10 xl:[animation-delay:1s] xl:[animation-fill-mode:backwards]',
displayName: 'MarketingContent',
})

const MarketingSocialLinksList = createContainerComponent({
defaultTagName: 'ul',
defaultClassName:
'mt-6 flex animate-slide-top space-x-6 [animation-delay:1.2s] [animation-fill-mode:backwards] xl:mt-8 xl:animate-slide-left xl:[animation-delay:1.2s] xl:[animation-fill-mode:backwards]',
displayName: 'MarketingSocialLinksList',
})

// experimenting with constructing class names
// separately by category and breakpoint
// possibly more readable and maintainable
const MarketingCanvasGrid = createContainerComponent({
defaultTagName: 'div',
defaultClassName: cn(
'mt-16 xl:mt-0',
'py-16 px-4 lg:px-8 xl:px-16',
'grid place-items-center',
'grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
'gap-8',
),
displayName: 'MarketingCanvasGrid',
})

export {
MarketingMainLayout,
MarketingContentSection,
MarketingDetailsSection,
MarketingLogoLink,
MarketingLogoImage,
MarketingHeader,
MarketingContent,
MarketingSocialLinksList,
MarketingCanvasGrid,
}
5 changes: 4 additions & 1 deletion app/components/layout/page-footer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { useOptionalUser } from '#app/utils/user'
import Logo from '../logo'
import { ThemeSwitch } from '../theme-switch'

const PageFooter = () => {
const user = useOptionalUser()

return (
<div className="container flex justify-between pb-5">
<Logo />
<ThemeSwitch />
{user ? <ThemeSwitch /> : '🔺'}
</div>
)
}
Expand Down
9 changes: 2 additions & 7 deletions app/components/layout/page-header.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Link } from '@remix-run/react'
import { useOptionalUser } from '#app/utils/user'
import Logo from '../logo'
import { ThemeSwitch } from '../theme-switch'
import { Button } from '../ui/button'
import { UserDropdown } from '../user-dropdown'

Expand All @@ -12,13 +13,7 @@ const PageHeader = () => {
<nav className="flex flex-wrap items-center justify-between gap-4 sm:flex-nowrap md:gap-8">
<Logo />
<div className="flex items-center gap-10">
{user ? (
<UserDropdown />
) : (
<Button asChild variant="default" size="lg">
<Link to="/">Coming Soon</Link>
</Button>
)}
{user ? <UserDropdown /> : <ThemeSwitch />}
</div>
</nav>
</header>
Expand Down
35 changes: 35 additions & 0 deletions app/components/templates/canvas/artwork-canvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { memo, useEffect, useRef } from 'react'
import { type IArtworkVersionGenerator } from '#app/definitions/artwork-generator'
import { canvasDrawService } from '#app/services/canvas/draw.service'

// The ArtworkCanvas component is wrapped in React.memo to optimize performance by memoizing the component.
// This prevents unnecessary re-renders when the props passed to the component have not changed.
// Specifically, since this component involves canvas drawing operations which can be computationally expensive,
// memoizing ensures that these operations are only re-executed when necessary, such as when the 'generator' prop changes.
export const ArtworkCanvas = memo(
({ generator }: { generator: IArtworkVersionGenerator }) => {
const { width, height, background } = generator.settings
const canvasRef = useRef<HTMLCanvasElement>(null)

useEffect(() => {
const canvas = canvasRef.current
if (canvas) {
canvasDrawService({ canvas, generator })
}
}, [canvasRef, generator])

return (
<div className="relative h-full w-full">
<canvas
id="canvas-editor"
ref={canvasRef}
width={width}
height={height}
style={{ backgroundColor: `#${background}` }}
className="h-full w-full"
/>
</div>
)
},
)
ArtworkCanvas.displayName = 'ArtworkCanvas'
1 change: 1 addition & 0 deletions app/components/templates/canvas/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './artwork-canvas'
4 changes: 4 additions & 0 deletions app/components/ui/icons/name.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type IconName =
| 'cross-1'
| 'crosshair-1'
| 'crosshair-2'
| 'crumpled-paper'
| 'dimensions'
| 'disc'
| 'dots-horizontal'
Expand Down Expand Up @@ -57,9 +58,12 @@ export type IconName =
| 'plus'
| 'question-mark-circled'
| 'reset'
| 'rocket'
| 'ruler-square'
| 'size'
| 'stack'
| 'star-filled'
| 'star'
| 'stretch-horizontally'
| 'stretch-vertically'
| 'sun'
Expand Down
26 changes: 26 additions & 0 deletions app/components/ui/icons/sprite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions app/models/artwork-version/artwork-version.get.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const whereArgs = z.object({
branchId: z.string().optional(),
nextId: zodStringOrNull.optional(),
prevId: zodStringOrNull.optional(),
starred: z.boolean().optional(),
})

const includeDesigns = {
Expand Down Expand Up @@ -100,3 +101,41 @@ export const getArtworkVersionWithDesignsAndLayers = async ({
})
return artworkVersion
}

export const getStarredArtworkVersionsByArtworkId = async ({
artworkId,
}: {
artworkId: string
}): Promise<IArtworkVersionWithDesignsAndLayers[]> => {
const starredVersions = await prisma.artworkVersion.findMany({
where: {
branch: {
artworkId: artworkId,
},
starred: true,
},
include: {
...includeDesignsAndLayers,
branch: true,
},
orderBy: {
updatedAt: 'desc',
},
})
return starredVersions
}

export const getAllPublishedArtworkVersions = async (): Promise<
IArtworkVersionWithDesignsAndLayers[]
> => {
const starredVersions = await prisma.artworkVersion.findMany({
where: {
published: true,
},
include: includeDesignsAndLayers,
orderBy: {
publishedAt: 'desc',
},
})
return starredVersions
}
Loading
Loading