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

v1.57.0 #728

Merged
merged 5 commits into from
Aug 30, 2024
Merged
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
4 changes: 2 additions & 2 deletions api/_lib/_dates.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { format, parse, parseISO } from "date-fns";

export function niceDate(d: string) {
return format(parse(d, "yyyy-MM-dd", new Date()), "LLLL d, yyyy");
export function niceDate(d: Date) {
return format(d, "LLLL d, yyyy");
}

export function dateString(d: string) {
Expand Down
2 changes: 1 addition & 1 deletion api/blog/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default async function handler(req: VercelRequest, res: VercelResponse) {
if (!("properties" in post)) throw new Error("No properties");
const { properties = {}, id } = post;
const { date, ...props } = getNestedProperties(properties);
const publishDate = niceDate(date);
const publishDate = niceDate(new Date(date));

const htmlContent = await getPostHtmlFromId(id);

Expand Down
66 changes: 47 additions & 19 deletions api/blog/posts.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,59 @@
import { VercelRequest, VercelResponse } from "@vercel/node";
import { dateAsNumber, dateString, niceDate } from "../_lib/_dates";
import { notion, getNestedProperties } from "../_lib/_notion";
import { niceDate } from "../_lib/_dates";
import { notion } from "../_lib/_notion";
import { z } from "zod";
import { BlogPost, NotionPost } from "shared";

export default async function handler(req: VercelRequest, res: VercelResponse) {
const response = await notion.databases.query({
database_id: "b7a09b10aa83485b94092269239a8b38",
});
const posts = response.results.map((page) => {
if (!("properties" in page)) throw new Error("No properties");
const { properties = {}, id } = page;
const { date, ...props } = getNestedProperties(properties);
if (!("title" in props)) throw new Error("No title");
if (!("status" in props)) throw new Error("No status");
if (!("slug" in props)) throw new Error("No slug");
if (!("description" in props)) throw new Error("No description");

if (!date) throw new Error("No date");

const sanitizedDate = dateString(date);
const publishDate = niceDate(date);
const rawDate = dateAsNumber(date);

return { id, rawDate, date: sanitizedDate, publishDate, ...props };
});

const notionPosts = response.results.filter(
isValidNotionPost
) as unknown as NotionPost[];

const posts = notionPosts.map(notionPostToBlogPost);

// Cache for 1 week, stale-while-revalidate
res.setHeader("Cache-Control", "s-maxage=1, stale-while-revalidate");

res.json(posts);
}

const postSchema: z.ZodType<NotionPost> = z.object({
id: z.string(),
created_time: z.string(),
properties: z.object({
title: z.object({
title: z.array(z.object({ plain_text: z.string() })).min(1),
}),
description: z.object({
rich_text: z.array(z.object({ plain_text: z.string() })).min(1),
}),
status: z.object({
status: z.object({ name: z.string() }),
}),
slug: z.object({
rich_text: z.array(z.object({ plain_text: z.string() })).min(1),
}),
}),
});

function isValidNotionPost(post: unknown): post is NotionPost {
const parsed = postSchema.safeParse(post);
if (parsed.success) return true;
return false;
}

function notionPostToBlogPost(post: NotionPost): BlogPost {
return {
id: post.id,
publishDate: new Date(post.created_time).getTime(),
niceDate: niceDate(new Date(post.created_time)),
description: post.properties.description.rich_text[0].plain_text,
slug: post.properties.slug.rich_text[0].plain_text,
status: post.properties.status.status.name,
title: post.properties.title.title[0].plain_text,
};
}
2 changes: 1 addition & 1 deletion api/prompt/_shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export async function handleRateLimit(
redis: kv,
limiter: isPro
? Ratelimit.slidingWindow(3, "1m")
: Ratelimit.fixedWindow(3, "30d"),
: Ratelimit.fixedWindow(2, "30d"),
});

const rateLimitKey = isPro ? `pro_${customerId}` : `unauth_${ip}`;
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "app",
"version": "1.56.2",
"version": "1.57.0",
"main": "module/module.js",
"license": "MIT",
"scripts": {
Expand Down
Binary file modified app/public/template-screenshots/code-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/decision-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/mindmap-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/mindmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/network-diagram-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/org-chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/pert-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/playful-mindmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/public/template-screenshots/process-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_code-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_decision-flow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_flowchart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_knowledge-graph.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_mindmap-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_mindmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_network-diagram-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_network-diagram-icons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_org-chart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_pert-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified app/public/template-screenshots/thumb_playful-mindmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 5 additions & 20 deletions app/scripts/screenshot-templates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ async function main() {

await screenshotTemplates(filteredTemplates);
await createThumbnails(filteredTemplates);
await createTemplatesIndex(templates); // Always create index with all templates
console.log(
"Don't forget to add the new templates to `shared/src/templates.ts` file."
);
}

/**
Expand Down Expand Up @@ -75,8 +77,8 @@ async function takeScreenshot(browser, template) {
console.error("Error loading template", error);
}

// wait a few seconds
await page.waitForTimeout(3000);
// wait 3 seconds
await new Promise((resolve) => setTimeout(resolve, 3000));

// get the full page link
const screenshotLink = await page.evaluate(() => {
Expand Down Expand Up @@ -137,21 +139,4 @@ async function createThumbnails(templates) {
}
}

async function createTemplatesIndex(templates) {
console.log("Creating templates index...");
const indexPath = path.join(__dirname, "../../shared/templates.ts");
const indexContent = `export const templates = ${JSON.stringify(
templates,
null,
2
)} as const;`;

try {
await writeFile(indexPath, indexContent, "utf8");
console.log("✅ Created templates index file");
} catch (error) {
console.error("Error creating templates index file:", error);
}
}

main().catch(console.error);
31 changes: 27 additions & 4 deletions app/src/components/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ const Graph = memo(function Graph({ shouldResize }: { shouldResize: number }) {
export default Graph;

function handleDragFree() {
// If the layout is fcose, we don't want to freeze the layout
// because people may not expect that behavior / Subject to change!
const layout = useGraphStore.getState().layout;
if (layout.name === "fcose" || layout.name === "stress") return;

const nodePositions = getNodePositionsFromCy();
useDoc.setState(
(state) => {
Expand Down Expand Up @@ -240,6 +245,10 @@ function initializeGraph({
}
);

cyCurrent.on("dragstart", "node", () => {
// stop the layout from running
window.__cy?.stop();
});
cyCurrent.on("dragfree", handleDragFree);

// on zoom
Expand Down Expand Up @@ -344,14 +353,13 @@ function getGraphUpdater({

elements = getElements(doc.text);

// Test
cyErrorCatcher.current.json({ elements, layout, style });

// Very specific bug wrt to cose layouts
// If it's the first render, randomize cannot be false
// Because the graph has no positions yet
if (layout.name === "fcose") {
if (isFirstRender.current) {
// @ts-ignore
layout.animate = false;
// @ts-ignore
layout.randomize = true;
// @ts-ignore
Expand All @@ -362,8 +370,20 @@ function getGraphUpdater({
}
}

// Stress layout, need to turn off interactive and animation on first render
// @ts-ignore
layout.animate = false;
if (layout.name === "elk" && layout.elk.algorithm === "stress") {
if (isFirstRender.current) {
// @ts-ignore
layout.elk.interactive = false;
// @ts-ignore
layout.animate = false;
// @ts-ignore
delete layout.animationDuration;
// @ts-ignore
delete layout.animationEasing;
}
}

// Finally we get rid of layouts when user has dragged
// Apply the preset layout if nodePositions is defined
Expand All @@ -376,6 +396,9 @@ function getGraphUpdater({
delete layout.spacingFactor;
}

// Test
cyErrorCatcher.current.json({ elements, layout, style });

cyErrorCatcher.current.layout(layout);

// Set up a listener to mark the graph as initialized after the first layout run
Expand Down
74 changes: 2 additions & 72 deletions app/src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint-disable jsx-a11y/no-distracting-elements */
import cx from "classnames";
import { X } from "phosphor-react";
import { memo, ReactNode, Suspense, useState } from "react";
import { memo, ReactNode, Suspense } from "react";
import { Link } from "react-router-dom";

import { useFullscreen, useIsEditorView } from "../lib/hooks";
Expand All @@ -12,15 +11,12 @@ import styles from "./Layout.module.css";
import Loading from "./Loading";
import { VersionCheck } from "./VersionCheck";
import { PaywallModal } from "./PaywallModal";
import { Trans } from "@lingui/macro";

const Layout = memo(({ children }: { children: ReactNode }) => {
const isFullscreen = useFullscreen();
let [showBanner, message, messageType] = getShowBannerAndMessage();
const isEditorView = useIsEditorView();

const [showPHBanner, setShowPHBanner] = useState<boolean>(isPHBannerTime());

// fullscreen disables banners
if (isFullscreen) {
showBanner = false;
Expand All @@ -33,19 +29,8 @@ const Layout = memo(({ children }: { children: ReactNode }) => {
className={styles.LayoutWrapper}
data-showing={isEditorView ? "editor" : undefined}
data-fullscreen={isFullscreen}
data-banner={showBanner || showPHBanner}
data-banner={showBanner}
>
{showPHBanner ? (
<ProductHuntBanner
hide={() => {
setShowPHBanner(false);
// set a cookie to not show the banner again
document.cookie = `showPHBanner=false; path=/; max-age=${
60 * 60 * 24 * 30
}`;
}}
/>
) : null}
{showBanner ? (
<div
className={cx("flex justify-center items-center w-full gap-2", {
Expand Down Expand Up @@ -73,8 +58,6 @@ Layout.displayName = "Layout";

export default Layout;

// ?error=server_error&error_description=Multiple+accounts+with+the+same+email+address+in+the+same+linking+domain+detected%3A+default

function getShowBannerAndMessage(): [boolean, string, "error" | "info"] {
const hash = window.location.hash;
if (hash.startsWith("#message=")) {
Expand All @@ -91,56 +74,3 @@ function getShowBannerAndMessage(): [boolean, string, "error" | "info"] {
}
return [false, "", "info"];
}

/**
* Extremely Temporary Producthunt Banner
*/
export function ProductHuntBanner({ hide }: { hide: () => void }) {
return (
<a
href="https://www.producthunt.com/posts/flowchart-fun-2?embed=true&utm_source=badge-featured&utm_medium=badge&utm_souce=badge-flowchart-fun-2"
target="_blank"
rel="noopener noreferrer"
className="relative bg-gradient-to-b from-orange-400 to-orange-300/80 text-[#443214] hidden md:flex items-center justify-center group"
onClick={hide}
>
<p className="text-sm font-bold pl-4 z-10">
<Trans>
Love Flowchart Fun? Support us with a vote on Product Hunt!
</Trans>
</p>
<div className="w-[64px] h-[52px] overflow-hidden relative mix-blend-multiply rounded-full z-10">
<div className="absolute -top-px -right-px w-[250px] h-[54px]">
<img
src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=483202&theme=neutral"
alt="Flowchart Fun - Text-to-Flowchart with AI Magic 🪄 | Product Hunt"
width={250}
height={54}
/>
</div>
</div>
<div className="absolute top-0 left-0 w-full h-full bg-gradient-to-b from-transparent to-amber-500 hidden group-hover:block animate-pulseIn" />
</a>
);
}

/**
* This function returns true if it's August 25th, 2024, between 12:00am and 11:59pm PST
*/
export function isPHBannerTime() {
// check if the cookie exists
const cookie = document.cookie
.split("; ")
.find((row) => row.startsWith("showPHBanner="));
if (cookie) {
return false;
}

const pstDate = new Date().toLocaleString("en-US", {
timeZone: "America/Los_Angeles",
});
const [date] = pstDate.split(", ");
const [month, day, year] = date.split("/").map(Number);

return year === 2024 && month === 8 && day === 25;
}
2 changes: 2 additions & 0 deletions app/src/components/LoadTemplateDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ export function LoadTemplateDialog() {
});
}, [template, replaceContent, reset]);

console.log(templates);

return (
<Dialog.Root
open={open}
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/templates/mindmap-dark-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const theme: FFTheme = {
targetArrowShape: "none",
sourceDistanceFromNode: 5,
targetDistanceFromNode: 5,
edgeTextSize: 10,
edgeTextSize: 1,
rotateEdgeLabel: false,
direction: "DOWN",
fixedHeight: 300,
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/templates/network-diagram-dark-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const theme: FFTheme = {
sourceDistanceFromNode: 0,
targetDistanceFromNode: 6,
arrowScale: 0.8,
edgeTextSize: 10,
edgeTextSize: 1,
rotateEdgeLabel: false,
fixedHeight: 100,
};
Expand Down
2 changes: 1 addition & 1 deletion app/src/lib/templates/pert-light-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const theme: FFTheme = {
sourceDistanceFromNode: 5,
targetDistanceFromNode: 5,
arrowScale: 1,
edgeTextSize: 10,
edgeTextSize: 1,
rotateEdgeLabel: true,
};

Expand Down
Loading
Loading