commit
eb612e0bf2
@ -1,7 +1,10 @@
|
|||||||
export default {
|
export default {
|
||||||
|
responses: {
|
||||||
|
privateAttributes: ['_v', 'id', 'created_at'],
|
||||||
|
},
|
||||||
rest: {
|
rest: {
|
||||||
defaultLimit: 25,
|
defaultLimit: 100,
|
||||||
maxLimit: 100,
|
maxLimit: 250,
|
||||||
withCount: true,
|
withCount: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,11 +1,22 @@
|
|||||||
import path from 'path';
|
export default ({env}) => ({
|
||||||
|
|
||||||
export default ({ env }) => ({
|
|
||||||
connection: {
|
connection: {
|
||||||
client: 'sqlite',
|
client: 'postgres',
|
||||||
connection: {
|
connection: {
|
||||||
filename: path.join(__dirname, '..', '..', env('DATABASE_FILENAME', '.tmp/data.db')),
|
host: env('DATABASE_HOST', 'localhost'),
|
||||||
|
port: env.int('DATABASE_PORT', 5432),
|
||||||
|
database: env('DATABASE_NAME', 'bank'),
|
||||||
|
user: env('DATABASE_USERNAME', 'postgres'),
|
||||||
|
password: env('DATABASE_PASSWORD', '0000'),
|
||||||
|
schema: env('DATABASE_SCHEMA', 'public'), // Not required
|
||||||
|
ssl: false,
|
||||||
},
|
},
|
||||||
useNullAsDefault: true,
|
debug: false,
|
||||||
},
|
},
|
||||||
|
// connection: {
|
||||||
|
// client: 'sqlite',
|
||||||
|
// connection: {
|
||||||
|
// filename: path.join(__dirname, '..', '..', env('DATABASE_FILENAME', '.tmp/data.db')),
|
||||||
|
// },
|
||||||
|
// useNullAsDefault: true,
|
||||||
|
// },
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
|||||||
|
services:
|
||||||
|
gs_postgres:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
container_name: gs_postgres
|
||||||
|
shm_size: '4gb'
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${DATABASE_USERNAME}
|
||||||
|
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
|
||||||
|
POSTGRES_DB: ${DATABASE_NAME}
|
||||||
|
TZ: Europe/Paris
|
||||||
|
healthcheck:
|
||||||
|
test: 'PGPASSWORD="${DATABASE_PASSWORD}" psql --host ${DATABASE_HOST} --username ${DATABASE_USERNAME} --dbname ${DATABASE_NAME} -c "select 1" ; [ "0" -eq "$$?" ]; echo $$?'
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
volumes:
|
||||||
|
- gs_postgres-master:/var/lib/postgresql/data:z
|
||||||
|
- ./.db/init:/docker-entrypoint-initdb.d
|
||||||
|
ports:
|
||||||
|
- ${DATABASE_PORT}:5432 # DB
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"kind": "collectionType",
|
||||||
|
"collectionName": "pages",
|
||||||
|
"info": {
|
||||||
|
"singularName": "page",
|
||||||
|
"pluralName": "pages",
|
||||||
|
"displayName": "Pages",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"draftAndPublish": true
|
||||||
|
},
|
||||||
|
"pluginOptions": {},
|
||||||
|
"attributes": {
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"slug": {
|
||||||
|
"type": "uid",
|
||||||
|
"targetField": "label"
|
||||||
|
},
|
||||||
|
"seo": {
|
||||||
|
"type": "component",
|
||||||
|
"repeatable": false,
|
||||||
|
"component": "shared.seo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* page controller
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { factories } from '@strapi/strapi'
|
||||||
|
|
||||||
|
export default factories.createCoreController('api::page.page');
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* page router
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { factories } from '@strapi/strapi';
|
||||||
|
|
||||||
|
export default factories.createCoreRouter('api::page.page');
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* page service
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { factories } from '@strapi/strapi';
|
||||||
|
|
||||||
|
export default factories.createCoreService('api::page.page');
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"collectionName": "components_meta_metas",
|
||||||
|
"info": {
|
||||||
|
"displayName": "meta",
|
||||||
|
"icon": "network-wired"
|
||||||
|
},
|
||||||
|
"options": {},
|
||||||
|
"attributes": {
|
||||||
|
"property": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"collectionName": "components_shared_seos",
|
||||||
|
"info": {
|
||||||
|
"displayName": "Seo",
|
||||||
|
"icon": "book",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"options": {},
|
||||||
|
"attributes": {
|
||||||
|
"metaTitle": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"metaDescription": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"SharedImage": {
|
||||||
|
"displayName": "SharedImage",
|
||||||
|
"type": "component",
|
||||||
|
"repeatable": false,
|
||||||
|
"component": "shared.shared-image"
|
||||||
|
},
|
||||||
|
"Meta": {
|
||||||
|
"displayName": "meta",
|
||||||
|
"type": "component",
|
||||||
|
"repeatable": true,
|
||||||
|
"component": "meta.meta"
|
||||||
|
},
|
||||||
|
"preventIndexing": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"structuredData": {
|
||||||
|
"type": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"collectionName": "components_shared_shared_images",
|
||||||
|
"info": {
|
||||||
|
"displayName": "SharedImage",
|
||||||
|
"icon": "file-image",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"options": {},
|
||||||
|
"attributes": {
|
||||||
|
"alt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"allowedTypes": [
|
||||||
|
"images",
|
||||||
|
"files",
|
||||||
|
"videos",
|
||||||
|
"audios"
|
||||||
|
],
|
||||||
|
"type": "media",
|
||||||
|
"multiple": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
STRAPI_URL=http://127.0.0.1:1337/api
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
* Replace this with your own classes
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* .container {
|
||||||
|
* }
|
||||||
|
*/
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import Carousel from './carousel';
|
||||||
|
|
||||||
|
describe('Carousel', () => {
|
||||||
|
it('should render successfully', () => {
|
||||||
|
const { baseElement } = render(<Carousel />);
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import styles from './carousel.module.scss';
|
||||||
|
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
export interface CarouselProps {}
|
||||||
|
|
||||||
|
export function Carousel(props: CarouselProps) {
|
||||||
|
return (
|
||||||
|
<div className={styles['container']}>
|
||||||
|
<h1>Welcome to Carousel!</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Carousel;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
* Replace this with your own classes
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* .container {
|
||||||
|
* }
|
||||||
|
*/
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import Footer from './footer';
|
||||||
|
|
||||||
|
describe('Footer', () => {
|
||||||
|
it('should render successfully', () => {
|
||||||
|
const { baseElement } = render(<Footer />);
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
import delve from "dlv";
|
||||||
|
|
||||||
|
export function Footer({items = []}) {
|
||||||
|
|
||||||
|
const generateItem = (item, index) => {
|
||||||
|
const value = delve(item, 'attributes', {});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li key={value.title + index}>
|
||||||
|
<a href={value.url} target={value.target} className="mr-4 hover:underline md:mr-6 ">
|
||||||
|
{value.title}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer className="p-4 bg-white rounded-lg shadow md:px-6 md:py-8 dark:bg-gray-900">
|
||||||
|
<div className="sm:flex sm:items-center sm:justify-between">
|
||||||
|
<a href="https://flowbite.com/" className="flex items-center mb-4 sm:mb-0">
|
||||||
|
<img src="https://flowbite.com/docs/images/logo.svg" className="h-8 mr-3" alt="Flowbite Logo"/>
|
||||||
|
<span className="self-center text-2xl font-semibold whitespace-nowrap dark:text-white">Flowbite</span>
|
||||||
|
</a>
|
||||||
|
<ul className="flex flex-wrap items-center mb-6 text-sm text-gray-500 sm:mb-0 dark:text-gray-400">
|
||||||
|
{items.map((item, index: number) => generateItem(item, index))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<hr className="my-6 border-gray-200 sm:mx-auto dark:border-gray-700 lg:my-8"/>
|
||||||
|
<span className="block text-sm text-gray-500 sm:text-center dark:text-gray-400">© 3 <a
|
||||||
|
href="https://flowbite.com/" className="hover:underline">Flowbite™</a>. All Rights Reserved.
|
||||||
|
</span>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Footer;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
* Replace this with your own classes
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* .container {
|
||||||
|
* }
|
||||||
|
*/
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import Header from './header';
|
||||||
|
|
||||||
|
describe('Header', () => {
|
||||||
|
it('should render successfully', () => {
|
||||||
|
const { baseElement } = render(<Header />);
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,152 @@
|
|||||||
|
import {Collapse, Dropdown} from "flowbite";
|
||||||
|
import {useEffect} from "react";
|
||||||
|
import delve from "dlv";
|
||||||
|
|
||||||
|
/* eslint-disable-next-line */
|
||||||
|
export interface AppHeaderProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Header({items = []}) {
|
||||||
|
useEffect(function mount() {
|
||||||
|
const burgerButton = document.getElementById('mega-menu-button');
|
||||||
|
const megaZone = document.getElementById('mega-menu');
|
||||||
|
new Collapse(megaZone, burgerButton);
|
||||||
|
|
||||||
|
const userButton = document.getElementById('user-menu-button');
|
||||||
|
const userZone = document.getElementById('user-dropdown');
|
||||||
|
new Dropdown(userZone, userButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateItem = (item, index, isActive = false) => {
|
||||||
|
const value = delve(item, 'attributes', {});
|
||||||
|
return (
|
||||||
|
<li key={value.title + index}>
|
||||||
|
{value.children.data.length > 0 ? dropdownItem(value, isActive) : regularItem(value, isActive)}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const regularItem = (item, isActive = false) => {
|
||||||
|
return (
|
||||||
|
<a href={item.url}
|
||||||
|
target={item.target}
|
||||||
|
className={(isActive ? 'text-blue-600' : '') + " block py-2 pl-3 pr-4 border-b border-gray-100 hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-blue-600 md:p-0 dark:text-blue-500 md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-blue-500 md:dark:hover:bg-transparent dark:border-gray-700"}
|
||||||
|
aria-current="page">{item.title}</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const regularDropdownItem = (item, index) => {
|
||||||
|
const value = delve(item, 'attributes', {});
|
||||||
|
return (
|
||||||
|
<li key={value.title + index}>
|
||||||
|
<a href={value.url}
|
||||||
|
className="dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-500">
|
||||||
|
{value.title}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dropdownItem = (item, isActive = false) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button id="mega-menu-dropdown-button"
|
||||||
|
data-dropdown-toggle="mega-menu-dropdown"
|
||||||
|
className={(isActive ? 'text-blue-600' : '') + " flex items-center justify-between w-full py-2 pl-3 pr-4 font-medium border-b border-gray-100 md:w-auto hover:bg-gray-50 md:hover:bg-transparent md:border-0 md:hover:text-blue-600 md:p-0 dark:text-gray-400 md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-blue-500 md:dark:hover:bg-transparent dark:border-gray-700"}>
|
||||||
|
{item.title}
|
||||||
|
<svg aria-hidden="true"
|
||||||
|
className="w-5 h-5 ml-1 md:w-4 md:h-4"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<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"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div id="mega-menu-dropdown"
|
||||||
|
className="absolute z-10 grid hidden w-auto text-sm bg-white border border-gray-100 rounded-lg shadow-md dark:border-gray-700 dark:bg-gray-700">
|
||||||
|
<div className="p-4 pb-0 text-gray-900 md:pb-4 dark:text-white">
|
||||||
|
<ul className="space-y-4" aria-labelledby="mega-menu-dropdown-button">
|
||||||
|
{item.children.data.map((children, index) => regularDropdownItem(children, index))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<nav
|
||||||
|
className="bg-white px-2 sm:px-4 py-2.5 dark:bg-gray-900 fixed w-full z-20 top-0 left-0 border-b border-gray-200 dark:border-gray-600">
|
||||||
|
<div className="container flex flex-wrap items-center justify-between mx-auto">
|
||||||
|
<a href="https://flowbite.com" className="flex items-center">
|
||||||
|
<img src="https://flowbite.com/docs/images/logo.svg" className="h-6 mr-3 sm:h-9" alt="Flowbite Logo"/>
|
||||||
|
<span className="self-center text-xl font-semibold whitespace-nowrap dark:text-white">Flowbite</span>
|
||||||
|
</a>
|
||||||
|
<div className="flex items-center md:order-2">
|
||||||
|
<a href="#"
|
||||||
|
className="text-gray-800 dark:text-white hover:bg-gray-50 focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-4 py-2 md:px-5 md:py-2.5 mr-1 md:mr-2 dark:hover:bg-gray-700 focus:outline-none dark:focus:ring-gray-800">Login</a>
|
||||||
|
<a href="#"
|
||||||
|
className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-4 py-2 md:px-5 md:py-2.5 mr-1 md:mr-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Sign
|
||||||
|
up</a>
|
||||||
|
|
||||||
|
<button type="button"
|
||||||
|
className="flex mr-3 text-sm bg-gray-800 rounded-full md:mr-0 focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600"
|
||||||
|
id="user-menu-button" aria-expanded="false" data-dropdown-toggle="user-dropdown"
|
||||||
|
data-dropdown-placement="bottom">
|
||||||
|
<span className="sr-only">Open user menu</span>
|
||||||
|
<img className="w-8 h-8 rounded-full" src="/docs/images/people/profile-picture-3.jpg" alt="user photo"/>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
className="z-50 hidden my-4 text-base list-none bg-white divide-y divide-gray-100 rounded shadow dark:bg-gray-700 dark:divide-gray-600"
|
||||||
|
id="user-dropdown">
|
||||||
|
<div className="px-4 py-3">
|
||||||
|
<span className="block text-sm text-gray-900 dark:text-white">Bonnie Green</span>
|
||||||
|
<span
|
||||||
|
className="block text-sm font-medium text-gray-500 truncate dark:text-gray-400">name@flowbite.com</span>
|
||||||
|
</div>
|
||||||
|
<ul className="py-1" aria-labelledby="user-menu-button">
|
||||||
|
<li>
|
||||||
|
<a href="#"
|
||||||
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Dashboard</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#"
|
||||||
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Settings</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#"
|
||||||
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Earnings</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#"
|
||||||
|
className="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-200 dark:hover:text-white">Sign
|
||||||
|
out</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="mega-menu-button" data-collapse-toggle="mega-menu" type="button"
|
||||||
|
className="inline-flex items-center p-2 ml-1 text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600"
|
||||||
|
aria-controls="mega-menu" aria-expanded="false">
|
||||||
|
<span className="sr-only">Open main menu</span>
|
||||||
|
<svg aria-hidden="true" className="w-6 h-6" fill="currentColor" viewBox="0 0 20 20"
|
||||||
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fillRule="evenodd"
|
||||||
|
d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
|
||||||
|
clipRule="evenodd"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="mega-menu" className="items-center justify-between hidden w-full md:flex md:w-auto md:order-1">
|
||||||
|
<ul className="flex flex-col mt-4 font-medium md:flex-row md:space-x-8 md:mt-0">
|
||||||
|
{items.map((item, index: number) => generateItem(item, index))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header;
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Replace this with your own classes
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* .container {
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
.app-container {
|
||||||
|
position: relative;
|
||||||
|
padding-top: 70px;
|
||||||
|
height: calc(100% - 181px);
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import Layout from './layout';
|
||||||
|
|
||||||
|
describe('Layout', () => {
|
||||||
|
it('should render successfully', () => {
|
||||||
|
const { baseElement } = render(<Layout />);
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
import Header from "../header/header";
|
||||||
|
import Footer from "../footer/footer";
|
||||||
|
|
||||||
|
import styles from './layout.module.scss';
|
||||||
|
|
||||||
|
export function Layout({menuHeader = [], menuFooter = [], children}) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header items={menuHeader}/>
|
||||||
|
<div className={styles['app-container'] + ' max-w-lg mx-auto'}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
<Footer items={menuFooter}/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
* Replace this with your own classes
|
||||||
|
*
|
||||||
|
* e.g.
|
||||||
|
* .container {
|
||||||
|
* }
|
||||||
|
*/
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
|
import SeoConfig from './seo-config';
|
||||||
|
|
||||||
|
describe('SeoConfig', () => {
|
||||||
|
it('should render successfully', () => {
|
||||||
|
const { baseElement } = render(<SeoConfig />);
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
import delve from "dlv";
|
||||||
|
|
||||||
|
import {siteConfig} from "../../config";
|
||||||
|
import Head from "next/head";
|
||||||
|
|
||||||
|
export const SeoConfig = ({metaDescription = null, lang = null, meta = [], metaTitle = null, SharedImage = null}) => {
|
||||||
|
const description = metaDescription || siteConfig.siteDescription;
|
||||||
|
const title = metaTitle || siteConfig.siteTitle;
|
||||||
|
const metaImage = SharedImage ? delve(SharedImage, `media.data.attributes.formats.small.url`, siteConfig.siteLogo) : siteConfig.siteLogo;
|
||||||
|
const metaLang = lang || siteConfig.siteLanguage;
|
||||||
|
const metas = [
|
||||||
|
{
|
||||||
|
name: `description`,
|
||||||
|
content: metaDescription
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:title`,
|
||||||
|
content: metaTitle
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:description`,
|
||||||
|
content: metaDescription
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:image`,
|
||||||
|
content: metaImage
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:type`,
|
||||||
|
content: 'website'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:card`,
|
||||||
|
content: `summary_large_image`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:creator`,
|
||||||
|
content: siteConfig.author
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:title`,
|
||||||
|
content: metaTitle
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:description`,
|
||||||
|
content: metaDescription
|
||||||
|
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const metaList = meta && meta.length > 0 ? meta : metas;
|
||||||
|
const type = 'website';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Head>
|
||||||
|
<title>{title}</title>
|
||||||
|
<meta name="description"
|
||||||
|
content={description}/>
|
||||||
|
<meta property="og:title"
|
||||||
|
content={title}/>
|
||||||
|
<meta property="lang"
|
||||||
|
content={lang}/>
|
||||||
|
{metaList.map((meta, index) => (
|
||||||
|
<meta key={meta + index} property={meta.name} content={meta.content}/>
|
||||||
|
))}
|
||||||
|
</Head>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SeoConfig;
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
export default {
|
||||||
|
env: process.env.NODE_ENV,
|
||||||
|
mainApiEndpoint: 'https://conduit.productionready.io/api'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const theme = {
|
||||||
|
colors: {
|
||||||
|
primary: '#3b5998',
|
||||||
|
secondary: '#8b9dc3',
|
||||||
|
gray: '#f7f7f7'
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
xl: 1200,
|
||||||
|
l: 900,
|
||||||
|
m: 750,
|
||||||
|
s: 400
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const siteConfig = {
|
||||||
|
siteTitle: 'Conduit', // Navigation and Site Title
|
||||||
|
siteUrl: process.env.ROOT_URL || 'https://next.org', // Domain of your site. No trailing slash!
|
||||||
|
siteLanguage: 'fr', // Language Tag on <html> element
|
||||||
|
siteLogo: '/logo.png', // Used for SEO and manifest, path to your image you placed in the 'static' folder
|
||||||
|
siteDescription: 'Real world example of nextjs SSR',
|
||||||
|
author: 'arrlancore', // Author for schemaORGJSONLD
|
||||||
|
organization: 'Open Source Organization',
|
||||||
|
|
||||||
|
userTwitter: '@arrlancore', // Twitter Username
|
||||||
|
ogSiteName: 'Dwiki Arlan', // Facebook Site Name
|
||||||
|
ogLanguage: 'en_US',
|
||||||
|
googleAnalyticsID: process.env.GOOGLE_ANALYTIC_ID || 'UA-XXX123-1',
|
||||||
|
|
||||||
|
// Manifest and Progress color
|
||||||
|
themeColor: '#4147DC',
|
||||||
|
backgroundColor: '#231C42',
|
||||||
|
|
||||||
|
// Social component
|
||||||
|
twitter: 'https://twitter.com/arrlancore/',
|
||||||
|
twitterHandle: '@arrlancore',
|
||||||
|
github: 'https://github.com/arrlancore/',
|
||||||
|
youtube: 'https://www.youtube.com/',
|
||||||
|
rss: 'https://next.org/blog/rss.xml'
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import axios, {AxiosRequestConfig} from "axios";
|
||||||
|
|
||||||
|
export class ServerApiRequest {
|
||||||
|
|
||||||
|
private _axiosConfig: AxiosRequestConfig = {};
|
||||||
|
|
||||||
|
async getSeoMetadata(slug: string): Promise<any> {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${process.env.STRAPI_URL}/pages?slug=${slug}&populate=deep`);
|
||||||
|
console.log(response);
|
||||||
|
if (response && response.data) {
|
||||||
|
return response.data;
|
||||||
|
} else {
|
||||||
|
throw new Error('no data');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMenu(): Promise<any> {
|
||||||
|
try {
|
||||||
|
const response = await axios.get(`${process.env.STRAPI_URL}/menus/1?nested&populate=deep`);
|
||||||
|
|
||||||
|
if (response && response.data) {
|
||||||
|
return response.data;
|
||||||
|
} else {
|
||||||
|
throw new Error('no data');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const serverApiRequest = new ServerApiRequest();
|
||||||
|
export default serverApiRequest;
|
||||||
@ -1,400 +1,15 @@
|
|||||||
html {
|
@tailwind components;
|
||||||
-webkit-text-size-adjust: 100%;
|
@tailwind base;
|
||||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
|
@tailwind utilities;
|
||||||
Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif,
|
|
||||||
Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
|
||||||
line-height: 1.5;
|
|
||||||
tab-size: 4;
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
font-family: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
p,
|
|
||||||
pre {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
*,
|
|
||||||
::before,
|
|
||||||
::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-width: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: currentColor;
|
|
||||||
}
|
|
||||||
h1,
|
|
||||||
h2 {
|
|
||||||
font-size: inherit;
|
|
||||||
font-weight: inherit;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
||||||
Liberation Mono, Courier New, monospace;
|
|
||||||
}
|
|
||||||
svg {
|
|
||||||
display: block;
|
|
||||||
vertical-align: middle;
|
|
||||||
shape-rendering: auto;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
background-color: rgba(55, 65, 81, 1);
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
color: rgba(229, 231, 235, 1);
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
||||||
Liberation Mono, Courier New, monospace;
|
|
||||||
overflow: scroll;
|
|
||||||
padding: 0.5rem 0.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shadow {
|
|
||||||
box-shadow: 0 0 #0000, 0 0 #0000, 0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
html, body {
|
||||||
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
.rounded {
|
|
||||||
border-radius: 1.5rem;
|
|
||||||
}
|
|
||||||
.wrapper {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
max-width: 768px;
|
|
||||||
padding-bottom: 3rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
color: rgba(55, 65, 81, 1);
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
#welcome {
|
|
||||||
margin-top: 2.5rem;
|
|
||||||
}
|
|
||||||
#welcome h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
#welcome span {
|
|
||||||
display: block;
|
|
||||||
font-size: 1.875rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 2.25rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
#hero {
|
|
||||||
align-items: center;
|
|
||||||
background-color: hsla(214, 62%, 21%, 1);
|
|
||||||
border: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: rgba(55, 65, 81, 1);
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
}
|
|
||||||
#hero .text-container {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
padding: 3rem 2rem;
|
|
||||||
}
|
|
||||||
#hero .text-container h2 {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: 2rem;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
|
||||||
#hero .text-container h2 svg {
|
|
||||||
color: hsla(162, 47%, 50%, 1);
|
|
||||||
height: 2rem;
|
|
||||||
left: -0.25rem;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 2rem;
|
|
||||||
}
|
|
||||||
#hero .text-container h2 span {
|
|
||||||
margin-left: 2.5rem;
|
|
||||||
}
|
|
||||||
#hero .text-container a {
|
|
||||||
background-color: rgba(255, 255, 255, 1);
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
color: rgba(55, 65, 81, 1);
|
|
||||||
display: inline-block;
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
padding: 1rem 2rem;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
#hero .logo-container {
|
|
||||||
display: none;
|
|
||||||
justify-content: center;
|
|
||||||
padding-left: 2rem;
|
|
||||||
padding-right: 2rem;
|
|
||||||
}
|
|
||||||
#hero .logo-container svg {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
width: 66.666667%;
|
|
||||||
}
|
|
||||||
#middle-content {
|
|
||||||
align-items: flex-start;
|
|
||||||
display: grid;
|
|
||||||
gap: 4rem;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
}
|
|
||||||
#learning-materials {
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
}
|
|
||||||
#learning-materials h2 {
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 1.25rem;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
.list-item-link {
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 0.75rem;
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding: 1rem;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.list-item-link svg:first-child {
|
|
||||||
margin-right: 1rem;
|
|
||||||
height: 1.5rem;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
width: 1.5rem;
|
|
||||||
}
|
|
||||||
.list-item-link > span {
|
|
||||||
flex-grow: 1;
|
|
||||||
font-weight: 400;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
.list-item-link > span > span {
|
|
||||||
color: rgba(107, 114, 128, 1);
|
|
||||||
display: block;
|
|
||||||
flex-grow: 1;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1rem;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
.list-item-link svg:last-child {
|
|
||||||
height: 1rem;
|
|
||||||
transition-property: all;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
width: 1rem;
|
|
||||||
}
|
|
||||||
.list-item-link:hover {
|
|
||||||
color: rgba(255, 255, 255, 1);
|
|
||||||
background-color: hsla(162, 47%, 50%, 1);
|
|
||||||
}
|
|
||||||
.list-item-link:hover > span {
|
|
||||||
}
|
|
||||||
.list-item-link:hover > span > span {
|
|
||||||
color: rgba(243, 244, 246, 1);
|
|
||||||
}
|
|
||||||
.list-item-link:hover svg:last-child {
|
|
||||||
transform: translateX(0.25rem);
|
|
||||||
}
|
|
||||||
#other-links {
|
|
||||||
}
|
|
||||||
.button-pill {
|
|
||||||
padding: 1.5rem 2rem;
|
|
||||||
transition-duration: 300ms;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.button-pill svg {
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 3rem;
|
|
||||||
}
|
|
||||||
.button-pill > span {
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 1.125rem;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
.button-pill span span {
|
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
}
|
|
||||||
.button-pill:hover svg,
|
|
||||||
.button-pill:hover {
|
|
||||||
color: rgba(255, 255, 255, 1) !important;
|
|
||||||
}
|
|
||||||
#nx-console:hover {
|
|
||||||
background-color: rgba(0, 122, 204, 1);
|
|
||||||
}
|
|
||||||
#nx-console svg {
|
|
||||||
color: rgba(0, 122, 204, 1);
|
|
||||||
}
|
|
||||||
#nx-repo:hover {
|
|
||||||
background-color: rgba(24, 23, 23, 1);
|
|
||||||
}
|
|
||||||
#nx-repo svg {
|
|
||||||
color: rgba(24, 23, 23, 1);
|
|
||||||
}
|
|
||||||
#nx-cloud {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
margin-top: 2rem;
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
}
|
|
||||||
#nx-cloud > div {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
#nx-cloud > div svg {
|
|
||||||
border-radius: 0.375rem;
|
|
||||||
flex-shrink: 0;
|
|
||||||
width: 3rem;
|
|
||||||
}
|
|
||||||
#nx-cloud > div h2 {
|
|
||||||
font-size: 1.125rem;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
#nx-cloud > div h2 span {
|
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
}
|
|
||||||
#nx-cloud p {
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
#nx-cloud pre {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
#nx-cloud a {
|
|
||||||
color: rgba(107, 114, 128, 1);
|
|
||||||
display: block;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
#nx-cloud a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
#commands {
|
|
||||||
padding: 2.5rem 2rem;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
}
|
|
||||||
#commands h2 {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: -0.025em;
|
|
||||||
line-height: 1.75rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
#commands p {
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 300;
|
|
||||||
line-height: 1.5rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
details {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1rem;
|
|
||||||
padding-left: 1rem;
|
|
||||||
padding-right: 1rem;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
details pre > span {
|
|
||||||
color: rgba(181, 181, 181, 1);
|
body #__next {
|
||||||
display: block;
|
position: relative;
|
||||||
}
|
height: 100%;
|
||||||
summary {
|
|
||||||
border-radius: 0.5rem;
|
|
||||||
display: flex;
|
|
||||||
font-weight: 400;
|
|
||||||
padding: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
transition-property: background-color, border-color, color, fill, stroke,
|
|
||||||
opacity, box-shadow, transform, filter, backdrop-filter,
|
|
||||||
-webkit-backdrop-filter;
|
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
transition-duration: 150ms;
|
|
||||||
}
|
|
||||||
summary:hover {
|
|
||||||
background-color: rgba(243, 244, 246, 1);
|
|
||||||
}
|
|
||||||
summary svg {
|
|
||||||
height: 1.5rem;
|
|
||||||
margin-right: 1rem;
|
|
||||||
width: 1.5rem;
|
|
||||||
}
|
|
||||||
#love {
|
|
||||||
color: rgba(107, 114, 128, 1);
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.25rem;
|
|
||||||
margin-top: 3.5rem;
|
|
||||||
opacity: 0.6;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
#love svg {
|
|
||||||
color: rgba(252, 165, 165, 1);
|
|
||||||
width: 1.25rem;
|
|
||||||
height: 1.25rem;
|
|
||||||
display: inline;
|
|
||||||
margin-top: -0.25rem;
|
|
||||||
}
|
|
||||||
@media screen and (min-width: 768px) {
|
|
||||||
#hero {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
#hero .logo-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
#middle-content {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
const { join } = require('path');
|
||||||
|
|
||||||
|
// Note: If you use library-specific PostCSS/Tailwind configuration then you should remove the `postcssConfig` build
|
||||||
|
// option from your application's configuration (i.e. project.json).
|
||||||
|
//
|
||||||
|
// See: https://nx.dev/guides/using-tailwind-css-in-react#step-4:-applying-configuration-to-libraries
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {
|
||||||
|
config: join(__dirname, 'tailwind.config.js'),
|
||||||
|
},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
const { createGlobPatternsForDependencies } = require('@nrwl/react/tailwind');
|
||||||
|
const { join } = require('path');
|
||||||
|
|
||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
join(
|
||||||
|
__dirname,
|
||||||
|
'{src,pages,components}/**/*!(*.stories|*.spec).{ts,tsx,html}'
|
||||||
|
),
|
||||||
|
...createGlobPatternsForDependencies(__dirname),
|
||||||
|
"./node_modules/flowbite-react/**/*.js",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('flowbite/plugin')
|
||||||
|
],
|
||||||
|
};
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
services:
|
||||||
|
|
||||||
|
# PostgreSQL (Database)
|
||||||
|
gs_postgres:
|
||||||
|
extends:
|
||||||
|
file: apps/backend/postgres.yml
|
||||||
|
service: gs_postgres
|
||||||
|
|
||||||
|
gs_redis:
|
||||||
|
image: "redis:alpine"
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
|
||||||
|
gs_redis_commander:
|
||||||
|
image: rediscommander/redis-commander:latest
|
||||||
|
environment:
|
||||||
|
- REDIS_HOSTS=local:gs_redis:6379
|
||||||
|
ports:
|
||||||
|
- "8081:8081"
|
||||||
|
depends_on:
|
||||||
|
- gs_redis
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
gs_postgres-master:
|
||||||
|
driver: local
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue