mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-08 14:43:24 +00:00
Début du projet, création du comportement de base + structure du site / du projet
This commit is contained in:
7
.env
Normal file
7
.env
Normal file
@@ -0,0 +1,7 @@
|
||||
# Environment variables declared in this file are automatically made available to Prisma.
|
||||
# See the documentation for more detail: https://pris.ly/d/prisma-schema#using-environment-variables
|
||||
|
||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server and MongoDB (Preview).
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
|
||||
3
.eslintrc.json
Normal file
3
.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
100
.gitignore
vendored
100
.gitignore
vendored
@@ -1,76 +1,34 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
# 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*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
36
README.md
36
README.md
@@ -1,2 +1,34 @@
|
||||
# superpipo-v2
|
||||
V2 de Superpipo sous Next et Prisma
|
||||
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
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
## 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.
|
||||
|
||||
31
components/Categories/Categories.js
Normal file
31
components/Categories/Categories.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import styles from '../../styles/categories.module.scss';
|
||||
|
||||
export default function Categories({ categories, favorites, handleSelectCategory, categoryActive }) {
|
||||
return (<div className={styles['categories-wrapper']}>
|
||||
<div className={styles['block-wrapper']}>
|
||||
<h4>Favoris</h4>
|
||||
<ul className={styles['favorites']}>
|
||||
{favorites.map(({ name, category }, key) => {
|
||||
const catName = categories.find(c => c.id === category).name;
|
||||
return <li key={key} className={styles['item']}>
|
||||
{name} <span className={styles['category']}>- {catName}</span>
|
||||
</li>;
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<div className={styles['block-wrapper']}>
|
||||
<h4>Catégories</h4>
|
||||
<ul className={styles['categories']}>
|
||||
{categories.map(({ id, name }, key) => (
|
||||
<li
|
||||
key={key}
|
||||
className={id === categoryActive ? styles['active'] : null}
|
||||
onClick={() => handleSelectCategory(id)}
|
||||
>
|
||||
{name} {id === categoryActive ? '(active)' : ''}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
28
components/Links/Link.js
Normal file
28
components/Links/Link.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
|
||||
import styles from '../../styles/links.module.scss';
|
||||
|
||||
export default function Link({ category, setCategoryActive, refCategoryActive }) {
|
||||
const { ref, inView } = useInView({ threshold: .5 });
|
||||
const { id, name, links, ref: refCategory } = category;
|
||||
|
||||
useEffect(() => inView ? setCategoryActive(id) : null, [id, inView, setCategoryActive]);
|
||||
|
||||
const setRefs = useCallback((node) => {
|
||||
refCategory.current = node;
|
||||
refCategoryActive.current = node;
|
||||
ref(node);
|
||||
}, [ref, refCategoryActive, refCategory]);
|
||||
|
||||
return (
|
||||
<div className={styles['link-block']} ref={setRefs}>
|
||||
<h2>{name}</h2>
|
||||
<ul className={styles['links']}>
|
||||
{links.map(({ name }, key2) => (
|
||||
<li key={key2} className={styles['item']}>{name}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
16
components/Links/Links.js
Normal file
16
components/Links/Links.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import Link from './Link';
|
||||
|
||||
import styles from '../../styles/links.module.scss';
|
||||
|
||||
export default function Links({ categories, setCategoryActive, refCategoryActive }) {
|
||||
return (<div className={styles['links-wrapper']}>
|
||||
{categories.map((category, key) => (
|
||||
<Link
|
||||
key={key}
|
||||
category={category}
|
||||
setCategoryActive={setCategoryActive}
|
||||
refCategoryActive={refCategoryActive}
|
||||
/>
|
||||
))}
|
||||
</div>);
|
||||
}
|
||||
3
next.config.js
Normal file
3
next.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
8412
package-lock.json
generated
Normal file
8412
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
package.json
Normal file
21
package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "superpipo-v2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "12.0.7",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-intersection-observer": "^8.33.1",
|
||||
"sass": "^1.46.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "7",
|
||||
"eslint-config-next": "12.0.7"
|
||||
}
|
||||
}
|
||||
7
pages/_app.js
Normal file
7
pages/_app.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import '../styles/globals.scss';
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
76
pages/index.js
Normal file
76
pages/index.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import styles from '../styles/Home.module.scss';
|
||||
|
||||
import Categories from '../components/Categories/Categories';
|
||||
import Links from '../components/Links/Links';
|
||||
import { createRef, useRef, useState } from 'react';
|
||||
|
||||
export default function Home({ categories, favorites }) {
|
||||
const [categoryActive, setCategoryActive] = useState(categories?.[0]?.id);
|
||||
const refCategoryActive = useRef();
|
||||
|
||||
const handleSelectCategory = (id) => {
|
||||
if (!refCategoryActive?.current) return;
|
||||
|
||||
const { ref } = categories.find(c => c.id === id);
|
||||
ref?.current?.scrollIntoView({
|
||||
block: 'end',
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.App}>
|
||||
<Categories
|
||||
categories={categories}
|
||||
favorites={favorites}
|
||||
handleSelectCategory={handleSelectCategory}
|
||||
categoryActive={categoryActive}
|
||||
/>
|
||||
<Links
|
||||
categories={categories}
|
||||
setCategoryActive={setCategoryActive}
|
||||
refCategoryActive={refCategoryActive}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps(context) {
|
||||
const categories = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const links = [];
|
||||
for (let y = 0; y < randomIntFromInterval(5, 25); y++) {
|
||||
links.push({
|
||||
id: y,
|
||||
name: 'Lien #' + (y + 1),
|
||||
category: i
|
||||
});
|
||||
}
|
||||
|
||||
categories.push({
|
||||
id: i,
|
||||
name: 'Catégorie #' + (i + 1),
|
||||
links,
|
||||
ref: createRef()
|
||||
});
|
||||
}
|
||||
|
||||
const favorites = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const category = categories[Math.floor(Math.random() * categories.length)];
|
||||
const link = category.links[Math.floor(Math.random() * category.links.length)]
|
||||
favorites.push(link);
|
||||
}
|
||||
|
||||
console.log(favorites);
|
||||
return {
|
||||
props: {
|
||||
categories,
|
||||
favorites
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function randomIntFromInterval(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
17
prisma/schema.prisma
Normal file
17
prisma/schema.prisma
Normal file
@@ -0,0 +1,17 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model user {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
password String
|
||||
}
|
||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
7
styles/Home.module.scss
Normal file
7
styles/Home.module.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.App {
|
||||
height: 100%;
|
||||
width: 1280px;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
32
styles/categories.module.scss
Normal file
32
styles/categories.module.scss
Normal file
@@ -0,0 +1,32 @@
|
||||
.categories-wrapper {
|
||||
border: 1px solid red;
|
||||
|
||||
height: 100%;
|
||||
width: 300px;
|
||||
padding: 10px;
|
||||
margin-right: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
overflow-x: auto;
|
||||
|
||||
& .block-wrapper {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
|
||||
& h4 {
|
||||
text-transform: uppercase;
|
||||
font-size: .85em;
|
||||
color: #dadce0;
|
||||
}
|
||||
|
||||
& .favorites .item .category {
|
||||
color: #dadce0;
|
||||
}
|
||||
|
||||
& .categories .active {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
styles/globals.scss
Normal file
31
styles/globals.scss
Normal file
@@ -0,0 +1,31 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,600;1,300;1,600&display=swap');
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
outline: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
font-family: Poppins, sans-serif;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#__next {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
ul, li {
|
||||
list-style: none;
|
||||
}
|
||||
25
styles/links.module.scss
Normal file
25
styles/links.module.scss
Normal file
@@ -0,0 +1,25 @@
|
||||
.links-wrapper {
|
||||
border: 1px solid red;
|
||||
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
flex: 1;
|
||||
overflow-x: auto;
|
||||
scroll-snap-type: y mandatory;
|
||||
|
||||
& .link-block {
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
scroll-snap-align: center;
|
||||
|
||||
& .links {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user