Skip to content

Commit 258e70c

Browse files
committed
chore: create nextjs app
1 parent b4bf970 commit 258e70c

17 files changed

+591
-35
lines changed

.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

.github/workflows/main.yml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: build and deploy
2+
on: push
3+
4+
permissions:
5+
contents: read
6+
pages: write
7+
id-token: write
8+
9+
concurrency:
10+
group: "pages"
11+
cancel-in-progress: false
12+
13+
jobs:
14+
build:
15+
name: build
16+
runs-on: ubuntu-latest
17+
env:
18+
NEXT_PUBLIC_BASE_PATH: /norwegian-public-organizations
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
- name: setup bun
23+
uses: oven-sh/setup-bun@v1
24+
- name: Install packages
25+
run: bun install
26+
- name: Build
27+
run: bun run build
28+
- name: Upload artifact
29+
uses: actions/upload-pages-artifact@v3
30+
with:
31+
path: ./out
32+
deploy:
33+
environment:
34+
name: github-pages
35+
url: ${{ steps.deployment.outputs.page_url }}
36+
runs-on: ubuntu-latest
37+
needs: build
38+
steps:
39+
- name: Deploy to GitHub Pages
40+
id: deployment
41+
uses: actions/deploy-pages@v4

.gitignore

+41-35
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,42 @@
1-
.gradle
2-
build/
3-
!gradle/wrapper/gradle-wrapper.jar
4-
!**/src/main/**/build/
5-
!**/src/test/**/build/
6-
7-
### STS ###
8-
.apt_generated
9-
.classpath
10-
.factorypath
11-
.project
12-
.settings
13-
.springBeans
14-
.sts4-cache
15-
bin/
16-
!**/src/main/**/bin/
17-
!**/src/test/**/bin/
18-
19-
### IntelliJ IDEA ###
20-
.idea
21-
*.iws
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env*.local
29+
30+
# vercel
31+
.vercel
32+
33+
# typescript
34+
*.tsbuildinfo
35+
next-env.d.ts
36+
37+
# IntelliJ based IDEs
2238
*.iml
23-
*.ipr
24-
out/
25-
!**/src/main/**/out/
26-
!**/src/test/**/out/
27-
28-
### NetBeans ###
29-
/nbproject/private/
30-
/nbbuild/
31-
/dist/
32-
/nbdist/
33-
/.nb-gradle/
34-
35-
### VS Code ###
36-
.vscode/
39+
.idea
40+
41+
#build folder
42+
.out

bun.lockb

175 KB
Binary file not shown.

next.config.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
reactStrictMode: true,
4+
basePath: process.env.NEXT_PUBLIC_BASE_PATH,
5+
images: {
6+
loader: 'akamai',
7+
path: '/'
8+
},
9+
output: 'export'
10+
}
11+
12+
module.exports = nextConfig

package.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "norwegian-public-organizations",
3+
"version": "1.0.0",
4+
"homepage": "https://mikaojk.github.io/norwegian-public-organizations",
5+
"private": true,
6+
"scripts": {
7+
"dev": "next dev",
8+
"build": "next build",
9+
"start": "next start",
10+
"lint": "next lint"
11+
},
12+
"dependencies": {
13+
"@types/node": "22.9.0",
14+
"@types/react": "18.3.12",
15+
"@types/react-dom": "18.3.1",
16+
"@octokit/core": "^6.1.2",
17+
"@octokit/rest": "^21.0.2",
18+
"@octokit/plugin-retry": "^7.1.2",
19+
"autoprefixer": "10.4.20",
20+
"eslint": "9.14.0",
21+
"eslint-config-next": "15.0.3",
22+
"next": "15.0.3",
23+
"postcss": "8.4.49",
24+
"react": "18.3.1",
25+
"react-dom": "18.3.1",
26+
"tailwindcss": "3.4.14",
27+
"typescript": "5.6.3"
28+
},
29+
"packageManager": "[email protected]+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
30+
}

postcss.config.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}

public/next.svg

+1
Loading

public/vercel.svg

+1
Loading

src/app/favicon.ico

25.3 KB
Binary file not shown.

src/app/globals.css

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
:root {
6+
--foreground-rgb: 0, 0, 0;
7+
--background-start-rgb: 214, 219, 220;
8+
--background-end-rgb: 255, 255, 255;
9+
}
10+
11+
@media (prefers-color-scheme: dark) {
12+
:root {
13+
--foreground-rgb: 255, 255, 255;
14+
--background-start-rgb: 0, 0, 0;
15+
--background-end-rgb: 0, 0, 0;
16+
}
17+
}
18+
19+
body {
20+
color: rgb(var(--foreground-rgb));
21+
background: linear-gradient(
22+
to bottom,
23+
transparent,
24+
rgb(var(--background-end-rgb))
25+
)
26+
rgb(var(--background-start-rgb));
27+
}

