Skip to content
Open
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
7 changes: 7 additions & 0 deletions apps/_template/codegen.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
overwrite: true
schema: "https://graph.codeday.org/"
documents: "./src/**/*.gql"
generates:
./src/@types/graphql-modules.d.ts:
plugins:
- typescript-graphql-files-modules
108 changes: 108 additions & 0 deletions apps/_template/gql-loader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"use strict";
const path = require("path");
const fs = require("fs");
const { parse, visit } = require("graphql");

function resolveImports(source, filePath, visited = new Set()) {
if (visited.has(filePath)) return [];
visited.add(filePath);

const dir = path.dirname(filePath);
const lines = source.split(/\r\n|\r|\n/);
let definitions = [];
const queryLines = [];

for (const line of lines) {
if (line.trim().startsWith("#import")) {
const match = line.match(/#import\s+["']([^"']+)["']/);
if (match) {
const importPath = path.resolve(dir, match[1]);
const importSource = fs.readFileSync(importPath, "utf-8");
definitions = definitions.concat(resolveImports(importSource, importPath, visited));
}
} else {
queryLines.push(line);
}
}

const cleanSource = queryLines.join("\n").trim();
if (cleanSource) {
const doc = parse(cleanSource);
definitions = definitions.concat(doc.definitions);
}

return definitions;
}

function deduplicateDefs(defs) {
const seen = new Set();
return defs
.slice()
.reverse()
.filter((def) => {
if (def.kind === "FragmentDefinition") {
if (seen.has(def.name.value)) return false;
seen.add(def.name.value);
}
return true;
})
.reverse();
}

function collectFragmentRefs(def) {
const refs = new Set();
visit(def, {
FragmentSpread(node) {
refs.add(node.name.value);
},
});
return refs;
}

function getTransitiveDeps(name, definitionMap, seen = new Set()) {
if (seen.has(name)) return seen;
seen.add(name);
const def = definitionMap.get(name);
if (def) {
for (const ref of collectFragmentRefs(def)) {
getTransitiveDeps(ref, definitionMap, seen);
}
}
return seen;
}

module.exports = function (source) {
if (this.cacheable) this.cacheable();

const allDefs = resolveImports(source, this.resourcePath);
const uniqueDefs = deduplicateDefs(allDefs);

const definitionMap = new Map();
for (const def of uniqueDefs) {
if (def.name) {
definitionMap.set(def.name.value, def);
}
}

const namedDefs = uniqueDefs.filter(
(d) => (d.kind === "OperationDefinition" || d.kind === "FragmentDefinition") && d.name,
);

function stripLoc(key, val) {
return key === "loc" ? undefined : val;
}

const fullDoc = { kind: "Document", definitions: uniqueDefs };
let output = `const _doc = ${JSON.stringify(fullDoc, stripLoc)};\n`;
output += `export default _doc;\n\n`;

for (const def of namedDefs) {
const name = def.name.value;
const deps = getTransitiveDeps(name, definitionMap);
const subsetDefs = uniqueDefs.filter((d) => d.name && deps.has(d.name.value));
const subsetDoc = { kind: "Document", definitions: subsetDefs };
output += `export const ${name} = ${JSON.stringify(subsetDoc, stripLoc)};\n`;
}

return output;
};
6 changes: 6 additions & 0 deletions apps/_template/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
24 changes: 24 additions & 0 deletions apps/_template/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { NextConfig } from "next";
import path from "path";

const nextConfig: NextConfig = {
transpilePackages: ["@codeday/topo", "@codeday/topocons"],
turbopack: {
rules: {
"*.gql": {
loaders: [path.resolve("gql-loader.js")],
as: "*.js",
},
},
},
webpack(config) {
config.module.rules.push({
test: /\.gql$/,
exclude: /node_modules/,
loader: path.resolve("gql-loader.js"),
});
return config;
},
};

export default nextConfig;
30 changes: 30 additions & 0 deletions apps/_template/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "@codeday/APPNAME",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"codegen": "echo 'Add .gql files to src/ then run: graphql-codegen'"
},
"dependencies": {
"@codeday/topo": "workspace:*",
"@codeday/topocons": "workspace:*",
"@codeday/utils": "workspace:*",
"graphql": "catalog:",
"graphql-tag": "^2.12.6",
"next": "catalog:",
"react": "catalog:",
"react-dom": "catalog:"
},
"devDependencies": {
"@codeday/tsconfig": "workspace:*",
"@graphql-codegen/cli": "^5.0.6",
"@graphql-codegen/typescript-graphql-files-modules": "^3.0.0",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"typescript": "catalog:"
}
}
12 changes: 12 additions & 0 deletions apps/_template/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ThemeProvider, PageDataProvider } from "@codeday/topo/Theme";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
return (
<ThemeProvider>
<PageDataProvider value={pageProps?.query || {}}>
<Component {...pageProps} />
</PageDataProvider>
</ThemeProvider>
);
}
11 changes: 11 additions & 0 deletions apps/_template/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Content } from "@codeday/topo/Molecule";
import { Heading, Text } from "@codeday/topo/Atom";

