V1 without presentation styling

This commit is contained in:
Daniel Heras Quesada
2024-01-16 23:53:33 +01:00
parent 39705a7b43
commit 3869d67172
295 changed files with 378 additions and 1255 deletions

View File

@@ -1,16 +0,0 @@
import { getRandomWordList } from "@/words/word-list/utils";
const getServerSideProps = async () => {
const wordList = await getRandomWordList();
console.log("Data is being fetch...", wordList)
return { props: { wordList:wordList } }
}
export default async function WordList(){
const wordList = await getServerSideProps();
return (
<div data-testid="word-list-view">
WordList server props: {JSON.stringify(wordList)}
</div>
)
}

View File

@@ -1 +0,0 @@
export * from './word-list.view'

View File

@@ -1,15 +0,0 @@
import { WordListRepsonse } from './word-list.types'
const dataURL = 'http://localhost:3000/words/es?complexity=easy&howMany=10'
export async function getStaticProps() {
const randomWordList = await getRandomWordList();
return {
props: { randomWordList }, // will be passed to the page component as props
}
}
export async function getRandomWordList() {
const wordList: WordListRepsonse = await fetch(dataURL).then((response) => response.json());
return wordList;
}

View File

@@ -1,3 +0,0 @@
.container {
}

View File

@@ -1,23 +0,0 @@
import type { Meta, StoryObj } from '@storybook/react'
import { expect } from '@storybook/jest'
import { within } from '@storybook/testing-library'
import { WordListView } from './word-list.view'
const meta: Meta<typeof WordListView> = {
title: 'WordListView',
component: WordListView,
argTypes: {},
}
export default meta
type Story = StoryObj<typeof WordListView>
export const Default: Story = {
args: {},
async play({ canvasElement }) {
const canvas = within(canvasElement)
const container = canvas.getByTestId('word-list-view')
expect(container).toBeTruthy()
},
}

View File

@@ -1,8 +0,0 @@
export type WordElement = {
word: string
correct?: boolean
}
export type WordListRepsonse = {
wordList: WordElement[]
}

View File

@@ -1,15 +0,0 @@
import React from 'react'
import styles from './word-list.module.css'
import { InferGetServerSidePropsType, InferGetStaticPropsType } from 'next'
import { getRandomWordList, getStaticProps } from './utils'
export function WordListView(
props: InferGetStaticPropsType<typeof getStaticProps>
) {
return (
<div data-testid="word-list-view" className={styles.container}>
WordList: {JSON.stringify(props?.randomWordList)}
</div>
)
}

View File

@@ -1,5 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@100;200;300;400;500;600;700;800;900&display=swap');

Submodule examples/front-arch-ssr-react deleted from febdeb7828

View File

@@ -1,15 +0,0 @@
# Generated files
node_modules
output
dist
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +0,0 @@
{
"name": "presentation-animations",
"private": true,
"version": "0.0.0",
"scripts": {
"serve": "vite",
"build": "tsc && vite build"
},
"dependencies": {
"@motion-canvas/core": "^3.11.0",
"@motion-canvas/2d": "^3.11.0",
"@motion-canvas/ffmpeg": "^1.1.0"
},
"devDependencies": {
"@motion-canvas/ui": "^3.11.0",
"@motion-canvas/vite-plugin": "^3.11.0",
"typescript": "^4.9.5",
"vite": "^4.1.4"
}
}

View File

@@ -1 +0,0 @@
/// <reference types="@motion-canvas/core/project" />

View File

@@ -1,32 +0,0 @@
{
"version": 0,
"shared": {
"background": null,
"range": [
0,
null
],
"size": {
"x": 1920,
"y": 1080
},
"audioOffset": 0
},
"preview": {
"fps": 30,
"resolutionScale": 1
},
"rendering": {
"fps": 60,
"resolutionScale": 1,
"colorSpace": "srgb",
"exporter": {
"name": "@motion-canvas/core/image-sequence",
"options": {
"fileType": "image/png",
"quality": 100,
"groupByScene": false
}
}
}
}

View File

@@ -1,7 +0,0 @@
import {makeProject} from '@motion-canvas/core';
import example from './scenes/example?scene';
export default makeProject({
scenes: [example],
});

View File

@@ -1,5 +0,0 @@
{
"version": 0,
"timeEvents": [],
"seed": 1375832605
}

View File

@@ -1,22 +0,0 @@
import {makeScene2D, Circle} from '@motion-canvas/2d';
import {all, createRef} from '@motion-canvas/core';
export default makeScene2D(function* (view) {
const myCircle = createRef<Circle>();
view.add(
<Circle
ref={myCircle}
// try changing these properties:
x={-300}
width={140}
height={140}
fill="#e13238"
/>,
);
yield* all(
myCircle().position.x(300, 1).to(-300, 1),
myCircle().fill('#e6a700', 1).to('#e13238', 1),
);
});

View File

@@ -1,4 +0,0 @@
{
"extends": "@motion-canvas/2d/tsconfig.project.json",
"include": ["src"]
}

View File

@@ -1,10 +0,0 @@
import {defineConfig} from 'vite';
import motionCanvas from '@motion-canvas/vite-plugin';
import ffmpeg from '@motion-canvas/ffmpeg';
export default defineConfig({
plugins: [
motionCanvas(),
ffmpeg(),
],
});

View File

@@ -1,6 +1,9 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
reactStrictMode: true, reactStrictMode: true,
experimental: {
serverActions: true,
},
// Avoiding CORS issues // Avoiding CORS issues
// async rewrites() { // async rewrites() {
// return [ // return [

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 629 B

View File

