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