export default function Home() {
return (
<Content>
<Heading>Hello World</Heading>
<Text>Replace this with your app content.</Text>
</Content>
);
}
8 changes: 8 additions & 0 deletions apps/_template/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@codeday/tsconfig/nextjs.json",
"compilerOptions": {
"typeRoots": ["./src/@types"]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
52 changes: 1 addition & 51 deletions apps/www/src/components/Calendly.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1 @@
import { Box } from "@codeday/topo/Atom";
import React, { useEffect, useState, useRef } from "react";

interface CalendlyProps {
slug: string;
meeting?: string;
calendlyURLParams?: string;
[key: string]: any;
}

export default function Calendly({ slug, meeting, calendlyURLParams, ...props }: CalendlyProps) {
const holder = useRef<HTMLDivElement>(null);
const [hasCalendlyLoaded, setHasCalendlyLoaded] = useState(false);

const typeOfWindow = typeof window; // For static analysis
const windowCalendly = typeOfWindow !== "undefined" && (window as any)?.Calendly;

useEffect(() => {
if (window && !(window as any).Calendly) {
const script = document.createElement("script");
script.src = "https://calendly.com/assets/external/widget.js";
script.addEventListener("load", () => {
setHasCalendlyLoaded(true);
});
document.head.appendChild(script);

const link = document.createElement("link");
link.href = "https://calendly.com/assets/external/widget.css";
link.rel = "stylesheet";
document.body.appendChild(link);

return () => {
document.head.removeChild(script);
document.body.removeChild(link);
};
}
}, [typeOfWindow]);

useEffect(() => {
if (windowCalendly && holder) {
(window as any).Calendly.initInlineWidget({
url: `https://calendly.com/${slug}${meeting ? `/${meeting}` : ""}${calendlyURLParams || ""}`,
parentElement: holder.current,
prefill: {},
utm: {},
});
}
}, [windowCalendly, hasCalendlyLoaded, holder, slug, meeting]);

return <Box w="100%" h="50em" border="none" {...props} ref={holder} />;
}
export { CalendlyEmbed as default } from "@codeday/topo/Molecule";
4 changes: 2 additions & 2 deletions apps/www/src/components/Contact/Employees.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Text, Box, Grid, Image, Link } from "@codeday/topo/Atom";
import { Content } from "@codeday/topo/Molecule";
import React from "react";

import { useQuery } from "../../query";
import { usePageData } from "@codeday/topo/Theme";

const titleContents = ["CEO", "President", "VP", "Chief", "Director", "Head", "Manager", "Lead"];
const titlePrecedence = (title: string) =>
Expand All @@ -29,7 +29,7 @@ function dedupeByKey(key: string, arr: any[]) {
export default function Employees(props: any) {
const {
account: { employees, otherTeam, contractors },
} = useQuery();
} = usePageData();

const sortedEmployees = dedupeByKey("username", [
...employees,
Expand Down
60 changes: 60 additions & 0 deletions apps/www/src/components/EventInfo/SubscribeBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Box, Button, TextInput as Input } from "@codeday/topo/Atom";
import { useToasts, apiFetch } from "@codeday/topo/utils";
import React, { useState } from "react";
import { stringify as urlencode } from "urlencode";
import { DateTime } from "luxon";

import { SubscribeToEvent } from "./EventInfo.gql";

export default function SubscribeBox({ event, ...rest }: { event: any; [key: string]: any }) {
const { success, error } = useToasts();
const [destination, setDestination] = useState("");
const dtFormat = `yyyyLLdd'T'HHmmss`;
const start = DateTime.fromISO(event.start).toUTC().toFormat(dtFormat);
const end = DateTime.fromISO(event.end).toUTC().toFormat(dtFormat);
const addLinkGoogleParams = urlencode({
action: "TEMPLATE",
text: event.title,
dates: `${start}Z/${end}Z`,
location: event.location,
sf: "true",
output: "xml",
});
const addLinkGoogle = `https://www.google.com/calendar/render?${addLinkGoogleParams}`;
return (
<Box {...rest}>
<Input
value={destination}
onChange={(e: any) => setDestination(e.target.value)}
placeholder="Phone Number"
display="inline-block"
w="sm"
borderTopRightRadius={0}
borderBottomRightRadius={0}
/>
<Button
borderTopLeftRadius={0}
borderBottomLeftRadius={0}
position="relative"
colorPalette="blue"
onClick={async () => {
try {
await apiFetch(
SubscribeToEvent,
{ id: event.id, calendarId: event.calendarId, destination },
{},
);
success(`We'll let you know when this event starts.`);
} catch (ex: any) {
error(ex.toString());
}
}}
>
Remind Me
</Button>
<Button as="a" {...({ href: addLinkGoogle, target: "_blank" } as any)} ml={2}>
Add to Google Calendar
</Button>
</Box>
);
}
Loading