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

Changelog project #1572

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
155 changes: 155 additions & 0 deletions components/ChangelogIndex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { useState, useEffect } from "react";
import { getPagesUnderRoute } from "nextra/context";
import { ImageFrame } from "./ImageFrame";
import { VideoButtonWithModal } from "./VideoButtonWithModal";
import Link from "next/link";

enum PostFilterOptions {
All = `all`,
Announcements = `announcements`,
Updates = `updates`,
}

const renderImage = (page) => {
return (
<ImageFrame
src={page.frontMatter.thumbnail}
alt={page.frontMatter.title}
isAnnouncement={page.frontMatter?.isAnnouncement}
/>
);
};

export default function ChangelogIndex({ more = "Learn More" }) {
// naturally sorts pages from a-z rather than z-a
const allPages = getPagesUnderRoute("/changelogs").reverse();
const itemsPerPage = 10;
const [displayedPages, setDisplayedPages] = useState([]);
const [pageIndex, setPageIndex] = useState(0);
const [filter, setFilter] = useState(PostFilterOptions.All);

const getAllFilteredPages = () => {
return allPages
.filter((page) => {
switch (filter) {
case PostFilterOptions.Updates:
// @ts-ignore:next-line
return !page.frontMatter?.isAnnouncement;
case PostFilterOptions.Announcements:
// @ts-ignore:next-line
return page.frontMatter?.isAnnouncement === true;
default:
return true;
}
})
}

// Load initial or additional pages
useEffect(() => {
const morePages = getAllFilteredPages().slice(0, pageIndex + itemsPerPage);

setDisplayedPages(morePages);
}, [pageIndex, filter]);

const loadMore = () => {
setPageIndex((prev) => prev + itemsPerPage);
};

const filterButton = (id: PostFilterOptions, label: string) => {
let className = "changelogFilterButton";
if (filter === id) {
className += " active";
}
return (
<button className={className} onClick={() => {
setFilter(id);
setPageIndex(0);
}}>
{label}
</button>
);
};

const filterOptions = [
{ id: PostFilterOptions.All, label: "All Posts" },
{ id: PostFilterOptions.Announcements, label: "Announcements" },
{ id: PostFilterOptions.Updates, label: "Updates" },
];

return (
<div
style={{
display: "flex",
alignItems: "center",
flexDirection: "column",
}}
className="changelogIndexContainer"
>
<div className="changelogIndexFilterBorder" />
<div className="changelogIndexFilterBar">
{filterOptions.map((filter) => filterButton(filter.id, filter.label))}
</div>

{displayedPages.map((page) => (
<div key={page.route} className="changelogIndexItem nx-mt-16">
<div className="changelogIndexItemDate">
{page.frontMatter?.date ? (
<p className="changelogDate">
{new Date(page.frontMatter.date).toLocaleDateString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
})}
</p>
) : null}
</div>

<div className="changelogIndexItemBody">
{page.frontMatter?.thumbnail && renderImage(page)}

<h3 className="changelogItemTitleWrapper">
<Link
href={page.route}
style={{ color: "inherit", textDecoration: "none" }}
className="changelogItemTitle block"
>
{page.meta?.title || page.frontMatter?.title || page.name}
</Link>
</h3>

<p className="opacity-80 mt-6 leading-7">
{page.frontMatter?.description}
</p>
<div className="nx-isolate nx-inline-flex nx-items-center nx-space-x-5 nx-mt-8">
{page.frontMatter?.isAnnouncement && (
<a
href="https://mixpanel.com/contact-us/demo-request/"
className="nx-px-5 nx-py-3 nx-my-4 nx-drop-shadow-sm nx-bg-gradient-to-t nx-from-purple100 nx-to-purple50 nx-rounded-full nx-text-white nx-font-medium nx-text-medium"
>
Request a Demo
</a>
)}
{page.frontMatter?.video && (
<VideoButtonWithModal
src={page.frontMatter.video}
showThumbnail={false}
/>
)}
<Link target="_blank" href={page.route} className="changelogReadMoreLink">
{more + " →"}
</Link>
</div>
<div className="changelogDivider nx-mt-16"></div>
</div>
</div>
))}
{pageIndex + itemsPerPage < getAllFilteredPages().length && (
<div className="changelogLoadMoreButtonContainer">
<button onClick={loadMore} className="changelogLoadMoreButton">
Load More
</button>
</div>
)}
</div>
);
}
31 changes: 31 additions & 0 deletions components/ChangelogPostHeader/ChangelogPostHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ImageFrame } from "../ImageFrame";

