mirror of https://github.com/waku-org/metrics.git
new branch with devops sorted
This commit is contained in:
commit
09881b1249
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
.env
|
||||
|
||||
.idea/
|
|
@ -0,0 +1,34 @@
|
|||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
|
@ -0,0 +1,17 @@
|
|||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET(request) {
|
||||
const requestUrl = new URL(request.url);
|
||||
const code = requestUrl.searchParams.get("code");
|
||||
|
||||
if (code) {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
await supabase.auth.exchangeCodeForSession(code);
|
||||
}
|
||||
|
||||
return NextResponse.redirect(requestUrl.origin);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Unauthenticated!",
|
||||
},
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
}: {
|
||||
id: number;
|
||||
} = await request.json();
|
||||
|
||||
const db = await initiateDb();
|
||||
|
||||
await db.from("benchmarks").delete().eq("id", id);
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db
|
||||
.from("benchmarks")
|
||||
.select()
|
||||
.order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const db = await initiateDb();
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db
|
||||
.from("benchmarks")
|
||||
.select()
|
||||
.order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Unauthenticated!",
|
||||
},
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
value,
|
||||
}: {
|
||||
id: number | boolean | null;
|
||||
name: string;
|
||||
value: object;
|
||||
} = await request.json();
|
||||
|
||||
const db = await initiateDb();
|
||||
|
||||
if (id) {
|
||||
await db.from("benchmarks").update({ name, value }).eq("id", id);
|
||||
} else {
|
||||
await db.from("benchmarks").insert({ name, value });
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db
|
||||
.from("benchmarks")
|
||||
.select()
|
||||
.order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
import axios from "axios";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`https://hub.docker.com/v2/repositories/statusteam/nim-waku`
|
||||
);
|
||||
|
||||
return NextResponse.json(response.data);
|
||||
} catch (error) {
|
||||
throw new Error("Failed to fetch Docker Hub image data");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Unauthenticated!",
|
||||
},
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
id,
|
||||
}: {
|
||||
id: number;
|
||||
} = await request.json();
|
||||
|
||||
const db = await initiateDb();
|
||||
|
||||
await db.from("ecosystem").delete().eq("id", id);
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db
|
||||
.from("ecosystem")
|
||||
.select()
|
||||
.order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const db = await initiateDb();
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db
|
||||
.from("ecosystem")
|
||||
.select()
|
||||
.order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function POST(request) {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Unauthenticated!",
|
||||
},
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const db = await initiateDb();
|
||||
|
||||
const body = await request.formData();
|
||||
let data = {};
|
||||
|
||||
body.forEach((field, key) => (data[key] = field));
|
||||
|
||||
const { id, name, description, url, image } = data;
|
||||
|
||||
if (id !== "false") {
|
||||
await db.from("ecosystem").update({ name, description, url }).eq("id", id);
|
||||
|
||||
if (image) {
|
||||
await db.storage.from("public").update(`public/${id}.png`, image);
|
||||
}
|
||||
} else {
|
||||
const { data } = await db
|
||||
.from("ecosystem")
|
||||
.upsert({ name, description, url })
|
||||
.select();
|
||||
|
||||
if (image) {
|
||||
await db.storage.from("public").upload(`public/${data[0].id}.png`, image);
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db
|
||||
.from("ecosystem")
|
||||
.select()
|
||||
.order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const db = await initiateDb();
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db.from("saves").select().order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import initiateDb from "@/utils/db";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createRouteHandlerClient({ cookies });
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: "Unauthenticated!",
|
||||
},
|
||||
{ status: 401 }
|
||||
);
|
||||
}
|
||||
|
||||
const { name, data }: { name: string; data: object } = await request.json();
|
||||
|
||||
const db = await initiateDb();
|
||||
|
||||
await db.from("saves").insert({ name, data });
|
||||
|
||||
return NextResponse.json({
|
||||
data: (
|
||||
await db.from("saves").select().order("created_at", { ascending: false })
|
||||
).data,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
import axios from "axios";
|
||||
import addOAuthInterceptor from "axios-oauth-1.0a";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const client = axios.create();
|
||||
const options = {
|
||||
algorithm: "HMAC-SHA1",
|
||||
key: process.env.TWITTER_CONSUMER_KEY,
|
||||
secret: process.env.TWITTER_CONSUMER_SECRET,
|
||||
token: process.env.TWITTER_ACCESS_TOKEN,
|
||||
tokenSecret: process.env.TWITTER_TOKEN_SECRET,
|
||||
};
|
||||
|
||||
addOAuthInterceptor(client, options);
|
||||
|
||||
const { data } = await client.get(
|
||||
"https://api.twitter.com/2/users/me?user.fields=public_metrics",
|
||||
{
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return NextResponse.json(data.data.public_metrics);
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1,4 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import './globals.css'
|
||||
import { Inter } from 'next/font/google'
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] })
|
||||
|
||||
export const metadata = {
|
||||
title: 'Waku Metrics',
|
||||
description: 'Metrics dashboard for the waku network and ecosystem',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import Router from '@/components/Router'
|
||||
import Image from 'next/image'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className='bg-black w-full min-h-screen'>
|
||||
<Router />
|
||||
</main>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import "react-responsive-modal/styles.css";
|
||||
import { Modal } from "react-responsive-modal";
|
||||
import Loader from "@/components/atoms/Loader";
|
||||
import axios from "axios";
|
||||
import initiateDb from "@/utils/dbPublic";
|
||||
|
||||
export default function Benchmarks(props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const onOpenModal = () => setOpen(true);
|
||||
const onCloseModal = () => {
|
||||
setCurrentBenchmark(false);
|
||||
setName(null);
|
||||
setValue(null);
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const [benchmarks, setBenchmarks] = useState(false);
|
||||
const [currentBenchmark, setCurrentBenchmark] = useState(false);
|
||||
|
||||
const [name, setName] = useState(null);
|
||||
const [value, setValue] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const supabase = initiateDb();
|
||||
|
||||
const data = await supabase
|
||||
.from("benchmarks")
|
||||
.select()
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
setBenchmarks(data.data);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
async function handleSet(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const res = await axios.post("/api/benchmarks/set", {
|
||||
id: currentBenchmark ? currentBenchmark.id : false,
|
||||
name,
|
||||
value,
|
||||
});
|
||||
|
||||
setBenchmarks(res.data.data);
|
||||
onCloseModal();
|
||||
}
|
||||
|
||||
async function handleDelete(benchmark) {
|
||||
if (confirm("Are you sure to delete the benchmark?")) {
|
||||
const res = await axios.post("/api/benchmarks/delete", {
|
||||
id: benchmark.id,
|
||||
});
|
||||
|
||||
setBenchmarks(res.data.data);
|
||||
}
|
||||
}
|
||||
|
||||
const closeIcon = (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000000"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="m7 7l10 10M7 17L17 7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
const customStyles = {
|
||||
content: {
|
||||
borderRadius: "20px",
|
||||
backgroundColor: "black",
|
||||
bgColor: "black",
|
||||
},
|
||||
};
|
||||
|
||||
if (benchmarks === false) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-2xl">Benchmarks</h1>
|
||||
<h1 className="text-[#707071] hidden md:block">Powered by Waku</h1>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
style={customStyles}
|
||||
classNames="bg-black"
|
||||
closeIcon={closeIcon}
|
||||
open={open}
|
||||
onClose={onCloseModal}
|
||||
center
|
||||
>
|
||||
<div className="rounded-xl w-40 h-40 ">
|
||||
<div className="m-4">
|
||||
<h1 className="text-xl">
|
||||
{currentBenchmark ? "Edit" : "Add new"} benchmark
|
||||
</h1>
|
||||
<div className="mt-4">
|
||||
<form onSubmit={(e) => handleSet(e)} className="space-y-3">
|
||||
<input
|
||||
className="border-[#2c2c2c3e] border-2 w-full rounde -lg p-2 text-sm border-2 rounded-lg"
|
||||
placeholder="Label"
|
||||
value={name}
|
||||
required={true}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<input
|
||||
className="border-[#2c2c2c3e] border-2 w-full rounde -lg p-2 text-sm border-2 rounded-lg"
|
||||
placeholder="Value"
|
||||
required={true}
|
||||
value={value}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<div className="flex justify-end">
|
||||
<button className="bg-black rounded-lg text-white p-2">
|
||||
{currentBenchmark ? "Update benchmark" : "Add benchmark"}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{props.isLoggedIn && (
|
||||
<div className="flex justify-end mt-10 space-x-5">
|
||||
<button
|
||||
onClick={onOpenModal}
|
||||
className="flex space-x-3 items-center bg-[#202021] p-2 rounded-xl text-white hover:border-white hover:border-2"
|
||||
>
|
||||
<h1>Add benchmark</h1>
|
||||
<svg
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M18 13h-5v5c0 .55-.45 1-1 1s-1-.45-1-1v-5H6c-.55 0-1-.45-1-1s.45-1 1-1h5V6c0-.55.45-1 1-1s1 .45 1 1v5h5c.55 0 1 .45 1 1s-.45 1-1 1z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{benchmarks.length ? (
|
||||
<div className="flow-root rounded-lg border border-gray-100 py-3 shadow-sm dark:border-gray-700 mt-10">
|
||||
<dl className="-my-3 divide-y divide-gray-100 text-sm dark:divide-gray-700">
|
||||
{benchmarks.map((benchmark, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="grid grid-cols-1 gap-1 p-3 even:bg-gray-50 even:dark:bg-[#202021] sm:grid-cols-5 sm:gap-4"
|
||||
>
|
||||
<dt className="font-medium text-gray-900 dark:text-white">
|
||||
{benchmark.name}
|
||||
</dt>
|
||||
<dd className="text-gray-700 dark:text-gray-200 sm:col-span-2">
|
||||
{benchmark.value}
|
||||
</dd>
|
||||
<dd className="sm:col-span-2">
|
||||
{props.isLoggedIn && (
|
||||
<div className="flex space-x-2 items-center justify-end">
|
||||
<svg
|
||||
onClick={() => {
|
||||
setCurrentBenchmark(benchmark);
|
||||
setName(benchmark.name);
|
||||
setValue(benchmark.value);
|
||||
onOpenModal();
|
||||
}}
|
||||
className="w-7 h-7 rounded-xl p-1 hover:bg-yellow-200"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M5 19h1.4l8.625-8.625l-1.4-1.4L5 17.6V19ZM19.3 8.925l-4.25-4.2l1.4-1.4q.575-.575 1.413-.575t1.412.575l1.4 1.4q.575.575.6 1.388t-.55 1.387L19.3 8.925ZM17.85 10.4L7.25 21H3v-4.25l10.6-10.6l4.25 4.25Zm-3.525-.725l-.7-.7l1.4 1.4l-.7-.7Z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
className="w-7 h-7 rounded-xl p-1 hover:bg-red-200"
|
||||
viewBox="0 0 256 256"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
onClick={() => handleDelete(benchmark)}
|
||||
>
|
||||
<path
|
||||
fill="#FFF"
|
||||
d="M216 48h-40v-8a24 24 0 0 0-24-24h-48a24 24 0 0 0-24 24v8H40a8 8 0 0 0 0 16h8v144a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16V64h8a8 8 0 0 0 0-16ZM96 40a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8v8H96Zm96 168H64V64h128Zm-80-104v64a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Zm48 0v64a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
) : (
|
||||
<div>No benchmarks yet!</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,595 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import CommunityMetricsCard from "@/components/molecules/CommunityMetricsCard";
|
||||
|
||||
export default function CommunityMetrics(props) {
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-2xl">
|
||||
{props.save !== undefined ? props.save.name : "Community metrics"}
|
||||
</h1>
|
||||
<h1 className="text-[#707071] hidden md:block">Powered by Waku</h1>
|
||||
</div>
|
||||
|
||||
{props.setCurrent !== undefined && (
|
||||
<div className={"flex row mt-2 justify-start"}>
|
||||
<button
|
||||
className={"bg-gray-400 p-2 rounded"}
|
||||
onClick={() => props.setCurrent(null)}
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-5 mt-5 justify-between">
|
||||
<h1 className="text-[#707071]">Community channels </h1>
|
||||
<CommunityMetricsCard
|
||||
title={"Discord members"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.discord}
|
||||
previous={props.previous?.data?.stats?.discord}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"X (Twitter) followers"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.twitter}
|
||||
previous={props.previous?.data?.stats?.twitter}
|
||||
/>
|
||||
|
||||
<h1 className="text-[#707071]">GitHub</h1>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"Total GitHub followers (organization wide)"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github}
|
||||
previous={props.previous?.data?.stats?.github}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"Total GitHub stars (organization wide)"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.total?.stars}
|
||||
previous={props.previous?.data?.stats?.github_repos?.total?.stars}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"Total GitHub forks (organization wide)"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.total?.forks}
|
||||
previous={props.previous?.data?.stats?.github_repos?.total?.forks}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"Total GitHub stars (nwaku)"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.nwaku?.stars}
|
||||
previous={props.previous?.data?.stats?.github_repos?.nwaku?.stars}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"Total GitHub forks (nwaku)"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.nwaku?.forks}
|
||||
previous={props.previous?.data?.stats?.github_repos?.nwaku?.forks}
|
||||
/>
|
||||
|
||||
<h1 className="text-[#707071]">SDKs</h1>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"NPM downloads"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.npm}
|
||||
previous={props.previous?.data?.stats?.npm}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"js-waku stars"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["js-waku"]?.stars}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["js-waku"]?.stars
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"js-waku forks"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["js-waku"]?.forks}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["js-waku"]?.forks
|
||||
}
|
||||
/>
|
||||
<CommunityMetricsCard
|
||||
title={"js-waku open issues"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["js-waku"]?.open_issues}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["js-waku"]?.open_issues
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"Rust downloads"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.rust}
|
||||
previous={props.previous?.data?.stats?.rust}
|
||||
/>
|
||||
<CommunityMetricsCard
|
||||
title={"waku-rust-bindings stars"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["waku-rust-bindings"]?.stars}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["waku-rust-bindings"]
|
||||
?.stars
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"waku-rust-bindings forks"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["waku-rust-bindings"]?.forks}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["waku-rust-bindings"]
|
||||
?.forks
|
||||
}
|
||||
/>
|
||||
<CommunityMetricsCard
|
||||
title={"waku-rust-bindings open issues"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={
|
||||
props.stats?.github_repos?.["waku-rust-bindings"]?.open_issues
|
||||
}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["waku-rust-bindings"]
|
||||
?.open_issues
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"go-waku stars"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["go-waku"]?.stars}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["go-waku"]?.stars
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"go-waku forks"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["go-waku"]?.forks}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["go-waku"]?.forks
|
||||
}
|
||||
/>
|
||||
<CommunityMetricsCard
|
||||
title={"go-waku open issues"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["go-waku"]?.open_issues}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["go-waku"]?.open_issues
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"waku-react-native stars"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["waku-react-native"]?.stars}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["waku-react-native"]
|
||||
?.stars
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"waku-react-native forks"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["waku-react-native"]?.forks}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["waku-react-native"]
|
||||
?.forks
|
||||
}
|
||||
/>
|
||||
<CommunityMetricsCard
|
||||
title={"waku-react-native open issues"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={
|
||||
props.stats?.github_repos?.["waku-react-native"]?.open_issues
|
||||
}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["waku-react-native"]
|
||||
?.open_issues
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"js-waku-examples stars"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["js-waku-examples"]?.stars}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["js-waku-examples"]
|
||||
?.stars
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"js-waku-examples forks"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["js-waku-examples"]?.forks}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["js-waku-examples"]
|
||||
?.forks
|
||||
}
|
||||
/>
|
||||
<CommunityMetricsCard
|
||||
title={"js-waku-examples open issues"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.github_repos?.["js-waku-examples"]?.open_issues}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.["js-waku-examples"]
|
||||
?.open_issues
|
||||
}
|
||||
/>
|
||||
|
||||
<CommunityMetricsCard
|
||||
title={"nwaku docker pulls"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats?.docker}
|
||||
previous={props.previous?.data?.docker}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
import React, { useState } from "react";
|
||||
import "react-responsive-modal/styles.css";
|
||||
import { Modal } from "react-responsive-modal";
|
||||
import { useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import Loader from "@/components/atoms/Loader";
|
||||
import initiateDb from "@/utils/dbPublic";
|
||||
|
||||
export default function Ecosystem(props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const onOpenModal = () => setOpen(true);
|
||||
const onCloseModal = () => {
|
||||
setCurrent(false);
|
||||
setImage(null);
|
||||
setName(null);
|
||||
setDescription(null);
|
||||
setUrl(null);
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
const [ecosystem, setEcosystem] = useState(false);
|
||||
|
||||
const [current, setCurrent] = useState(false);
|
||||
|
||||
const [image, setImage] = useState(null);
|
||||
const [name, setName] = useState(null);
|
||||
const [description, setDescription] = useState(null);
|
||||
const [url, setUrl] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const supabase = initiateDb();
|
||||
|
||||
const data = await supabase
|
||||
.from("ecosystem")
|
||||
.select()
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
setEcosystem(data.data);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
async function handleSet(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const data = new FormData();
|
||||
|
||||
data.append("id", current ? current.id : false);
|
||||
if (image !== null) {
|
||||
data.append("image", image);
|
||||
}
|
||||
data.append("name", name);
|
||||
data.append("description", description);
|
||||
data.append("url", url);
|
||||
|
||||
const res = await axios.post("/api/ecosystem/set", data);
|
||||
|
||||
setEcosystem(res.data.data);
|
||||
onCloseModal();
|
||||
}
|
||||
|
||||
async function handleDelete(project) {
|
||||
if (confirm("Are you sure to delete the project?")) {
|
||||
const res = await axios.post("/api/ecosystem/delete", {
|
||||
id: project.id,
|
||||
});
|
||||
|
||||
setEcosystem(res.data.data);
|
||||
}
|
||||
}
|
||||
|
||||
const closeIcon = (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000000"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="m7 7l10 10M7 17L17 7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
const customStyles = {
|
||||
content: {
|
||||
borderRadius: "20px",
|
||||
backgroundColor: "black",
|
||||
bgColor: "black",
|
||||
},
|
||||
};
|
||||
|
||||
if (ecosystem === false) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-2xl">Ecosystem directory</h1>
|
||||
<h1 className="text-[#707071] hidden md:block">Powered by Waku</h1>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
style={customStyles}
|
||||
classNames="bg-black"
|
||||
closeIcon={closeIcon}
|
||||
open={open}
|
||||
onClose={onCloseModal}
|
||||
center
|
||||
>
|
||||
<div className="rounded-xl w-40 h-40 ">
|
||||
<div className="m-4">
|
||||
<h1 className="text-xl">{current ? "Edit" : "Add new"} project</h1>
|
||||
<div className="mt-4">
|
||||
<form onSubmit={(e) => handleSet(e)} className="space-y-3">
|
||||
<label>
|
||||
<svg
|
||||
className="w-14 h-14 bg-black rounded-full p-2"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M14 7.5a1.5 1.5 0 1 1-3 0a1.5 1.5 0 0 1 3 0Zm-1 0a.5.5 0 1 0-1 0a.5.5 0 0 0 1 0ZM3 6a3 3 0 0 1 3-3h8a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3V6Zm3-2a2 2 0 0 0-2 2v8c0 .373.102.722.28 1.02l4.669-4.588a1.5 1.5 0 0 1 2.102 0l4.67 4.588A1.99 1.99 0 0 0 16 14V6a2 2 0 0 0-2-2H6Zm0 12h8c.37 0 .715-.1 1.012-.274l-4.662-4.58a.5.5 0 0 0-.7 0l-4.662 4.58A1.99 1.99 0 0 0 6 16Z"
|
||||
/>
|
||||
</svg>
|
||||
<input
|
||||
type="file"
|
||||
required={current === false}
|
||||
onChange={(e) => setImage(e.target.files[0])}
|
||||
className="hidden"
|
||||
name="file1"
|
||||
accept={".png"}
|
||||
/>
|
||||
</label>
|
||||
<input
|
||||
className="border-[#2c2c2c3e] border-2 w-full rounde -lg p-2 text-sm border-2 rounded-lg"
|
||||
placeholder="Project name"
|
||||
value={name}
|
||||
required={true}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<textarea
|
||||
className="border-[#2c2c2c3e] align-top w-full h-20 border-2 rounded-lg p-2 text-sm"
|
||||
placeholder="Project description"
|
||||
value={description}
|
||||
required={true}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<input
|
||||
className="border-[#2c2c2c3e] border-2 w-full rounde -lg p-2 text-sm border-2 rounded-lg"
|
||||
placeholder="Project URL"
|
||||
value={url}
|
||||
required={true}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<div className="flex justify-end">
|
||||
<button className="bg-black rounded-lg text-white p-2">
|
||||
{current ? "Edit" : "Add"} project
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{props.isLoggedIn && (
|
||||
<div className="flex justify-end mt-10 space-x-5">
|
||||
<button
|
||||
onClick={onOpenModal}
|
||||
className="flex space-x-3 items-center bg-[#202021] p-2 rounded-xl text-white hover:border-white hover:border-2"
|
||||
>
|
||||
<h1>Add project</h1>
|
||||
<svg
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M18 13h-5v5c0 .55-.45 1-1 1s-1-.45-1-1v-5H6c-.55 0-1-.45-1-1s.45-1 1-1h5V6c0-.55.45-1 1-1s1 .45 1 1v5h5c.55 0 1 .45 1 1s-.45 1-1 1z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{ecosystem.length ? (
|
||||
<div className="mt-10 space-y-10">
|
||||
{ecosystem.map((project, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex md:w-auto items-end justify-between rounded-lg bg-white p-6 dark:bg-[#202021]"
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<img
|
||||
className="rounded-full w-16 h-16 bg-white"
|
||||
src={`https://wmpoapaaynbjbqtjjtdy.supabase.co/storage/v1/object/public/public/public/${project.id}.png`}
|
||||
alt={"Project image"}
|
||||
/>
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className="text-lg text-[#707071] dark:text-white">
|
||||
{project.name}
|
||||
</p>
|
||||
|
||||
<p className="text-xs font-medium text-gray-900 dark:text-gray-400">
|
||||
{project.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{props.isLoggedIn && (
|
||||
<div className="flex space-x-2 items-center">
|
||||
<svg
|
||||
onClick={() => {
|
||||
setCurrent(project);
|
||||
setName(project.name);
|
||||
setDescription(project.description);
|
||||
setUrl(project.url);
|
||||
onOpenModal();
|
||||
}}
|
||||
className="w-7 h-7 rounded-xl p-1 hover:bg-yellow-200"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#000000"
|
||||
d="M5 19h1.4l8.625-8.625l-1.4-1.4L5 17.6V19ZM19.3 8.925l-4.25-4.2l1.4-1.4q.575-.575 1.413-.575t1.412.575l1.4 1.4q.575.575.6 1.388t-.55 1.387L19.3 8.925ZM17.85 10.4L7.25 21H3v-4.25l10.6-10.6l4.25 4.25Zm-3.525-.725l-.7-.7l1.4 1.4l-.7-.7Z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
className="w-7 h-7 rounded-xl p-1 hover:bg-red-200"
|
||||
viewBox="0 0 256 256"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
onClick={() => handleDelete(project)}
|
||||
>
|
||||
<path
|
||||
fill="#000000"
|
||||
d="M216 48h-40v-8a24 24 0 0 0-24-24h-48a24 24 0 0 0-24 24v8H40a8 8 0 0 0 0 16h8v144a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16V64h8a8 8 0 0 0 0-16ZM96 40a8 8 0 0 1 8-8h48a8 8 0 0 1 8 8v8H96Zm96 168H64V64h128Zm-80-104v64a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Zm48 0v64a8 8 0 0 1-16 0v-64a8 8 0 0 1 16 0Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div>No projects added yet!</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react'
|
||||
|
||||
export default function NetworkMetrics() {
|
||||
return (
|
||||
<div className=''>
|
||||
<div className='flex justify-between items-center'>
|
||||
<h1 className='text-2xl'>Network metrics</h1>
|
||||
<h1 className='text-[#707071] hidden md:block'>Powered by Waku</h1>
|
||||
</div>
|
||||
|
||||
<div className="grid mt-60 px-4 place-content-center">
|
||||
<h1 className='text-[#707071] hidden md:block'>Work in progress</h1>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
import React from "react";
|
||||
import OverviewCard from "@/components/molecules/OverviewCard";
|
||||
|
||||
export default function Overview(props) {
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-2xl">Overview</h1>
|
||||
<h1 className="text-[#707071] hidden md:block">Powered by Waku</h1>
|
||||
</div>
|
||||
|
||||
<div className="md:flex flex-wrap md:space-x-5 space-y-5 md:space-y-0 mt-10 justify-between">
|
||||
<OverviewCard
|
||||
title={"Discord members"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats.discord}
|
||||
previous={props.previous?.data?.stats?.discord}
|
||||
/>
|
||||
<OverviewCard
|
||||
title={"X (Twitter) followers"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats.twitter}
|
||||
previous={props.previous?.data?.stats?.twitter}
|
||||
/>
|
||||
|
||||
<OverviewCard
|
||||
title={"Github followers"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats.github}
|
||||
previous={props.previous?.data?.stats?.github}
|
||||
/>
|
||||
|
||||
<OverviewCard
|
||||
title={"Github Open Issues"}
|
||||
icon={
|
||||
<span className="hidden rounded-full bg-gray-100 p-2 text-gray-600 dark:bg-black dark:text-gray-300 sm:block">
|
||||
<svg
|
||||
className="w-6 h-6"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M19.27 5.33C17.94 4.71 16.5 4.26 15 4a.09.09 0 0 0-.07.03c-.18.33-.39.76-.53 1.09a16.09 16.09 0 0 0-4.8 0c-.14-.34-.35-.76-.54-1.09c-.01-.02-.04-.03-.07-.03c-1.5.26-2.93.71-4.27 1.33c-.01 0-.02.01-.03.02c-2.72 4.07-3.47 8.03-3.1 11.95c0 .02.01.04.03.05c1.8 1.32 3.53 2.12 5.24 2.65c.03.01.06 0 .07-.02c.4-.55.76-1.13 1.07-1.74c.02-.04 0-.08-.04-.09c-.57-.22-1.11-.48-1.64-.78c-.04-.02-.04-.08-.01-.11c.11-.08.22-.17.33-.25c.02-.02.05-.02.07-.01c3.44 1.57 7.15 1.57 10.55 0c.02-.01.05-.01.07.01c.11.09.22.17.33.26c.04.03.04.09-.01.11c-.52.31-1.07.56-1.64.78c-.04.01-.05.06-.04.09c.32.61.68 1.19 1.07 1.74c.03.01.06.02.09.01c1.72-.53 3.45-1.33 5.25-2.65c.02-.01.03-.03.03-.05c.44-4.53-.73-8.46-3.1-11.95c-.01-.01-.02-.02-.04-.02zM8.52 14.91c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.84 2.12-1.89 2.12zm6.97 0c-1.03 0-1.89-.95-1.89-2.12s.84-2.12 1.89-2.12c1.06 0 1.9.96 1.89 2.12c0 1.17-.83 2.12-1.89 2.12z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
}
|
||||
isLoading={props.isLoading}
|
||||
current={props.stats.github_repos?.total?.open_issues}
|
||||
previous={
|
||||
props.previous?.data?.stats?.github_repos?.total?.open_issues
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="md:flex justify-between md:space-x-10 mt-10 space-y-10 md:space-y-0">
|
||||
<div
|
||||
id="communitymetricsbox"
|
||||
className="md:w-1/2 border-[#202021] hover:border-white border-4 rounded-lg p-6"
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-xl">Community metrics</h1>
|
||||
<svg
|
||||
className="w-10 h-10"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M3 3a2 2 0 1 1 4 0a2 2 0 0 1-4 0Zm2-1a1 1 0 1 0 0 2a1 1 0 0 0 0-2Zm4.779 2.584a2 2 0 1 1 2.442-3.168A2 2 0 0 1 9.78 4.584ZM11 2a1 1 0 1 0 0 2a1 1 0 0 0 0-2ZM2.5 6h2.67c-.11.313-.17.65-.17 1H2.5a.5.5 0 0 0-.5.5c0 .817.325 1.423.838 1.835c.236.19.519.343.839.455a2.5 2.5 0 0 0-.532.868a3.733 3.733 0 0 1-.933-.543C1.46 9.51 1 8.616 1 7.5A1.5 1.5 0 0 1 2.5 6Zm3.768 0a2 2 0 1 0 3.466 2a2 2 0 0 0-3.466-2Zm1.508.025A1.003 1.003 0 0 1 9 7a1 1 0 1 1-1.224-.975Zm5.386 3.31c-.236.19-.519.343-.839.455a2.5 2.5 0 0 1 .531.868c.34-.139.655-.32.934-.543C14.54 9.51 15 8.616 15 7.5A1.5 1.5 0 0 0 13.5 6h-2.67c.11.313.17.65.17 1h2.5a.5.5 0 0 1 .5.5c0 .817-.325 1.423-.838 1.835ZM10.5 10a1.5 1.5 0 0 1 1.5 1.5c0 1.116-.459 2.01-1.212 2.615C10.047 14.71 9.053 15 8 15c-1.053 0-2.047-.29-2.788-.885C4.46 13.51 4 12.616 4 11.5A1.496 1.496 0 0 1 5.5 10h5Zm0 1h-5a.5.5 0 0 0-.5.5c0 .817.325 1.423.838 1.835C6.364 13.757 7.12 14 8 14c.88 0 1.636-.243 2.162-.665c.513-.412.838-1.018.838-1.835a.5.5 0 0 0-.5-.5Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-xs mt-4 text-[#737378]">
|
||||
Community metrics include data related to adoption, user base,
|
||||
social audience and outreach.
|
||||
</div>
|
||||
<div className="flex space-x-3 mt-5">
|
||||
<span className="inline-flex items-center justify-center rounded-full bg-[#737378] px-2.5 py-0.5 text-[#000000]">
|
||||
<p className="whitespace-nowrap text-xs">Beta</p>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="networkmetricsbox"
|
||||
className="md:w-1/2 border-[#202021] hover:border-white border-4 rounded-lg p-6"
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-xl">Network metrics</h1>
|
||||
<svg
|
||||
className="w-10 h-10"
|
||||
viewBox="0 0 2048 2048"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M1836 517q42 87 63 184t21 195q0 131-36 252t-102 227t-162 190t-212 141v86H768v128h256v128H384v-128h256v-128H0V896h128q0-124 32-238t90-214t140-181t181-140t214-91t239-32q130 0 252 36t227 102t190 162t141 212h2v5zm-147-5q-73-127-187-217t-254-134q48 78 77 169t47 182h317zm103 384q0-132-44-256h-356q16 128 16 255t0 257h340q44-124 44-256zm-512 0q0-65-4-128t-12-128H784q-8 64-12 127t-4 129h512zm-256-763q-29 0-55 21t-49 56t-41 78t-33 85t-25 79t-15 60h436q-5-23-15-60t-24-79t-33-85t-41-77t-49-56t-56-22zm-224 28q-140 43-254 133T359 512h317q17-90 46-181t78-170zM300 640q-44 124-44 256h384q0-65 4-128t12-128H300zM128 1664h1152v-640H128v640zm1280-103q88-51 159-122t123-159h-282v281z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-xs mt-4 text-[#737378]">
|
||||
Network metrics include data related to Waku node delivery and network
|
||||
</div>
|
||||
<div className="flex space-x-3 mt-5">
|
||||
<span className="inline-flex items-center justify-center rounded-full bg-[#737378] px-2.5 py-0.5 text-[#000000]">
|
||||
<p className="whitespace-nowrap text-xs">Work in progress</p>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="docs"
|
||||
className="mt-10 border-[#202021] hover:border-white border-4 rounded-lg p-6"
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-xl">Documentation</h1>
|
||||
<svg
|
||||
className="w-10 h-10"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#ffffff"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="M19 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2ZM7 7h10M7 12h10M7 17h6"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="propose-a-metric"
|
||||
className="mt-10 border-[#202021] hover:border-white border-4 rounded-lg p-6"
|
||||
>
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-xl">Propose a new metric</h1>
|
||||
<svg
|
||||
className="w-10 h-10"
|
||||
viewBox="0 0 26 26"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M12.906-.031a1 1 0 0 0-.125.031A1 1 0 0 0 12 1v1H3a3 3 0 0 0-3 3v13c0 1.656 1.344 3 3 3h9v.375l-5.438 2.719a1.006 1.006 0 0 0 .875 1.812L12 23.625V24a1 1 0 1 0 2 0v-.375l4.563 2.281a1.006 1.006 0 0 0 .875-1.812L14 21.375V21h9c1.656 0 3-1.344 3-3V5a3 3 0 0 0-3-3h-9V1a1 1 0 0 0-1.094-1.031zM2 5h22v13H2V5zm18.875 1a1 1 0 0 0-.594.281L17 9.563L14.719 7.28a1 1 0 0 0-1.594.219l-2.969 5.188l-1.219-3.063a1 1 0 0 0-1.656-.344l-3 3a1.016 1.016 0 1 0 1.439 1.44l1.906-1.906l1.438 3.562a1 1 0 0 0 1.812.125l3.344-5.844l2.062 2.063a1 1 0 0 0 1.438 0l4-4A1 1 0 0 0 20.875 6z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,637 @@
|
|||
"use client"; //
|
||||
|
||||
import React from "react";
|
||||
import { useState } from "react";
|
||||
import Benchmarks from "./Benchmarks";
|
||||
import CommunityMetrics from "./CommunityMetrics";
|
||||
import Ecosystem from "./Ecosystem";
|
||||
import NetworkMetrics from "./NetworkMetrics";
|
||||
import Overview from "./Overview";
|
||||
import Timeline from "./Timeline";
|
||||
import { useEffect } from "react";
|
||||
import Npm from "@/utils/npm";
|
||||
import Discord from "@/utils/discord";
|
||||
import Github from "@/utils/github";
|
||||
import Twitter from "@/utils/twitter";
|
||||
import Rust from "@/utils/rust_package";
|
||||
import Docker from "@/utils/docker";
|
||||
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function Router() {
|
||||
const [mobileMenu, setMobileMenu] = useState(false);
|
||||
const [screen, setScreen] = useState(0);
|
||||
|
||||
const [session, setSession] = useState(false);
|
||||
|
||||
const [stats, setStats] = useState({});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [overviewLoading, setOverviewLoading] = useState(true);
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
|
||||
const [saves, setSaves] = useState({});
|
||||
const supabase = createClientComponentClient();
|
||||
|
||||
supabase.auth.onAuthStateChange((event, session) => {
|
||||
if (event === "SIGNED_OUT") {
|
||||
setSession(false);
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (isLoading) {
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
if (!session) {
|
||||
setSession(false);
|
||||
} else {
|
||||
setSession(session);
|
||||
setIsLoggedIn(true);
|
||||
}
|
||||
|
||||
const discord = await Discord.getServerMembers("j5pGbn7MHZ");
|
||||
const github = await Github.getOrganizationFollowers("waku-org");
|
||||
|
||||
const repos = [
|
||||
"nwaku",
|
||||
"js-waku",
|
||||
"go-waku",
|
||||
"waku-react-native",
|
||||
"js-waku-examples",
|
||||
"waku-rust-bindings",
|
||||
];
|
||||
|
||||
const github_repos = await Github.getReposStats("waku-org", repos);
|
||||
// const twitter = await Twitter.getFollowers();
|
||||
const twitter = 2;
|
||||
|
||||
setOverviewLoading(false);
|
||||
setStats({
|
||||
twitter,
|
||||
discord,
|
||||
github,
|
||||
github_repos,
|
||||
});
|
||||
|
||||
await (async () => {
|
||||
const npm = await Npm.getDownloadsLastWeek("@waku/core");
|
||||
// console.log(Golang.getDownloads("waku-org/go-waku@v0.5.2/waku"));
|
||||
const rust = await Rust.getDownloads("waku-bindings");
|
||||
const docker = await Docker.getPulls();
|
||||
|
||||
const data = await supabase
|
||||
.from("saves")
|
||||
.select()
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
setSaves(data.data);
|
||||
|
||||
setStats({
|
||||
...stats,
|
||||
npm,
|
||||
discord,
|
||||
github,
|
||||
github_repos,
|
||||
rust,
|
||||
twitter,
|
||||
docker,
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
})();
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const handleSignIn = async () => {
|
||||
await supabase.auth.signInWithOAuth({
|
||||
provider: "google",
|
||||
options: {
|
||||
queryParams: {
|
||||
access_type: "offline",
|
||||
prompt: "consent",
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleSignOut = async () => {
|
||||
await supabase.auth.signOut();
|
||||
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="text-white flex justify-between">
|
||||
{mobileMenu === true ? (
|
||||
<div
|
||||
id="mobile-nav"
|
||||
className="flex h-screen flex-col justify-between bg-[#202021] w-full md:w-auto md:hidden"
|
||||
>
|
||||
<div className="px-4 py-6">
|
||||
<div className="flex justify-between">
|
||||
<img
|
||||
src="https://waku.org/theme/image/logo.svg"
|
||||
className="w-20"
|
||||
/>
|
||||
<button
|
||||
onClick={() => setMobileMenu(false)}
|
||||
className="md:hidden"
|
||||
>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59L7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12L5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul className="mt-6 space-y-1">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
setScreen(0);
|
||||
setMobileMenu(false);
|
||||
}}
|
||||
className={
|
||||
screen === 0
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Overview
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<details className="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary className="flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700">
|
||||
<span className="text-sm font-medium">Metrics</span>
|
||||
|
||||
<span className="shrink-0 transition duration-300 group-open:-rotate-180">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</summary>
|
||||
|
||||
<ul className="mt-2 space-y-1 px-4">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
setScreen(1);
|
||||
setMobileMenu(false);
|
||||
}}
|
||||
className={
|
||||
screen === 1
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Community
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
setScreen(2);
|
||||
setMobileMenu(false);
|
||||
}}
|
||||
className={
|
||||
screen === 2
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Network
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<details className="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary className="flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700">
|
||||
<span className="text-sm font-medium"> Growth </span>
|
||||
|
||||
<span className="shrink-0 transition duration-300 group-open:-rotate-180">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</summary>
|
||||
|
||||
<ul className="mt-2 space-y-1 px-4">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
setScreen(3);
|
||||
setMobileMenu(false);
|
||||
}}
|
||||
className={
|
||||
screen === 3
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Timeline
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
setScreen(4);
|
||||
setMobileMenu(false);
|
||||
}}
|
||||
className={
|
||||
screen === 4
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Ecosystem
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
setScreen(5);
|
||||
setMobileMenu(false);
|
||||
}}
|
||||
className={
|
||||
screen === 5
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Benchmarks
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="sticky inset-x-0 bottom-0 border-x-4 border-[#202021] mb-1">
|
||||
<div
|
||||
onClick={() => {
|
||||
session === false ? handleSignIn() : handleSignOut();
|
||||
}}
|
||||
className="flex space-x-3 items-center gap-2 bg-[#000000] p-4 hover:bg-gray-50 rounded-lg"
|
||||
>
|
||||
<div className="h-10 w-10 flex items-center justify-center bg-[#202021] rounded-full object-cover">
|
||||
{session && session?.user?.user_metadata?.avatar_url ? (
|
||||
<img src={session?.user?.user_metadata?.avatar_url} />
|
||||
) : (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M8 8a3 3 0 1 0 0-6a3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0a2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1s1-4 6-4s6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332c-.678.678-.83 1.418-.832 1.664h10Z"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-xs">
|
||||
<strong className="block font-medium">
|
||||
{session === false
|
||||
? "Login as core contributor"
|
||||
: "Sign Out"}
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="block md:hidden w-full">
|
||||
<div
|
||||
id="mobile-header"
|
||||
className="flex justify-between w-full px-4 py-6"
|
||||
>
|
||||
<img src="https://waku.org/theme/image/logo.svg" className="w-20" />
|
||||
<button onClick={() => setMobileMenu(true)} className="md:hidden">
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M4 18h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zm0-5h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1zM3 7c0 .55.45 1 1 1h16c.55 0 1-.45 1-1s-.45-1-1-1H4c-.55 0-1 .45-1 1z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className="p-5 w-full">
|
||||
{(screen === 0 && (
|
||||
<Overview
|
||||
stats={stats}
|
||||
isLoading={overviewLoading}
|
||||
previous={Object.values(saves)[Object.keys(saves).length - 1]}
|
||||
/>
|
||||
)) ||
|
||||
(screen === 1 && (
|
||||
<CommunityMetrics
|
||||
stats={stats}
|
||||
isLoading={isLoading}
|
||||
previous={
|
||||
Object.keys(saves).length
|
||||
? Object.values(saves)[Object.keys(saves).length - 1]
|
||||
: {}
|
||||
}
|
||||
/>
|
||||
)) ||
|
||||
(screen === 2 && <NetworkMetrics />) ||
|
||||
(screen === 3 && (
|
||||
<Timeline
|
||||
stats={stats}
|
||||
saves={saves}
|
||||
setSaves={setSaves}
|
||||
isLoading={isLoading}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
)) ||
|
||||
(screen === 4 && <Ecosystem isLoggedIn={isLoggedIn} />) ||
|
||||
(screen === 5 && <Benchmarks isLoggedIn={isLoggedIn} />)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="hidden md:flex w-full">
|
||||
<div
|
||||
id="desktop-nav"
|
||||
className="flex sticky top-0 h-screen flex-col justify-between bg-[#202021] w-full md:w-1/6 "
|
||||
>
|
||||
<div className="px-4 py-6">
|
||||
<div className="flex justify-between">
|
||||
<img
|
||||
src="https://waku.org/theme/image/logo.svg"
|
||||
className="w-20"
|
||||
/>
|
||||
<button
|
||||
onClick={() => setMobileMenu(false)}
|
||||
className="md:hidden"
|
||||
>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59L7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12L5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ul className="mt-6 space-y-1">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => setScreen(0)}
|
||||
className={
|
||||
screen === 0
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Overview
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<details className="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary className="flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700">
|
||||
<span className="text-sm font-medium">Metrics</span>
|
||||
|
||||
<span className="shrink-0 transition duration-300 group-open:-rotate-180">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</summary>
|
||||
|
||||
<ul className="mt-2 space-y-1 px-4">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => setScreen(1)}
|
||||
className={
|
||||
screen === 1
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Community
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
onClick={() => setScreen(2)}
|
||||
className={
|
||||
screen === 2
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Network
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<details className="group [&_summary::-webkit-details-marker]:hidden">
|
||||
<summary className="flex cursor-pointer items-center justify-between rounded-lg px-4 py-2 text-gray-500 hover:bg-gray-100 hover:text-gray-700">
|
||||
<span className="text-sm font-medium"> Growth </span>
|
||||
|
||||
<span className="shrink-0 transition duration-300 group-open:-rotate-180">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</summary>
|
||||
|
||||
<ul className="mt-2 space-y-1 px-4">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => setScreen(3)}
|
||||
className={
|
||||
screen === 3
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Timeline
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
onClick={() => setScreen(4)}
|
||||
className={
|
||||
screen === 4
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Ecosystem
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div
|
||||
onClick={() => setScreen(5)}
|
||||
className={
|
||||
screen === 5
|
||||
? "block rounded-lg bg-gray-100 px-4 py-2 text-sm font-medium text-gray-700"
|
||||
: "block rounded-lg px-4 py-2 text-sm font-medium text-gray-500 hover:bg-black hover:text-white"
|
||||
}
|
||||
>
|
||||
Benchmarks
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="sticky inset-x-0 bottom-0 border-x-4 border-[#202021] mb-1">
|
||||
<div
|
||||
onClick={() => {
|
||||
session === false ? handleSignIn() : handleSignOut();
|
||||
}}
|
||||
className="flex space-x-3 items-center gap-2 bg-[#000000] p-4 hover:bg-gray-50 rounded-lg"
|
||||
>
|
||||
<div className="h-10 w-10 flex items-center justify-center bg-[#202021] rounded-full object-cover">
|
||||
{session && session?.user?.user_metadata?.avatar_url ? (
|
||||
<img src={session?.user?.user_metadata?.avatar_url} />
|
||||
) : (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M8 8a3 3 0 1 0 0-6a3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0a2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1s1-4 6-4s6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332c-.678.678-.83 1.418-.832 1.664h10Z"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-xs">
|
||||
<strong className="block font-medium">
|
||||
{session === false
|
||||
? "Login as core contributor"
|
||||
: "Sign Out"}
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-10 w-full">
|
||||
{(screen === 0 && (
|
||||
<Overview
|
||||
stats={stats}
|
||||
isLoading={overviewLoading}
|
||||
previous={
|
||||
Object.keys(saves).length
|
||||
? Object.values(saves)[Object.keys(saves).length - 1]
|
||||
: {}
|
||||
}
|
||||
/>
|
||||
)) ||
|
||||
(screen === 1 && (
|
||||
<CommunityMetrics
|
||||
stats={stats}
|
||||
isLoading={isLoading}
|
||||
previous={
|
||||
Object.keys(saves).length
|
||||
? Object.values(saves)[Object.keys(saves).length - 1]
|
||||
: {}
|
||||
}
|
||||
/>
|
||||
)) ||
|
||||
(screen === 2 && <NetworkMetrics />) ||
|
||||
(screen === 3 && (
|
||||
<Timeline
|
||||
stats={stats}
|
||||
saves={saves}
|
||||
setSaves={setSaves}
|
||||
isLoading={isLoading}
|
||||
isLoggedIn={isLoggedIn}
|
||||
/>
|
||||
)) ||
|
||||
(screen === 4 && <Ecosystem isLoggedIn={isLoggedIn} />) ||
|
||||
(screen === 5 && <Benchmarks isLoggedIn={isLoggedIn} />)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
import React, { useState } from "react";
|
||||
import "react-responsive-modal/styles.css";
|
||||
import { Modal } from "react-responsive-modal";
|
||||
import axios from "axios";
|
||||
import CommunityMetrics from "@/components/CommunityMetrics";
|
||||
import Loader from "@/components/atoms/Loader";
|
||||
|
||||
export default function Timeline(props) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const onOpenModal = () => setOpen(true);
|
||||
const onCloseModal = () => setOpen(false);
|
||||
|
||||
const [current, setCurrent] = useState(null);
|
||||
const [previous, setPrevious] = useState(null);
|
||||
|
||||
const [name, setName] = useState("");
|
||||
|
||||
async function handleNewSave(e) {
|
||||
e.preventDefault();
|
||||
const res = await axios.post("/api/saves/set", {
|
||||
name,
|
||||
data: {
|
||||
stats: props.stats,
|
||||
},
|
||||
});
|
||||
|
||||
props.setSaves(res.data.data);
|
||||
setName(null);
|
||||
onCloseModal();
|
||||
}
|
||||
|
||||
const closeIcon = (
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="#000000"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
d="m7 7l10 10M7 17L17 7"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
const customStyles = {
|
||||
content: {
|
||||
borderRadius: "20px",
|
||||
backgroundColor: "black",
|
||||
bgColor: "black",
|
||||
},
|
||||
};
|
||||
|
||||
if (props.isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
|
||||
if (current !== null) {
|
||||
return (
|
||||
<CommunityMetrics
|
||||
stats={props.saves[current]?.data?.stats}
|
||||
isLoading={false}
|
||||
previous={previous ? props.saves[previous]?.data?.stats : {}}
|
||||
setCurrent={setCurrent}
|
||||
save={props.saves[current]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="flex justify-between items-center">
|
||||
<h1 className="text-2xl">Timeline</h1>
|
||||
<h1 className="text-[#707071] hidden md:block">Powered by Waku</h1>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
style={customStyles}
|
||||
className="bg-black"
|
||||
closeIcon={closeIcon}
|
||||
open={open}
|
||||
onClose={onCloseModal}
|
||||
center
|
||||
>
|
||||
<div className="rounded-xl w-40 h-40 ">
|
||||
<div className="m-4">
|
||||
<h1 className="text-xl">Snapshot</h1>
|
||||
<div className="mt-4">
|
||||
<form onSubmit={(e) => handleNewSave(e)} className="space-y-3">
|
||||
<input
|
||||
className="border-[#2c2c2c3e] border-2 w-full rounde -lg p-2 text-sm border-2 rounded-lg"
|
||||
placeholder="Name"
|
||||
value={name}
|
||||
required={true}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
/>
|
||||
<br />
|
||||
<div className="flex justify-end">
|
||||
<button className="bg-black rounded-lg text-white p-2">
|
||||
Create snapshot
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{props.isLoggedIn && (
|
||||
<div className="flex justify-end mt-10 space-x-5">
|
||||
<button
|
||||
onClick={onOpenModal}
|
||||
className="flex space-x-3 items-center bg-[#202021] p-2 rounded-xl text-white hover:border-white hover:border-2"
|
||||
>
|
||||
<h1>Create snapshot</h1>
|
||||
<svg
|
||||
className="h-5 w-5"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fill="#ffffff"
|
||||
d="M18 13h-5v5c0 .55-.45 1-1 1s-1-.45-1-1v-5H6c-.55 0-1-.45-1-1s.45-1 1-1h5V6c0-.55.45-1 1-1s1 .45 1 1v5h5c.55 0 1 .45 1 1s-.45 1-1 1z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{props.saves?.length ? (
|
||||
<div className="overflow-x-auto mt-10 rounded-lg">
|
||||
<table className="min-w-full divide-y-2 divide-black bg-white text-sm dark:divide-black dark:bg-[#202021]">
|
||||
<thead className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<tr>
|
||||
<td className="whitespace-nowrap px-4 py-2 font-medium text-gray-900 dark:text-white">
|
||||
Name
|
||||
</td>
|
||||
<td className="whitespace-nowrap font-medium px-4 py-2 text-gray-700 dark:text-gray-200">
|
||||
Date
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-4 py-2"></td>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
|
||||
{props.saves.map((save, index) => (
|
||||
<tr key={index}>
|
||||
<td className="whitespace-nowrap px-4 py-2 text-gray-400">
|
||||
{save.name}
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-4 py-2 text-gray-400">
|
||||
{new Date(save.created_at).toDateString()}
|
||||
</td>
|
||||
<td className="whitespace-nowrap px-4 py-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
setCurrent(index);
|
||||
setPrevious(
|
||||
index !== props.saves?.length - 1 ? index + 1 : null
|
||||
);
|
||||
}}
|
||||
className="inline-block rounded bg-black px-4 py-2 text-xs font-medium text-white hover:bg-indigo-700"
|
||||
>
|
||||
View snapshot
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
) : (
|
||||
<div>Snapshot data</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
"use client";
|
||||
|
||||
export default function Loader() {
|
||||
return <div>Loading...</div>;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import Percentage from "@/components/molecules/Percentage";
|
||||
|
||||
export default function CommunityMetricsCard(props) {
|
||||
return (
|
||||
<div className="flex md:w-auto items-end justify-between rounded-lg bg-white p-6 dark:bg-[#202021]">
|
||||
<div className="flex items-center gap-4">
|
||||
{props.icon}
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm text-[#707071] dark:text-gray-400">
|
||||
{props.title}
|
||||
</p>
|
||||
|
||||
<p className="text-2xl font-medium text-gray-900 dark:text-white">
|
||||
{props.isLoading ? "..." : props.current}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Percentage previous={props.previous} current={props.current} />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import React from "react";
|
||||
import Percentage from "@/components/molecules/Percentage";
|
||||
|
||||
export default function OverviewCard(props) {
|
||||
return (
|
||||
<div className="flex md:w-auto items-end justify-between rounded-lg bg-white p-6 dark:bg-[#202021]">
|
||||
<div className="flex items-center gap-4">
|
||||
{props.icon}
|
||||
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm text-[#707071] dark:text-gray-400">
|
||||
{props.title}
|
||||
</p>
|
||||
|
||||
<p className="text-2xl font-medium text-gray-900 dark:text-white">
|
||||
{props.isLoading ? "..." : props.current}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Percentage previous={props.previous} current={props.current} />
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
export default function Percentage(props) {
|
||||
const previous = props.previous ?? 0;
|
||||
const value = (
|
||||
((props.current - props.previous) / props.previous) *
|
||||
100
|
||||
).toFixed(0);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`inline-flex gap-2 rounded p-1 ${
|
||||
props.current >= previous
|
||||
? "bg-green-700 text-white"
|
||||
: "bg-red-700 text-white"
|
||||
}`}
|
||||
>
|
||||
{props.current >= previous ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-4 w-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M13 17h8m0 0V9m0 8l-8-8-4 4-6-6"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
<span className="text-xs font-medium">
|
||||
{" "}
|
||||
{`${value && !isNaN(value) ? value : 0}%`}{" "}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { createMiddlewareClient } from "@supabase/auth-helpers-nextjs";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function middleware(req) {
|
||||
const res = NextResponse.next();
|
||||
const supabase = createMiddlewareClient({ req, res });
|
||||
await supabase.auth.getSession();
|
||||
return res;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {}
|
||||
|
||||
module.exports = nextConfig
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "metrics",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/auth-helpers-nextjs": "^0.7.4",
|
||||
"@supabase/supabase-js": "^2.33.1",
|
||||
"autoprefixer": "10.4.15",
|
||||
"axios": "^1.5.0",
|
||||
"axios-oauth-1.0a": "^0.3.6",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"encoding": "^0.1.13",
|
||||
"eslint": "8.48.0",
|
||||
"eslint-config-next": "13.4.19",
|
||||
"next": "13.4.19",
|
||||
"postcss": "8.4.28",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-responsive-modal": "^6.4.2",
|
||||
"reactjs-popup": "^2.0.5",
|
||||
"tailwindcss": "3.3.3",
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "18.2.21"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>
|
After Width: | Height: | Size: 629 B |
|
@ -0,0 +1,18 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
backgroundImage: {
|
||||
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
||||
'gradient-conic':
|
||||
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
},
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
".next/types/**/*.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
import axios from "axios";
|
||||
|
||||
export async function login() {
|
||||
return (window.location.href = `https://github.com/login/oauth/authorize?client_id=${process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID}&scope=repo read:org read:project`);
|
||||
}
|
||||
|
||||
export async function isLoggedIn() {
|
||||
if (
|
||||
!localStorage.getItem("access_token") ||
|
||||
!localStorage.getItem("token_expiration") ||
|
||||
localStorage.getItem("access_token") === "undefined"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
localStorage.getItem("token_expiration") < Math.floor(Date.now() / 1000)
|
||||
) {
|
||||
if (
|
||||
!localStorage.getItem("refresh_token") ||
|
||||
localStorage.getItem("refresh_token_expiration") <
|
||||
Math.floor(Date.now() / 1000)
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
await refreshToken();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
localStorage.clear();
|
||||
|
||||
window.location.href = "/";
|
||||
}
|
||||
|
||||
export async function getToken(code) {
|
||||
const data = (await axios.get(`/api/verify?code=${code}`)).data;
|
||||
|
||||
if (!data.access_token) {
|
||||
await logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
localStorage.setItem("access_token", data.access_token);
|
||||
localStorage.setItem("refresh_token", data.refresh_token);
|
||||
localStorage.setItem(
|
||||
"token_expiration",
|
||||
Math.floor(Date.now() / 1000) + data.expires_in - 5
|
||||
);
|
||||
localStorage.setItem(
|
||||
"refresh_token_expiration",
|
||||
Math.floor(Date.now() / 1000) + data.refresh_token_expires_in - 5
|
||||
);
|
||||
}
|
||||
|
||||
export async function refreshToken() {
|
||||
const token = localStorage.getItem("refresh_token");
|
||||
|
||||
if (!token) {
|
||||
await logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
const data = (await axios.get(`/api/refresh?token=${token}`)).data;
|
||||
|
||||
if (!data.access_token) {
|
||||
await logout();
|
||||
return false;
|
||||
}
|
||||
|
||||
localStorage.setItem("access_token", data.access_token);
|
||||
localStorage.setItem("refresh_token", data.refresh_token);
|
||||
localStorage.setItem(
|
||||
"token_expiration",
|
||||
Math.floor(Date.now() / 1000) + data.expires_in - 5
|
||||
);
|
||||
localStorage.setItem(
|
||||
"refresh_token_expiration",
|
||||
Math.floor(Date.now() / 1000) + data.refresh_token_expires_in - 5
|
||||
);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
export default function initiateDb(): any {
|
||||
const supabaseUrl: string = process.env.SUPABASE_URL;
|
||||
const supabaseKey: string = process.env.SUPABASE_KEY;
|
||||
|
||||
return createClient(supabaseUrl, supabaseKey, {
|
||||
auth: { persistSession: false },
|
||||
});
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
export default function initiateDb() {
|
||||
return createClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
|
||||
{
|
||||
auth: { persistSession: false },
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import axios from "axios";
|
||||
|
||||
export default class Discord {
|
||||
static async getServerMembers(invite) {
|
||||
return (
|
||||
await axios.get(
|
||||
`https://discord.com/api/v9/invites/${invite}?with_counts=true`
|
||||
)
|
||||
).data.approximate_member_count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import axios from "axios";
|
||||
|
||||
export default class Docker {
|
||||
static async getPulls() {
|
||||
return (await axios.get(`/api/docker`)).data.pull_count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
import axios from "axios";
|
||||
import { isLoggedIn, logout } from "./auth";
|
||||
|
||||
export default class Github {
|
||||
static async getOrganizationFollowers(organization) {
|
||||
return (await axios.get(`https://api.github.com/orgs/${organization}`)).data
|
||||
.followers;
|
||||
}
|
||||
|
||||
static async getRepoStars(repo) {
|
||||
return (await axios.get(`https://api.github.com/repos/${repo}`)).data
|
||||
.stargazers_count;
|
||||
}
|
||||
|
||||
static async getRepoForks(repo) {
|
||||
return (await axios.get(`https://api.github.com/repos/${repo}`)).data
|
||||
.forks_count;
|
||||
}
|
||||
|
||||
static async getRepoStats(repo) {
|
||||
const data = (await axios.get(`https://api.github.com/repos/${repo}`)).data;
|
||||
|
||||
return { stars: data.stargazers_count, forks: data.forks_count };
|
||||
}
|
||||
|
||||
static async getReposStats(organization, repos) {
|
||||
let data = (
|
||||
await axios.get(`https://api.github.com/orgs/${organization}/repos`)
|
||||
).data;
|
||||
|
||||
let total_stars = 0;
|
||||
let total_forks = 0;
|
||||
let total_open_issues = 0;
|
||||
|
||||
data.forEach((repo) => {
|
||||
total_stars += repo.stargazers_count;
|
||||
total_forks += repo.forks_count;
|
||||
total_open_issues += repo.open_issues_count;
|
||||
});
|
||||
|
||||
data = data?.length
|
||||
? data.filter((repo) => repos.indexOf(repo.name) !== -1)
|
||||
: [];
|
||||
|
||||
let stats = {};
|
||||
|
||||
data.forEach((repo) => {
|
||||
stats[repo.name] = {
|
||||
stars: repo.stargazers_count,
|
||||
forks: repo.forks_count,
|
||||
open_issues: repo.open_issues_count,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...stats,
|
||||
total: {
|
||||
stars: total_stars,
|
||||
forks: total_forks,
|
||||
open_issues: total_open_issues,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static async getEvents() {
|
||||
if (!(await isLoggedIn())) {
|
||||
await logout();
|
||||
}
|
||||
|
||||
const organization = process.env.NEXT_PUBLIC_GITHUB_ORGANIZATION;
|
||||
const project_id = process.env.NEXT_PUBLIC_GITHUB_EVENTS_PROJECT;
|
||||
|
||||
const res = await axios.post(
|
||||
"https://api.github.com/graphql",
|
||||
{
|
||||
query: `query{organization(login:"${organization}"){name projectV2(number:${project_id}){number title items(first:100,orderBy:{direction:DESC,field:POSITION}){nodes{fieldValueByName(name:"Status"){... on ProjectV2ItemFieldSingleSelectValue{name}}content{... on Issue{title assignees(first:3){nodes{login url}}resourcePath}... on DraftIssue{title assignees(first:3){nodes{login url}}}... on PullRequest{title assignees(first:3){nodes{login url}}}}}}}}}`,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let events = { Upcoming: [], Completed: [] };
|
||||
|
||||
res.data.data.organization.projectV2.items.nodes.forEach((item) => {
|
||||
if (
|
||||
item.fieldValueByName?.name !== "Upcoming Events" &&
|
||||
item.fieldValueByName?.name !== "Completed Events"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
events[
|
||||
item.fieldValueByName.name == "Upcoming Events"
|
||||
? "Upcoming"
|
||||
: "Completed"
|
||||
].push({
|
||||
title: item.content.title,
|
||||
assignees: item.content.assignees.nodes,
|
||||
url: item.content.resourcePath
|
||||
? `https://github.com/${item.content.resourcePath}`
|
||||
: false,
|
||||
});
|
||||
});
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
static async getEcosystemDirectory() {
|
||||
if (!(await isLoggedIn())) {
|
||||
await logout();
|
||||
}
|
||||
|
||||
const organization = process.env.NEXT_PUBLIC_GITHUB_ORGANIZATION;
|
||||
const project_id =
|
||||
process.env.NEXT_PUBLIC_GITHUB_ECOSYSTEM_DIRECTORY_PROJECT;
|
||||
|
||||
const res = await axios.post(
|
||||
"https://api.github.com/graphql",
|
||||
{
|
||||
query: `query{organization(login:"${organization}"){name projectV2(number:${project_id}){number title items(first:100,orderBy:{direction:DESC,field:POSITION}){nodes{createdAt updatedAt fieldValueByName(name:"Status"){... on ProjectV2ItemFieldSingleSelectValue{name}}content{... on Issue{title assignees(first:3){nodes{login url}}resourcePath}... on DraftIssue{title assignees(first:3){nodes{login url}}}... on PullRequest{title assignees(first:3){nodes{login url}}}}}}}}}`,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("access_token")}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let projects = {
|
||||
"Active Users": [],
|
||||
"In Progress": [],
|
||||
Icebox: [],
|
||||
"No Status": [],
|
||||
Prioritized: [],
|
||||
Todo: [],
|
||||
Competitors: [],
|
||||
};
|
||||
|
||||
const allowed_values = [
|
||||
"Active Users",
|
||||
"In Progress",
|
||||
"Icebox",
|
||||
"Epics",
|
||||
null,
|
||||
"Prioritized",
|
||||
"Todo",
|
||||
"Competitors",
|
||||
];
|
||||
|
||||
const all_projects = res.data.data.organization.projectV2.items.nodes.sort(
|
||||
(a, b) => {
|
||||
let da = new Date(a.createdAt),
|
||||
db = new Date(b.createdAt);
|
||||
return da - db;
|
||||
}
|
||||
);
|
||||
|
||||
projects["latest_3"] = all_projects
|
||||
.slice(Math.max(all_projects.length - 3, 0))
|
||||
.reverse();
|
||||
|
||||
all_projects.forEach((item) => {
|
||||
if (
|
||||
allowed_values.indexOf(item.fieldValueByName?.name) === -1 &&
|
||||
item.fieldValueByName != null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
projects[
|
||||
item.fieldValueByName === null
|
||||
? "No Status"
|
||||
: item.fieldValueByName.name === "Epics"
|
||||
? "Icebox"
|
||||
: item.fieldValueByName.name
|
||||
].push({
|
||||
title: item.content.title,
|
||||
updatedAt: item.updatedAt,
|
||||
url: item.content.resourcePath
|
||||
? `https://github.com/${item.content.resourcePath}`
|
||||
: false,
|
||||
assignees: item.content.assignees.nodes,
|
||||
});
|
||||
});
|
||||
|
||||
return projects;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import axios from "axios";
|
||||
import * as cheerio from "cheerio";
|
||||
|
||||
export default class Golang {
|
||||
static async getDownloads(pack) {
|
||||
const data = (await axios.get(`https://pkg.go.dev/github.com/${pack}`))
|
||||
.data;
|
||||
|
||||
if (!data) {
|
||||
console.error(`Could not fetch download count for package ${pack}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const $ = cheerio.load(data);
|
||||
const downloadCountText = $(
|
||||
'.DetailsItem:contains("Go to Imports")'
|
||||
).text();
|
||||
|
||||
return Number(downloadCountText);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import axios from "axios";
|
||||
|
||||
export default class Npm {
|
||||
static async getDownloadsLastWeek(pack) {
|
||||
return (
|
||||
await axios.get(`https://api.npmjs.org/downloads/point/last-week/${pack}`)
|
||||
).data.downloads;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import axios from "axios";
|
||||
|
||||
export default class Rust {
|
||||
static async getDownloads(crate) {
|
||||
return (await axios.get(`https://crates.io/api/v1/crates/${crate}`)).data
|
||||
.crate.downloads;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import axios from "axios";
|
||||
|
||||
export default class Twitter {
|
||||
static async getFollowers() {
|
||||
return (await axios.get(`/api/twitter`)).data.followers_count;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue