initial import
This commit is contained in:
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "next/core-web-vitals"
|
||||||
|
}
|
||||||
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# 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
|
||||||
|
.env
|
||||||
|
|
||||||
|
# vercel
|
||||||
|
.vercel
|
||||||
|
|
||||||
|
# typescript
|
||||||
|
*.tsbuildinfo
|
||||||
|
next-env.d.ts
|
||||||
|
|
||||||
|
postgres
|
||||||
20
README.md
Normal file
20
README.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
## Next.js App Router Course - Starter
|
||||||
|
|
||||||
|
This is the starter template for the Next.js App Router Course. It contains the starting code for the dashboard application.
|
||||||
|
|
||||||
|
For more information, see the [course curriculum](https://nextjs.org/learn) on the Next.js Website.
|
||||||
|
|
||||||
|
## ToDo
|
||||||
|
Zadnje sam stao na koraku 12 (nisam ga dovršio): https://nextjs.org/learn/dashboard-app/mutating-data
|
||||||
|
|
||||||
|
# Authentication
|
||||||
|
Authentication consists of the following parts:
|
||||||
|
* `next-auth` boilerplate
|
||||||
|
* `middleware.ts` = hooks-up `next-auth` into the page processing pipeline
|
||||||
|
* `auth.config.ts` = defines how user session is to be checked and redirects anonymous user to login page
|
||||||
|
* `auth.ts` = verifies user credentials during the log-in action (i.e. against a database)
|
||||||
|
* exports `auth`, `signIn`, `signOut` actions
|
||||||
|
* UI boilerplate
|
||||||
|
* `sidenav.tsx` = implements logout action - calls `signOut` from `auth.ts`
|
||||||
|
* `login-form.tsx` = implements login form
|
||||||
|
* `actions.ts` = handles login-form validation and submition - calls `signIn` from `auth.ts`
|
||||||
14
app/layout.tsx
Normal file
14
app/layout.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import '@/app/ui/global.css';
|
||||||
|
import { inter } from '@/app/ui/fonts';
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body className={`${inter.className} antialiased`}>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
2
app/lib/actions.ts
Normal file
2
app/lib/actions.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
'use server';
|
||||||
|
|
||||||
25
app/lib/sql-shim.ts
Normal file
25
app/lib/sql-shim.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { Client, QueryResult, QueryResultRow } from 'pg';
|
||||||
|
|
||||||
|
const client = new Client({
|
||||||
|
// connectionString: process.env.DATABASE_URL,
|
||||||
|
host: process.env.POSTGRES_HOST,
|
||||||
|
user: process.env.POSTGRES_USER,
|
||||||
|
password: process.env.POSTGRES_PASSWORD,
|
||||||
|
database: process.env.POSTGRES_DB
|
||||||
|
});
|
||||||
|
|
||||||
|
client.connect();
|
||||||
|
|
||||||
|
/** an adapter function which simulates @vercel/postgres `sql` function */
|
||||||
|
export function sql<T extends QueryResultRow>(strings: TemplateStringsArray, ...values: any[]): Promise<QueryResult<T>> {
|
||||||
|
// string values need to be wrapped in single quotes
|
||||||
|
const fixedValues = values.map((value) => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return `'${value}'`;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const query = String.raw(strings, ...fixedValues);
|
||||||
|
return client.query<T>(query);
|
||||||
|
}
|
||||||
51
app/page.tsx
Normal file
51
app/page.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import Link from 'next/link';
|
||||||
|
import styles from '@/app/ui/home.module.css';
|
||||||
|
import { lusitana } from './ui/fonts';
|
||||||
|
import Image from 'next/image';
|
||||||
|
|
||||||
|
import {
|
||||||
|
Cog8ToothIcon
|
||||||
|
} from '@heroicons/react/24/outline';
|
||||||
|
|
||||||
|
export default function Page() {
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col p-6 bg-base-300">
|
||||||
|
|
||||||
|
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
|
||||||
|
<div className="card-body">
|
||||||
|
<h2 className="card-title">2023-05 Budakova <Cog8ToothIcon className="h-[1em] w-[1em] absolute right-4 cursor-pointer" /></h2>
|
||||||
|
<div className="card-actions">
|
||||||
|
<div className="badge badge-lg badge-success cursor-pointer">GDKG</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">HEP Elektra</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">Iskon</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">Plinara</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
|
||||||
|
<div className="card-body">
|
||||||
|
<h2 className="card-title">2023-05 Kopernikova <Cog8ToothIcon className="h-[1em] w-[1em] absolute right-4 cursor-pointer" /></h2>
|
||||||
|
<div className="card-actions">
|
||||||
|
<div className="badge badge-lg badge-success cursor-pointer">GDKG</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">HEP Elektra</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">Iskon</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">Plinara</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
|
||||||
|
<div className="card-body">
|
||||||
|
<h2 className="card-title">2023-05 Šišićeva <Cog8ToothIcon className="h-[1em] w-[1em] absolute right-4 cursor-pointer" /></h2>
|
||||||
|
<div className="card-actions">
|
||||||
|
<div className="badge badge-lg badge-success cursor-pointer">GDKG</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">HEP Elektra</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">Iskon</div>
|
||||||
|
<div className="badge badge-lg badge-neutral cursor-pointer">Plinara</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
19
app/ui/button.tsx
Normal file
19
app/ui/button.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Button({ children, className, ...rest }: ButtonProps) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
{...rest}
|
||||||
|
className={clsx(
|
||||||
|
'flex h-10 items-center rounded-lg bg-blue-500 px-4 text-sm font-medium text-white transition-colors hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:bg-blue-600 aria-disabled:cursor-not-allowed aria-disabled:opacity-50',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
4
app/ui/fonts.ts
Normal file
4
app/ui/fonts.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { Inter, Lusitana } from 'next/font/google';
|
||||||
|
|
||||||
|
export const inter = Inter({ subsets: ['latin'] });
|
||||||
|
export const lusitana = Lusitana({ weight: ["400", "700"], subsets: ['latin'] });
|
||||||
18
app/ui/global.css
Normal file
18
app/ui/global.css
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
input[type='number'] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='number']::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type='number']::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
7
app/ui/home.module.css
Normal file
7
app/ui/home.module.css
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
.shape {
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
border-bottom: 30px solid indigo;
|
||||||
|
border-left: 20px solid transparent;
|
||||||
|
border-right: 20px solid transparent;
|
||||||
|
}
|
||||||
33
docker-compose.yml
Normal file
33
docker-compose.yml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# this compose file runs Postgres db and exposes it's port to the host machine
|
||||||
|
version: "3.7"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres:
|
||||||
|
pgadmin:
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16.1-alpine
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_DB: dashboard
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
volumes:
|
||||||
|
# store postgres data in a local `postgres` directory
|
||||||
|
- postgres:/var/lib/postgresql/data
|
||||||
|
pgadmin:
|
||||||
|
image: dpage/pgadmin4:8.1
|
||||||
|
environment:
|
||||||
|
PGADMIN_DEFAULT_EMAIL: admin@example.com
|
||||||
|
PGADMIN_DEFAULT_PASSWORD: SuperSecret
|
||||||
|
PGADMIN_LISTEN_PORT: 80
|
||||||
|
ports:
|
||||||
|
- 8080:80
|
||||||
|
volumes:
|
||||||
|
- pgadmin:/var/lib/pgadmin
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
4
next.config.js
Normal file
4
next.config.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {};
|
||||||
|
|
||||||
|
module.exports = nextConfig;
|
||||||
7552
package-lock.json
generated
Normal file
7552
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
46
package.json
Normal file
46
package.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"build": "next build",
|
||||||
|
"dev": "next dev",
|
||||||
|
"prettier": "prettier --write --ignore-unknown .",
|
||||||
|
"prettier:check": "prettier --check --ignore-unknown .",
|
||||||
|
"start": "next start",
|
||||||
|
"seed": "node -r dotenv/config ./scripts/seed.js"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@heroicons/react": "^2.0.18",
|
||||||
|
"@tailwindcss/forms": "^0.5.7",
|
||||||
|
"@types/node": "20.5.7",
|
||||||
|
"autoprefixer": "10.4.15",
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
|
"clsx": "^2.0.0",
|
||||||
|
"daisyui": "^4.4.24",
|
||||||
|
"next": "^14.0.2",
|
||||||
|
"next-auth": "^5.0.0-beta.4",
|
||||||
|
"pg": "^8.11.3",
|
||||||
|
"postcss": "8.4.31",
|
||||||
|
"react": "18.2.0",
|
||||||
|
"react-dom": "18.2.0",
|
||||||
|
"tailwindcss": "3.3.3",
|
||||||
|
"typescript": "5.2.2",
|
||||||
|
"use-debounce": "^10.0.0",
|
||||||
|
"zod": "^3.22.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bcrypt": "^5.0.1",
|
||||||
|
"@types/pg": "^8.10.9",
|
||||||
|
"@types/react": "18.2.21",
|
||||||
|
"@types/react-dom": "18.2.14",
|
||||||
|
"@vercel/style-guide": "^5.0.1",
|
||||||
|
"dotenv": "^16.3.1",
|
||||||
|
"eslint": "^8.52.0",
|
||||||
|
"eslint-config-next": "^14.0.0",
|
||||||
|
"eslint-config-prettier": "9.0.0",
|
||||||
|
"prettier": "^3.0.3",
|
||||||
|
"prettier-plugin-tailwindcss": "0.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.17.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
6
prettier.config.js
Normal file
6
prettier.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const styleguide = require('@vercel/style-guide/prettier');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
...styleguide,
|
||||||
|
plugins: [...styleguide.plugins, 'prettier-plugin-tailwindcss'],
|
||||||
|
};
|
||||||
35
tailwind.config.ts
Normal file
35
tailwind.config.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import type { Config } from 'tailwindcss';
|
||||||
|
|
||||||
|
const config: Config = {
|
||||||
|
content: [
|
||||||
|
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
||||||
|
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
||||||
|
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
gridTemplateColumns: {
|
||||||
|
'13': 'repeat(13, minmax(0, 1fr))',
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
blue: {
|
||||||
|
400: '#2589FE',
|
||||||
|
500: '#0070F3',
|
||||||
|
600: '#2F6FEB',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
shimmer: {
|
||||||
|
'100%': {
|
||||||
|
transform: 'translateX(100%)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/forms'),
|
||||||
|
require("daisyui")
|
||||||
|
],
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
34
tsconfig.json
Normal file
34
tsconfig.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
"app/lib/placeholder-data.js",
|
||||||
|
"scripts/seed.js"
|
||||||
|
],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user