diff --git a/src/components/thumbnail/index.ts b/src/components/thumbnail/index.ts index f9a0f21..81eccc1 100644 --- a/src/components/thumbnail/index.ts +++ b/src/components/thumbnail/index.ts @@ -1,10 +1,6 @@ import './styles.css'; -import {EventBus} from "../../event-bus"; -import {Events} from "../../consts/events"; -import {handlers} from "../../consts/handlers"; +import {EVENT_BUS} from "../../core"; -const EVENT_BUS = new EventBus(); -EVENT_BUS.subscribe('page_navigation', handlers.page_navigation); export type thumbnailContent = { readonly thumbnail: string; @@ -45,7 +41,9 @@ export function createThumbnail(content: thumbnailContent, showcase: boolean) { itemTexts.appendChild(itemCategory); itemBox.appendChild(clearFix); - itemThumbnail.addEventListener('click', () => EVENT_BUS.dispatch('page_navigation', {path: "Button A", pageReference: content.path})); + itemThumbnail.addEventListener('click', () => { + EVENT_BUS.dispatch('page_navigation', { pageReference: 'interactive/' + content.path }); + }); return itemBox; } \ No newline at end of file diff --git a/src/consts/events/index.ts b/src/consts/events/index.ts deleted file mode 100644 index 059ff12..0000000 --- a/src/consts/events/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./events"; \ No newline at end of file diff --git a/src/consts/handlers/handlers.ts b/src/consts/handlers/handlers.ts deleted file mode 100644 index 616a96b..0000000 --- a/src/consts/handlers/handlers.ts +++ /dev/null @@ -1,8 +0,0 @@ -import {Events} from "../events"; -import {buildProjectPage} from "../../content/projects"; - -export const handlers = { - page_navigation: (value: Events['page_navigation']): void => { - buildProjectPage(value.pageReference); - }, -}; \ No newline at end of file diff --git a/src/consts/handlers/index.ts b/src/consts/handlers/index.ts deleted file mode 100644 index c7db3bf..0000000 --- a/src/consts/handlers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./handlers"; \ No newline at end of file diff --git a/src/content/projects/index.ts b/src/content/projects/index.ts index 9b88a1e..ed51f2f 100644 --- a/src/content/projects/index.ts +++ b/src/content/projects/index.ts @@ -1,16 +1,18 @@ -import {projectView} from "../../views/project-view"; +import {projectView, renderView} from "../../views"; import {projectInfo} from "../../components/vertical-nav/info-project.ts"; -import {renderView} from "../../views/utils"; import {renderBreadcrumbs, renderNavInfo} from "../../components/vertical-nav"; import {createThumbnail} from "../../components/thumbnail"; import {BreadcrumbCategory, breadcrumbs, BreadcrumbsLink} from "../../components/breadcrumbs"; import * as spaceCompass from "./space-compass"; +import * as nextUx from "./next-ux"; +import {interactiveView} from "../../views/interactive.ts"; const pageReferences: { [key: string]: any } = { "space-compass": spaceCompass, + "next-ux": nextUx, }; @@ -32,6 +34,13 @@ export function buildProjectPage(pageReference: string) { renderView(viewContent); } +export function buildInteractivePage() { + const viewContent = interactiveView(); + + renderView(viewContent); + +} + export function buildThumbnailList() { const list = document.createElement('ul'); diff --git a/src/content/projects/next-ux/assets/next-ux-screenshot-1.jpg b/src/content/projects/next-ux/assets/next-ux-screenshot-1.jpg new file mode 100644 index 0000000..2d4ff2d Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-screenshot-1.jpg differ diff --git a/src/content/projects/next-ux/assets/next-ux-screenshot-2.jpg b/src/content/projects/next-ux/assets/next-ux-screenshot-2.jpg new file mode 100644 index 0000000..e2f647f Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-screenshot-2.jpg differ diff --git a/src/content/projects/next-ux/assets/next-ux-screenshot-3.jpg b/src/content/projects/next-ux/assets/next-ux-screenshot-3.jpg new file mode 100644 index 0000000..652ec89 Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-screenshot-3.jpg differ diff --git a/src/content/projects/next-ux/assets/next-ux-screenshot-4.jpg b/src/content/projects/next-ux/assets/next-ux-screenshot-4.jpg new file mode 100644 index 0000000..d7cd0c1 Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-screenshot-4.jpg differ diff --git a/src/content/projects/next-ux/assets/next-ux-showcase.mp4 b/src/content/projects/next-ux/assets/next-ux-showcase.mp4 new file mode 100644 index 0000000..43fbdcb Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-showcase.mp4 differ diff --git a/src/content/projects/next-ux/assets/next-ux-showcase.webm b/src/content/projects/next-ux/assets/next-ux-showcase.webm new file mode 100644 index 0000000..ca5fe48 Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-showcase.webm differ diff --git a/src/content/projects/next-ux/assets/next-ux-thumbnail.jpg b/src/content/projects/next-ux/assets/next-ux-thumbnail.jpg new file mode 100644 index 0000000..7d182d0 Binary files /dev/null and b/src/content/projects/next-ux/assets/next-ux-thumbnail.jpg differ diff --git a/src/content/projects/next-ux/index.ts b/src/content/projects/next-ux/index.ts new file mode 100644 index 0000000..f0cf09f --- /dev/null +++ b/src/content/projects/next-ux/index.ts @@ -0,0 +1,56 @@ +import {ProjectContent} from "../../../views/project-view/"; +import {ButtonLink} from "../../../components/vertical-nav/info-project.ts"; +import {thumbnailContent} from "../../../components/thumbnail"; + +import WEBM_VIDEO from "./assets/next-ux-showcase.webm"; +import MP4_VIDEO from "./assets/next-ux-showcase.mp4"; + +import SCREENSHOT_1 from "./assets/next-ux-screenshot-1.jpg" +import SCREENSHOT_2 from "./assets/next-ux-screenshot-2.jpg" +import SCREENSHOT_3 from "./assets/next-ux-screenshot-3.jpg" +import SCREENSHOT_4 from "./assets/next-ux-screenshot-4.jpg" + +import THUMBNAIL from "./assets/next-ux-thumbnail.jpg"; + +export const content: ProjectContent = { + title: "Next UX", + subtitle: "web app ux / ui - 2021", + + tagline: "Clear Workflows ", + paragraphs: [ + "Complete overhaul of Voxco's product line, including a redesigned user flow and interface." + ], + + heroVideo: [ + WEBM_VIDEO, + MP4_VIDEO + ], + + imageGallery: [ + SCREENSHOT_1, + SCREENSHOT_2, + SCREENSHOT_3, + SCREENSHOT_4 + ] +} + +export const buttons: ButtonLink[] = [ + [ + "INSERT", + "INSERT URL", + true + ], + [ + "INSERT", + "INSERT URL", + false + ], +] + +export const thumbnail: thumbnailContent = { + thumbnail: THUMBNAIL, + title: content.title, + description: "INSERT", + tags: ["INSERT", "INSERT"], + path: "next-ux" +} diff --git a/src/content/projects/space-compass/index.ts b/src/content/projects/space-compass/index.ts index c5b9d58..6818cef 100644 --- a/src/content/projects/space-compass/index.ts +++ b/src/content/projects/space-compass/index.ts @@ -1,4 +1,4 @@ -import {ProjectContent} from "../../../views/project-view"; +import {ProjectContent} from "../../../views/project.ts"; import {ButtonLink} from "../../../components/vertical-nav/info-project.ts"; import {thumbnailContent} from "../../../components/thumbnail"; diff --git a/src/event-bus/index.ts b/src/core/event-bus.ts similarity index 50% rename from src/event-bus/index.ts rename to src/core/event-bus.ts index 173a53c..71882c7 100644 --- a/src/event-bus/index.ts +++ b/src/core/event-bus.ts @@ -3,31 +3,32 @@ type EventKey = keyof T; type EventHandler = (value: T) => void; export class EventBus { - private subscribers: Partial[]>> = {}; + private subscribers: Map, EventHandler[]> = new Map(); subscribe>(event: E, handler: EventHandler): void { - if (!this.subscribers[event]) { - this.subscribers[event] = []; + if (!this.subscribers.has(event)) { + this.subscribers.set(event, []); } - - this.subscribers[event].push(handler); + this.subscribers.get(event)!.push(handler); } unsubscribe>(event: E, handler: EventHandler): void { - if (!this.subscribers[event]) { + const handlers = this.subscribers.get(event); + if (!handlers) { return; } - - this.subscribers[event] = this.subscribers[event]!.filter( - (listener) => listener !== handler - ); + const index = handlers.indexOf(handler); + if (index !== -1) { + handlers.splice(index, 1); + } } dispatch>(event: E, value: T[E]): void { - if (!this.subscribers[event]) { + const handlers = this.subscribers.get(event); + if (!handlers) { return; } - this.subscribers[event]!.forEach((listener) => { + handlers.forEach((listener) => { listener(value); }); } diff --git a/src/consts/events/events.ts b/src/core/events.ts similarity index 77% rename from src/consts/events/events.ts rename to src/core/events.ts index 03b4641..abb679f 100644 --- a/src/consts/events/events.ts +++ b/src/core/events.ts @@ -1,6 +1,5 @@ export type Events = { readonly page_navigation: { - readonly path: string; readonly pageReference: string; } }; \ No newline at end of file diff --git a/src/core/handlers.ts b/src/core/handlers.ts new file mode 100644 index 0000000..9427617 --- /dev/null +++ b/src/core/handlers.ts @@ -0,0 +1,9 @@ +import {Events} from "./events"; +import {router} from "./router.ts"; + + +export const handlers = { + page_navigation: (value: Events['page_navigation']): void => { + router.handleRoute(value.pageReference); + }, +}; \ No newline at end of file diff --git a/src/core/index.ts b/src/core/index.ts new file mode 100644 index 0000000..b21d423 --- /dev/null +++ b/src/core/index.ts @@ -0,0 +1,9 @@ +import {EventBus} from "./event-bus"; +import {Events} from "./events"; +import {handlers} from "./handlers"; + +const EVENT_BUS = new EventBus(); + +EVENT_BUS.subscribe('page_navigation', handlers.page_navigation); + +export {EVENT_BUS}; \ No newline at end of file diff --git a/src/core/router.ts b/src/core/router.ts new file mode 100644 index 0000000..b159789 --- /dev/null +++ b/src/core/router.ts @@ -0,0 +1,58 @@ +import { EVENT_BUS } from "./"; + +type RouteHandler = (params?: Record) => void; + +class Router { + private routes: Map = new Map(); + + constructor() { + window.addEventListener('popstate', () => this.handleRoute(window.location.pathname)); + EVENT_BUS.subscribe('page_navigation', (data: { pageReference: string }) => this.navigate(data.pageReference)); + } + + public registerRoute(path: string, handler: RouteHandler) { + this.routes.set(path, handler); + } + + public navigate(path: string) { + window.history.pushState({}, '', path); + this.handleRoute(path); + } + + public handleRoute(path: string) { + for (const [route, handler] of this.routes.entries()) { + const match = this.matchRoute(route, path); + if (match) { + handler(match.params); + return; + } + } + console.error(`No handler found for path: ${path}`); + } + + private matchRoute(route: string, path: string) { + const routeParts = route.split('/').filter(Boolean); + const pathParts = path.split('/').filter(Boolean); + + if (routeParts.length !== pathParts.length) { + return null; + } + + const params: Record = {}; + for (let i = 0; i < routeParts.length; i++) { + const routePart = routeParts[i]; + const pathPart = pathParts[i]; + + if (routePart.startsWith(':')) { + const paramName = routePart.slice(1); + params[paramName] = pathPart; + } else if (routePart !== pathPart) { + return null; + } + } + + return { params }; + } +} + +export const router = new Router(); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 02af705..639fc2e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,17 @@ -import './views/home-view/styles.css'; +import { router } from "./core/router"; import {buildVerticalNav} from "./components/vertical-nav"; -import {buildViewBase} from "./views/utils"; -import {buildProjectPage} from "./content/projects"; +import {buildInteractivePage, buildProjectPage} from "./content/projects"; +import {homeView} from "./views/home.ts"; +import {buildViewBase} from "./views"; + + +const routes = [ + { path: '/', handler: homeView }, + { path: '/interactive', handler: buildInteractivePage }, + { path: '/interactive/:id', handler: (params) => buildProjectPage(params?.id) } +]; + +routes.forEach(route => router.registerRoute(route.path, route.handler)); function init() { @@ -12,7 +22,9 @@ function init() { body.appendChild(contentPage); contentPage.appendChild(verticalNav); - buildProjectPage("space-compass"); + router.handleRoute(window.location.pathname); } -init(); \ No newline at end of file +init(); + + diff --git a/src/views/error404.ts b/src/views/error404.ts new file mode 100644 index 0000000..4605c92 --- /dev/null +++ b/src/views/error404.ts @@ -0,0 +1,4 @@ + +export function buildErrorPage() { + +} \ No newline at end of file diff --git a/src/views/home-view/styles.css b/src/views/home-view/styles.css deleted file mode 100644 index e535057..0000000 --- a/src/views/home-view/styles.css +++ /dev/null @@ -1,99 +0,0 @@ -body { - background: #000; - height: 100%; - margin: 0; -} - -.corner-triangle { - position: absolute; - top: 0; - left: 0; - border-left: 0px solid transparent; - border-right: 25vw solid transparent; - border-top: 55vh solid #3BFFC5; -} - -.hero-visual { - position: absolute; - top: 0; - right: 0; - width: 90vw; - height: 100%; - clip-path: polygon(0 0, 100% 0, 100% 100%, 60vw 100%); - background-image: url("/img/home/hero-visual-test.png"); - background-repeat: no-repeat; - background-size: cover; - z-index: -1; -} - -.main-title { - position: relative; -} - -.main-title h3 { - font-size: 12vw; - font-family: "Cabin", sans-serif; - color: white; - text-align: center; - margin: 50vh auto 0; - transform: translateY(-50%); - text-shadow: 0px 0px 22px black; -} - -.business-card { - position: absolute; - bottom: 10vh; - left: 5vw; - width: 33vw; -} - -.business-card img { - float: left; - width: 10vw; - image-rendering: pixelated; -} - -.business-card article { - float: left; - color: white; - font-family: "Handjet", serif; - margin: 1.2vw 0 0 2vw; -} - -.business-card article h2 { - font-size: 2vw; - font-weight: 700; - margin: 0px; -} - -.business-card article h1 { - font-size: 5vw; - font-weight: 300; - margin: 0vw 0 0 0; -} - - -footer { - position: fixed; - bottom: 0; - width: 100%; - height: 40px; - background: #000; -} - -footer .logs-title { - float: left; - background: white; - height: 100%; - text-transform: uppercase; -} - -footer .logs-title h6 { - color: #000; - font-family: "Handjet", serif; - font-size: 1em; - font-weight: 900; - vertical-align: middle; - line-height: 100%; - margin: 12px 10px; -} \ No newline at end of file diff --git a/src/views/home-view/home-view.ts b/src/views/home.ts similarity index 98% rename from src/views/home-view/home-view.ts rename to src/views/home.ts index 93023c3..22c9f9f 100644 --- a/src/views/home-view/home-view.ts +++ b/src/views/home.ts @@ -1,7 +1,7 @@ import cdIcon from "/img/common/cd_icon_green.png"; -export function BuildView() { +export function homeView() { const view = document.createElement("main"); const mainVisuals = DrawVisuals(); const mainTitle = BuildMainTitle("bonjour, hi"); diff --git a/src/views/utils/view-utils.ts b/src/views/index.ts similarity index 69% rename from src/views/utils/view-utils.ts rename to src/views/index.ts index 043b05a..bdec125 100644 --- a/src/views/utils/view-utils.ts +++ b/src/views/index.ts @@ -1,8 +1,10 @@ -/* - VIEW-UTILITIESed to - Are functions usbuild the skeleton of content pages. - They are mostly used when building templates. - */ +import "./styles.css"; + +export * from "./home"; +export * from "./interactive.ts"; +export * from "./project.ts"; + +// -------------------------------------------------------------------------------- export function buildViewBase() { const viewBox = document.createElement('div'); @@ -19,6 +21,7 @@ export function renderView(view: HTMLElement) { viewWrapper.appendChild(view); } +// -------------------------------------------------------------------------------- function clearView() { const cleanViewWrapper = document.getElementById('view-wrapper')!; @@ -28,4 +31,3 @@ function clearView() { return cleanViewWrapper; } - diff --git a/src/views/interactive-view/index.ts b/src/views/interactive.ts similarity index 78% rename from src/views/interactive-view/index.ts rename to src/views/interactive.ts index ff261f4..49aafe8 100644 --- a/src/views/interactive-view/index.ts +++ b/src/views/interactive.ts @@ -1,12 +1,10 @@ -import {writeTitle} from "../utils"; -import {buildThumbnailList} from "../../content/projects"; - +import {writeTitle} from "./utils"; +import {buildThumbnailList} from "../content/projects"; //----------------------------------------------------------------------- export function interactiveView() { - const viewWrapper = document.getElementById('view-wrapper')!; const article = document.createElement('article'); const latestProject = document.createElement('div'); const listProject = document.createElement('div'); @@ -17,7 +15,6 @@ export function interactiveView() { latestProject.className = 'latest-project'; listProject.className = 'list-project'; - viewWrapper.appendChild(article); article.appendChild(viewTitle); article.appendChild(latestProject); article.appendChild(listProject); diff --git a/src/views/project-view/styles.css b/src/views/project-view/styles.css deleted file mode 100644 index 0d2814f..0000000 --- a/src/views/project-view/styles.css +++ /dev/null @@ -1,4 +0,0 @@ -section { - margin:0; - padding: 58px 0; -} \ No newline at end of file diff --git a/src/views/project-view/index.ts b/src/views/project.ts similarity index 97% rename from src/views/project-view/index.ts rename to src/views/project.ts index bc3291e..d4165a7 100644 --- a/src/views/project-view/index.ts +++ b/src/views/project.ts @@ -1,10 +1,9 @@ -import "./styles.css"; -import { +import { writeTitle, createVideoShowcase, writeParagraph, createContentGallery, createBackground -} from "../utils" +} from "./utils" export type ProjectContent = { diff --git a/src/views/utils/styles.css b/src/views/styles.css similarity index 90% rename from src/views/utils/styles.css rename to src/views/styles.css index 93eab85..42ec096 100644 --- a/src/views/utils/styles.css +++ b/src/views/styles.css @@ -1,4 +1,8 @@ -#view-box { +body { + background-color: black; +} + +#view-box { padding-left: 280px; height: 100%; font-family: "Cabin", sans-serif; @@ -9,6 +13,10 @@ margin: 0 auto; padding-top: 60px; + section { + margin:0; + padding: 58px 0; + } .showcase { margin: 50px 0; @@ -22,7 +30,7 @@ width: 100%; padding-top: 65px; z-index: -2; - background-image: url("./assets/video-showcase-decoration.png"); + background-image: url("utils/assets/video-showcase-decoration.png"); background-blend-mode: multiply; background-repeat: repeat-x; filter: invert(100%) sepia(100%) hue-rotate(240deg) saturate(100%); @@ -114,7 +122,7 @@ .layer-a { position: fixed; - background-image: url("./assets/background-test.png"); + background-image: url("utils/assets/background-test.png"); width: 100%; height: 100%; z-index: -11; diff --git a/src/views/utils/index.ts b/src/views/utils/index.ts index 1ae2ad7..d6f030c 100644 --- a/src/views/utils/index.ts +++ b/src/views/utils/index.ts @@ -1,6 +1,3 @@ -import './styles.css'; - -export * from "./text-utils.ts"; +export * from "./text-utils.ts"; export * from "./visual-utils.ts"; -export * from "./view-utils.ts"; export * from "./backgrounds-utils.ts"; \ No newline at end of file