@@ -0,0 +1,140 @@
'use client'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
export default function Presentation() {
const [current, setCurrent] = useState<number>(0)
const stages = [
<Introduction />,
<Benefits />,
<Rendering />,
<Strategies />,
<DataFetching />,
]
return (
<div className="main-presentation">
{stages[current]}
<button
onClick={() =>
setCurrent(current + 1 < stages.length ? current + 1 : 0)
}
>
Siguiente
</button>
</div>
)
}
// 1. Introduction
// 2. Rendering strategies.
// 3. Benefits.
// 4. Actual process and why its important to know it.
// 5. Serverside data fetching
function Introduction() {
return (
<div className="main-presentation-comparation">
<h3>Next</h3>
<div>
<p>Nos da la posibilidad de renderizar desde el servidor</p>
</div>
</div>
)
}
function Rendering() {
return (
<div className="main-presentation-comparation">
<h3>Rendering</h3>
<div>
The rendering works is split into chunks: - By individual route
segments - By React [Suspense
boundaries](https://react.dev/reference/react/Suspense) (react
way of having a fallback while a components has finished
loading) Each chunk is rendered in the server, then, on the
client: 1. The HTML is used to immediately show fast preview. 2.
The server components rendered are inserted to update the DOM
(components rendered in server with placeholders for client
components and props). 3. `JS` instructions are used to
[hydrate?](https://react.dev/reference/react-dom/client/hydrateRoot)
Client Components and make the application interactive.
</div>
</div>
)
}
function Strategies() {
return (
<div className="main-presentation-strategies">
<h3>Strategies</h3>
<div>
<ul>
<li>
- Static rendering (default): Good for static pages:
Rendered in build time or in the background after data
revalidation
</li>
<li>
- Security: sensitive data is kept int the server (API
keys and tokens)
</li>
<li>
- Dynamic rendering: rendered per user request, Next
uses this type of rendering automatically when discovers
a dynamic function (`cookies()`, `headers()`,
`userSearchParams()`).
</li>
<li>
- Streaming: work is split into chunks and streamed as
they become ready so the load is progressive.
</li>
</ul>
</div>
</div>
)
}
function Benefits() {
return (
<div className="main-presentation-benefits">
<h3>Beneficios</h3>
<div>
<ul>
<li>
- Fetch data directly on the server, performance and
load benefits.
</li>
<li>
- Security: sensitive data is kept int the server (API
keys and tokens)
</li>
<li>
- Caching: results can be cached to improve performance
between users.
</li>
<li>
- Bundle size: will be reduced as part of the
application will reside in the server.
</li>
<li>
- SEO: because the pages will be rendered the search
engine bots will make good use of it.
</li>
<li>
- Streaming: to split the rendering into chunks and
stream them as they become ready.
</li>
</ul>
</div>
</div>
)
}
function DataFetching() {
const router = useRouter()
router.push('/word-list')
return <>Redirecting...</>
}

View File

@@ -0,0 +1,6 @@
'use server'
import { revalidateTag } from 'next/cache'
export async function revalidateFetchByTag(tag: string) {
revalidateTag(tag)
}

View File

@@ -0,0 +1,31 @@
'use client'
import { useEffect, useState } from 'react'
import { WordListRepsonse, fetchWordlist } from '../utils'
export default function ClientWordList() {
const [data, setData] = useState<WordListRepsonse>()
const fetchData = () =>
fetchWordlist().then((response) => setData(response))
useEffect(() => {
fetchData()
}, [])
return (
<div className="data-fetching-client">
<h3>
Wordlist fetched in the <span>client</span>
</h3>
<div>
{data?.wordList.map((word) => (
<span>{word.word}</span>
))}
</div>
<div>
<button onClick={fetchData}>Revalidate!</button>
</div>
</div>
)
}

View File

@@ -0,0 +1,15 @@
'use client'
import { useRouter } from 'next/navigation'
export default function GoBackButton() {
const router = useRouter()
return (
<button
style={{ position: 'absolute' }}
onClick={() => router.push('/presentation')}
>
Go back to presentation
</button>
)
}

View File

@@ -0,0 +1,11 @@
'use client'
import { revalidateFetchByTag } from '../actions'
export default function RevalidateButton() {
return (
<button onClick={() => revalidateFetchByTag('wordlist')}>
Revalidate!
</button>
)
}

View File

@@ -0,0 +1,22 @@
import RevalidateButton from './revalidate-button'
import { fetchWordlist } from '../utils'
export default async function ServerWordList() {
const response = await fetchWordlist()
return (
<div data-testid="word-list-view" className="data-fetching-server">
<h3>
Wordlist fetched in the <span>server</span>
</h3>
<div>
{response?.wordList.map((word) => (
<span>{word.word}</span>
))}
</div>
<div>
<RevalidateButton />
</div>
</div>
)
}

View File

@@ -0,0 +1,12 @@
import ClientWordList from './components/clientside-word-list'
import GoBackButton from './components/go-back-button'
import ServerWordList from './components/serverside-word-list'
export default function WordList() {
return (
<div className="data-fetching">
<ServerWordList />
<ClientWordList />
</div>
)
}

View File

@@ -0,0 +1,22 @@
const WORDLIST_API_URL =
'http://localhost:3000/words/es?complexity=medium&howMany=30'
export type WordElement = {
word: string
correct?: boolean
}
export type WordListRepsonse = {
wordList: WordElement[]
}
// fetch("https://...", { cache: "no-store" });
export const fetchWordlist = async () => {
const wordList: WordListRepsonse = await fetch(WORDLIST_API_URL, {
next: { tags: ['wordlist'] },
}).then((response) => response.json())
console.log('Data fetch is done', wordList)
return wordList
}

Some files were not shown because too many files have changed in this diff Show More