type ChangelogHeaderProps = {
date?: string;
image?: any;
title?: string;
};

export default function ChangelogPostHeader({
date,
image,
title,
}: ChangelogHeaderProps) {
return (
<div className="changelogPostHeader">
{date && (
<p className="changelogDate">
{new Date(date).toLocaleDateString(undefined, {
year: "numeric",
month: "long",
day: "numeric",
})}
</p>
)}

{title && <h3 className="changelogTitle">{title}</h3>}

{image && <ImageFrame src={image} alt={title} />}
</div>
);
}
78 changes: 78 additions & 0 deletions components/ImageFrame/ImageFrame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { useLayoutEffect, useRef, useState } from "react";
import Image from "next/image";
// https://www.tailwind-variants.org/docs
import { tv } from "tailwind-variants";

type ImageFrameProps = {
src: string;
alt?: string;
isAnnouncement?: boolean;
};

const MAX_IMAGE_HEIGHT_WITHOUT_OVERFLOW = 400;

export default function ImageFrame({
alt = "Thumbnail of screenshot",
isAnnouncement = false,
...props
}: ImageFrameProps) {
const imageRef = useRef<HTMLImageElement>(null);
const [height, setHeight] = useState(0);
const [width, setWidth] = useState(0);

useLayoutEffect(() => {
if (imageRef.current) {
setHeight(imageRef.current.getBoundingClientRect().height);
setWidth(imageRef.current.getBoundingClientRect().width);
}
}, []);

const isTall = height > MAX_IMAGE_HEIGHT_WITHOUT_OVERFLOW;

const imageFrame = tv({
base: "nx-aspect-video nx-overflow-hidden nx-nx-mt-8 lg:nx-rounded-3xl nx-rounded-xl nx-bg-[#EAE7E714] nx-bg-gradient-to-t nx-from-[#EAE7E70D] nx-mb-8 lg:nx-px-14",
variants: {
isTall: {
false: "nx-flex nx-justify-center nx-items-center",
},
},
});

const imageSelf = tv({
base: "nx-w-full max-h-96 h-full nx-shadow-sm",
variants: {
isTall: {
true: "nx-border nx-border-grey20",
false: "nx-rounded-2xl",
},
isAnnouncement: {
true: "lg:nx-rounded-3xl nx-rounded-xl nx-mb-8",
},
},
});

return isAnnouncement ? (
<Image
ref={imageRef}
src={props.src}
height={height}
width={width}
className={imageSelf({ isTall: isTall, isAnnouncement: isAnnouncement })}
alt={alt}
/>
) : (
<div className={imageFrame({ isTall: isTall })}>
<Image
ref={imageRef}
src={props.src}
height={height}
width={width}
className={imageSelf({
isTall: isTall,
isAnnouncement: isAnnouncement,
})}
alt={alt}
/>
</div>
);
}
1 change: 1 addition & 0 deletions components/ImageFrame/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as ImageFrame } from "./ImageFrame";
8 changes: 4 additions & 4 deletions components/MainContent/MainContent.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { FeedbackCollector } from "../FeedbackCollector/FeedbackCollector";

interface Props {
children: React.ReactNode
children: React.ReactNode;
}

const MainContent: React.FC<Props> = ({children}): JSX.Element => {
const MainContent: React.FC<Props> = ({ children }): JSX.Element => {
return (
<>
{children}
<FeedbackCollector />
</>
)
}
);
};

export default MainContent;
4 changes: 2 additions & 2 deletions components/SignUpButton/SignUpButton.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

.signUpButton {
box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
background-color: colors.$purple50;
font-weight: 600;
background: linear-gradient(1deg, colors.$purple100 0.97%, colors.$purple50 96.96%);
font-weight: 500;
font-size: 1rem;
line-height: 1.5rem;
color: colors.$white;
Expand Down
Loading