src/app/layout.tsx

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import './globals.css'
2+
import type { Metadata } from 'next'
3+
import { Inter } from 'next/font/google'
4+
5+
const inter = Inter({ subsets: ['latin'] })
6+
7+
export const metadata: Metadata = {
8+
title: 'norwegian public organizations on GitHub',
9+
description: 'List of norwegian public organizations on GitHub',
10+
}
11+
12+
export default function RootLayout({
13+
children,
14+
}: {
15+
children: React.ReactNode
16+
}) {
17+
return (
18+
<html lang="en">
19+
<body className={inter.className}>{children}</body>
20+
</html>
21+
)
22+
}

src/app/page.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {OrganizationsOnGithub} from "@/components/OrganizationsOnGithub";
2+
import React from "react";
3+
4+
export default function Home() {
5+
return (
6+
<main>
7+
<div className="flex min-h-screen flex-col items-center justify-between">
8+
<div className="z- items-center justify-between font-mono text-sm flex">
9+
<OrganizationsOnGithub/>
10+
</div>
11+
</div>
12+
</main>
13+
)
14+
}
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
'use client';
2+
3+
import React, {useEffect, useState} from 'react';
4+
import organizations from "./data/organizations.json";
5+
import {Octokit} from "@octokit/core";
6+
import {paginateRest} from "@octokit/plugin-paginate-rest";
7+
import {retry} from "@octokit/plugin-retry";
8+
9+
export interface OrganizationsJson {
10+
id: number;
11+
name: string;
12+
url: string;
13+
owner: string;
14+
}
15+
16+
type OrganizationsWithRepos = {
17+
id: number;
18+
name: string;
19+
url: string;
20+
owner: string;
21+
repos: number
22+
}
23+
24+
export const OrganizationsOnGithub = () => {
25+
const organizationsOnGithub: OrganizationsJson[] = organizations
26+
const [organizationsWithRepos, setOrganizationsWithRepos] = useState<OrganizationsWithRepos[]>([]);
27+
28+
useEffect(() => {
29+
organizationsOnGithub.forEach(organization => (
30+
getNumberOfPublicRepos(organization.owner)
31+
.then((numberOfRepos) => {
32+
setOrganizationsWithRepos(organizationsWithRepos => {
33+
return [{
34+
id: organization.id,
35+
name: organization.name,
36+
url: organization.url,
37+
owner: organization.owner,
38+
repos: numberOfRepos
39+
}, ...organizationsWithRepos]
40+
});
41+
42+
})));
43+
}, []);
44+
45+
const organizationsWithReposByRepoNumber: OrganizationsWithRepos[] = organizationsWithRepos.sort((a, b) => b.repos - a.repos)
46+
47+
48+
return (
49+
<div className="flex min-h-screen flex-col p-16 md:items-center md:p-24">
50+
<h1 className="text-5xl font-extrabold mb-4">Norwegian public organizations on GitHub</h1>
51+
<div className="md:flex md:min-h-screen md:flex-col">
52+
<div className="mt-4 md:mt-10">
53+
{organizationsWithReposByRepoNumber &&
54+
<table className="w-full text-sm text-left rtl:text-right">
55+
<thead className="text-m uppercase">
56+
<tr>
57+
<th scope="col" className="px-6 py-3">Name</th>
58+
<th scope="col" className="px-6 py-3">Url</th>
59+
<th scope="col" className="px-6 py-3">Number of repos</th>
60+
</tr>
61+
</thead>
62+
<tbody>
63+
{organizationsWithReposByRepoNumber.map(organization =>
64+
<tr className="border-b dark:border-gray-700" key={organization.id}>
65+
<td className="px-6 py-4">
66+
{organization.name}
67+
</td>
68+
<td className="px-6 py-4">
69+
<a className="text-blue-600 dark:text-blue-500 hover:underline"
70+
href={organization.url}>{organization.url} </a>
71+
</td>
72+
<td className="px-6 py-4">
73+
{organization.repos}
74+
</td>
75+
</tr>
76+
)}
77+
</tbody>
78+
</table>
79+
}
80+
</div>
81+
</div>
82+
</div>
83+
);
84+
}
85+
86+
87+
async function getNumberOfPublicRepos(owner: string): Promise<number> {
88+
const octokitplugin = Octokit.plugin(paginateRest, retry).defaults({
89+
userAgent: "norwegian-public-organizations",
90+
/// auth: 'mysupersecrettoken'
91+
});
92+
93+
const myOctokit = new octokitplugin()
94+
95+
try {
96+
const repos = await myOctokit.request(`GET /orgs/${owner}`, {
97+
headers: {
98+
'X-GitHub-Api-Version': '2022-11-28'
99+
}
100+
})
101+
102+
return repos.data.public_repos
103+
} catch (e) {
104+
console.log(e)
105+
return 0
106+
}
107+
}
108+

0 commit comments

Comments
 (0)