WIP
This commit is contained in:
parent
a7523a7d5d
commit
3522af1a16
|
@ -1,12 +1,10 @@
|
||||||
import { appRegistry } from "pages/apps/_appRegistry";
|
import { App } from "@lib/apps/interfaces/App";
|
||||||
|
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
|
|
||||||
import AppCard from "./AppCard";
|
import AppCard from "./AppCard";
|
||||||
|
|
||||||
export default function AllApps() {
|
export default function AllApps({ apps }: { apps: App[] }) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const apps = appRegistry();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mb-16">
|
<div className="mb-16">
|
||||||
|
|
|
@ -2,16 +2,15 @@ import Glide from "@glidejs/glide";
|
||||||
import "@glidejs/glide/dist/css/glide.core.min.css";
|
import "@glidejs/glide/dist/css/glide.core.min.css";
|
||||||
import "@glidejs/glide/dist/css/glide.theme.min.css";
|
import "@glidejs/glide/dist/css/glide.theme.min.css";
|
||||||
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid";
|
import { ArrowLeftIcon, ArrowRightIcon } from "@heroicons/react/solid";
|
||||||
import { appRegistry } from "pages/apps/_appRegistry";
|
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import type { App } from "@lib/apps/interfaces/App";
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
import useMediaQuery from "@lib/hooks/useMediaQuery";
|
import useMediaQuery from "@lib/hooks/useMediaQuery";
|
||||||
|
|
||||||
import AppCard from "./AppCard";
|
import AppCard from "./AppCard";
|
||||||
|
|
||||||
export default function Slider() {
|
const Slider = <T extends App>({ items }: { items: T[] }) => {
|
||||||
const apps = appRegistry();
|
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const isMobile = useMediaQuery("(max-width: 767px)");
|
const isMobile = useMediaQuery("(max-width: 767px)");
|
||||||
const [size, setSize] = useState(3);
|
const [size, setSize] = useState(3);
|
||||||
|
@ -49,7 +48,7 @@ export default function Slider() {
|
||||||
</div>
|
</div>
|
||||||
<div className="glide__track" data-glide-el="track">
|
<div className="glide__track" data-glide-el="track">
|
||||||
<ul className="glide__slides">
|
<ul className="glide__slides">
|
||||||
{apps.map((app) => {
|
{items.map((app) => {
|
||||||
return (
|
return (
|
||||||
app.trending && (
|
app.trending && (
|
||||||
<li key={app.name} className="glide__slide">
|
<li key={app.name} className="glide__slide">
|
||||||
|
@ -71,4 +70,6 @@ export default function Slider() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default Slider;
|
||||||
|
|
|
@ -18,4 +18,14 @@ export type App = {
|
||||||
description: string;
|
description: string;
|
||||||
imageSrc: string;
|
imageSrc: string;
|
||||||
variant: "calendar" | "payment" | "conferencing";
|
variant: "calendar" | "payment" | "conferencing";
|
||||||
|
label: string;
|
||||||
|
slug: string;
|
||||||
|
category: string;
|
||||||
|
logo: string;
|
||||||
|
publisher: string;
|
||||||
|
url: string;
|
||||||
|
verified: boolean;
|
||||||
|
trending: boolean;
|
||||||
|
rating: number;
|
||||||
|
reviews: number;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { ChevronLeftIcon } from "@heroicons/react/solid";
|
import { ChevronLeftIcon } from "@heroicons/react/solid";
|
||||||
|
import { InferGetStaticPropsType } from "next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
import { getAppRegistry } from "@calcom/app-store/_appRegistry";
|
||||||
|
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
|
|
||||||
import Shell from "@components/Shell";
|
import Shell from "@components/Shell";
|
||||||
import AppCard from "@components/apps/AppCard";
|
import AppCard from "@components/apps/AppCard";
|
||||||
import Button from "@components/ui/Button";
|
import Button from "@components/ui/Button";
|
||||||
|
|
||||||
import { appRegistry } from "../_appRegistry";
|
export default function Apps({ appStore }: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
|
|
||||||
export default function Apps() {
|
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const apps = appRegistry();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Shell
|
<Shell
|
||||||
|
@ -27,7 +27,7 @@ export default function Apps() {
|
||||||
<div className="mb-16">
|
<div className="mb-16">
|
||||||
<h2 className="mb-2 text-lg font-semibold text-gray-900">All {router.query.category} apps</h2>
|
<h2 className="mb-2 text-lg font-semibold text-gray-900">All {router.query.category} apps</h2>
|
||||||
<div className="grid grid-cols-3 gap-3">
|
<div className="grid grid-cols-3 gap-3">
|
||||||
{apps.map((app) => {
|
{appStore.map((app) => {
|
||||||
return (
|
return (
|
||||||
app.category === router.query.category && (
|
app.category === router.query.category && (
|
||||||
<AppCard
|
<AppCard
|
||||||
|
@ -46,3 +46,26 @@ export default function Apps() {
|
||||||
</Shell>
|
</Shell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getStaticPaths = async () => {
|
||||||
|
const appStore = getAppRegistry();
|
||||||
|
const paths = appStore.reduce((categories, app) => {
|
||||||
|
if (!categories.includes(app.category)) {
|
||||||
|
categories.push(app.category);
|
||||||
|
}
|
||||||
|
return categories;
|
||||||
|
}, [] as string[]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
paths: paths.map((category) => ({ params: { category } })),
|
||||||
|
fallback: false,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getStaticProps = async () => {
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
appStore: getAppRegistry(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { getAppRegistry } from "@calcom/app-store/_appRegistry";
|
||||||
|
|
||||||
import { useLocale } from "@lib/hooks/useLocale";
|
import { useLocale } from "@lib/hooks/useLocale";
|
||||||
|
|
||||||
import AppsShell from "@components/AppsShell";
|
import AppsShell from "@components/AppsShell";
|
||||||
|
@ -6,31 +8,35 @@ import AllApps from "@components/apps/AllApps";
|
||||||
import AppStoreCategories from "@components/apps/Categories";
|
import AppStoreCategories from "@components/apps/Categories";
|
||||||
import Slider from "@components/apps/Slider";
|
import Slider from "@components/apps/Slider";
|
||||||
|
|
||||||
export default function Apps() {
|
export default function Apps({ appStore, categories }) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
const popularCategories = [
|
|
||||||
{
|
|
||||||
name: "Payments",
|
|
||||||
count: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Video",
|
|
||||||
count: 3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Calendar",
|
|
||||||
count: 4,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Shell heading={t("app_store")} subtitle={t("app_store_description")} large>
|
<Shell heading={t("app_store")} subtitle={t("app_store_description")} large>
|
||||||
<AppsShell>
|
<AppsShell>
|
||||||
<AppStoreCategories categories={popularCategories} />
|
<AppStoreCategories categories={categories} />
|
||||||
<Slider />
|
<Slider items={appStore} />
|
||||||
<AllApps />
|
<AllApps apps={appStore} />
|
||||||
</AppsShell>
|
</AppsShell>
|
||||||
</Shell>
|
</Shell>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getStaticProps = async () => {
|
||||||
|
const appStore = getAppRegistry();
|
||||||
|
const categories = appStore.reduce((c, app) => {
|
||||||
|
if (c[app.category]) {
|
||||||
|
c[app.category] = c[app.category]++;
|
||||||
|
} else {
|
||||||
|
c[app.category] = 1;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
categories: Object.entries(categories).map(([name, count]) => ({ name, count })),
|
||||||
|
appStore,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -1,38 +1,9 @@
|
||||||
import fs from "fs";
|
export function getAppRegistry() {
|
||||||
import path from "path";
|
|
||||||
|
|
||||||
// It won't be called on client-side.
|
|
||||||
export async function getStaticProps() {
|
|
||||||
const appStoreDir = path.join(process.cwd(), "packages/appStore");
|
|
||||||
const filenames = fs.readdirSync(appStoreDir);
|
|
||||||
|
|
||||||
const apps = filenames.map((filename) => {
|
|
||||||
const filePath = path.join(appStoreDir, filename);
|
|
||||||
const fileContents = fs.readFileSync(filePath, "utf8");
|
|
||||||
|
|
||||||
// Generally you would parse/transform the contents
|
|
||||||
// For example you can transform markdown to HTML here
|
|
||||||
|
|
||||||
return {
|
|
||||||
filename,
|
|
||||||
content: fileContents,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
// By returning { props: posts }, the Blog component
|
|
||||||
// will receive `posts` as a prop at build time
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
posts: apps,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function appRegistry() {
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: "Zoom",
|
name: "Zoom",
|
||||||
slug: "zoom", // needs to be the same as the folder name
|
slug: "zoom", // needs to be the same as the folder name
|
||||||
category: "Video Conferencing",
|
category: "video",
|
||||||
description:
|
description:
|
||||||
"Zoom is the most popular video conferencing platform, joinable on the web or via desktop/mobile apps.",
|
"Zoom is the most popular video conferencing platform, joinable on the web or via desktop/mobile apps.",
|
||||||
logo: "/apps/zoom.svg",
|
logo: "/apps/zoom.svg",
|
||||||
|
@ -45,7 +16,7 @@ export function appRegistry() {
|
||||||
{
|
{
|
||||||
name: "Cal Video",
|
name: "Cal Video",
|
||||||
slug: "cal-video",
|
slug: "cal-video",
|
||||||
category: "Video Conferencing",
|
category: "video",
|
||||||
description:
|
description:
|
||||||
"Cal Video is the in-house web-based video conferencing platform powered by Daily.co, which is minimalistic and lightweight, but has most of the features you need.",
|
"Cal Video is the in-house web-based video conferencing platform powered by Daily.co, which is minimalistic and lightweight, but has most of the features you need.",
|
||||||
logo: "/apps/daily.svg",
|
logo: "/apps/daily.svg",
|
||||||
|
@ -59,7 +30,7 @@ export function appRegistry() {
|
||||||
{
|
{
|
||||||
name: "Google Meet",
|
name: "Google Meet",
|
||||||
slug: "google-meet",
|
slug: "google-meet",
|
||||||
category: "Video Conferencing",
|
category: "video",
|
||||||
description:
|
description:
|
||||||
"Google Meet is Google's web-based video conferencing platform, designed to compete with major conferencing platforms.",
|
"Google Meet is Google's web-based video conferencing platform, designed to compete with major conferencing platforms.",
|
||||||
logo: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png",
|
logo: "https://cdn.iconscout.com/icon/free/png-256/google-meet-2923654-2416657.png",
|
||||||
|
@ -69,8 +40,8 @@ export function appRegistry() {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Stripe",
|
name: "Stripe",
|
||||||
slug: "stripe",
|
slug: "stripe_payment",
|
||||||
category: "Payments",
|
category: "payment",
|
||||||
description: "Stripe is the world's leading payment provider. Start charging for your bookings today.",
|
description: "Stripe is the world's leading payment provider. Start charging for your bookings today.",
|
||||||
logo: "/apps/stripe.svg",
|
logo: "/apps/stripe.svg",
|
||||||
rating: 4.6,
|
rating: 4.6,
|
||||||
|
@ -80,7 +51,7 @@ export function appRegistry() {
|
||||||
{
|
{
|
||||||
name: "Google Calendar",
|
name: "Google Calendar",
|
||||||
slug: "google-calendar",
|
slug: "google-calendar",
|
||||||
category: "Calendar",
|
category: "calendar",
|
||||||
description:
|
description:
|
||||||
"Google Calendar is the most popular calendar platform for personal and business calendars.",
|
"Google Calendar is the most popular calendar platform for personal and business calendars.",
|
||||||
logo: "/apps/google-calendar.svg",
|
logo: "/apps/google-calendar.svg",
|
||||||
|
@ -90,7 +61,7 @@ export function appRegistry() {
|
||||||
{
|
{
|
||||||
name: "Microsoft 365/Outlook Calendar",
|
name: "Microsoft 365/Outlook Calendar",
|
||||||
slug: "microsoft-365",
|
slug: "microsoft-365",
|
||||||
category: "Calendar",
|
category: "calendar",
|
||||||
description:
|
description:
|
||||||
"Microsoft 365 calendars for business users, and Outlook is a popular calendar platform for personal users.",
|
"Microsoft 365 calendars for business users, and Outlook is a popular calendar platform for personal users.",
|
||||||
logo: "/apps/outlook.svg",
|
logo: "/apps/outlook.svg",
|
||||||
|
@ -100,7 +71,7 @@ export function appRegistry() {
|
||||||
{
|
{
|
||||||
name: "CalDAV",
|
name: "CalDAV",
|
||||||
slug: "caldav",
|
slug: "caldav",
|
||||||
category: "Calendar",
|
category: "calendar",
|
||||||
description: "CalDAV is an open calendar standard which connects to virtually every calendar.",
|
description: "CalDAV is an open calendar standard which connects to virtually every calendar.",
|
||||||
logo: "/apps/caldav.svg",
|
logo: "/apps/caldav.svg",
|
||||||
rating: 3.6,
|
rating: 3.6,
|
||||||
|
@ -109,7 +80,7 @@ export function appRegistry() {
|
||||||
{
|
{
|
||||||
name: "iCloud Calendar",
|
name: "iCloud Calendar",
|
||||||
slug: "icloud-calendar",
|
slug: "icloud-calendar",
|
||||||
category: "Calendar",
|
category: "calendar",
|
||||||
description:
|
description:
|
||||||
"iCloud Calendar is Apple's calendar platform for users of iCloud, and is used in the Apple Calendar app on iOS and macOS.",
|
"iCloud Calendar is Apple's calendar platform for users of iCloud, and is used in the Apple Calendar app on iOS and macOS.",
|
||||||
logo: "/apps/apple-calendar.svg",
|
logo: "/apps/apple-calendar.svg",
|
Loading…
Reference in New Issue
Block a user