Skip to content

Commit 791daf5

Browse files
ctmphuonggLeo6Leo
andauthored
Sample app frontend (#5931)
* Add darkmode * Edit README * Add comments and readme * Fix UI * Update README * Update code-samples/eventing/bookstore-sample-app/frontend/client/pages/Main.js Co-authored-by: Leo Li <leoli@redhat.com> * Update code-samples/eventing/bookstore-sample-app/frontend/client/components/BookDetail.js Co-authored-by: Leo Li <leoli@redhat.com> * Change emoji * Update code-samples/eventing/bookstore-sample-app/frontend/client/components/Toggle.js Co-authored-by: Leo Li <leoli@redhat.com> * Fix UI * Align time --------- Co-authored-by: Leo Li <leoli@redhat.com>
1 parent bf326bb commit 791daf5

24 files changed

+8094
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
.yarn/install-state.gz
8+
9+
# testing
10+
/coverage
11+
12+
# next.js
13+
/.next/
14+
/out/
15+
16+
# production
17+
/build
18+
19+
# misc
20+
.DS_Store
21+
*.pem
22+
23+
# debug
24+
npm-debug.log*
25+
yarn-debug.log*
26+
yarn-error.log*
27+
28+
# local env files
29+
.env*.local
30+
31+
# vercel
32+
.vercel
33+
34+
# typescript
35+
*.tsbuildinfo
36+
next-env.d.ts
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Use a base image with Node.js LTS
2+
FROM node:lts-alpine
3+
4+
# Set the working directory inside the container
5+
WORKDIR /app
6+
7+
# Copy package.json and package-lock.json to the working directory
8+
COPY package*.json ./
9+
10+
# Install dependencies
11+
RUN npm install
12+
13+
# Copy the rest of your application code to the working directory
14+
COPY . .
15+
16+
# Build the Next.js application
17+
RUN npm run build
18+
19+
# Expose the port your app runs on
20+
EXPOSE 3000
21+
22+
# Define the command to run your app
23+
CMD ["npm", "run dev"]
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Getting Started
2+
3+
This app use Next.js and TailwindCSS as main packages. Use this command to install all dependencies:
4+
5+
```bash
6+
npm install
7+
```
8+
9+
To run application, use:
10+
11+
```bash
12+
npm run dev
13+
# or
14+
yarn dev
15+
# or
16+
pnpm dev
17+
# or
18+
bun dev
19+
```
20+
21+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
22+
23+
# Project Structures
24+
25+
- app/: Contains the main layout, page, and global styling.
26+
- client/: Contains components and pages used in the application.
27+
- public/images/: Contains image files.
28+
- next-env.d.ts, next.config.mjs, package-lock.json, package.json, postcss.config.js, tailwind.config.js, tsconfig.json: Configuration files for Next.js, Tailwind CSS, and TypeScript.
29+
30+
# Containerize Application
31+
32+
This repository contains a Next.js application that utilizes next-themes and Tailwind CSS. This README file provides instructions on how to containerize the application using Docker.
33+
34+
## Prerequisites
35+
36+
- Docker installed on your machine. You can download and install Docker from [here](https://www.docker.com/get-started).
37+
38+
## Dockerization Steps
39+
40+
1. Clone this repository to your local machine.
41+
2. Navigate to the root directory of the cloned repository.
42+
43+
### Building the Docker Image
44+
45+
Run the following command to build the Docker image:
46+
47+
```bash
48+
docker build -t frontend .
49+
```
50+
51+
## Running the Docker Container
52+
53+
Once the image is built, you can run a container using the following command:
54+
55+
```bash
56+
docker run -d -p 3000:3000 frontend
57+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap');
6+
7+
#__next {
8+
min-height: 100vh;
9+
width: 100%;
10+
display: flex;
11+
flex-direction: column;
12+
}
13+
14+
body {
15+
font-family: 'Poppins', sans-serif;
16+
}
17+
18+
@layer utilities {
19+
.text-balance {
20+
text-wrap: balance;
21+
}
22+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { Metadata } from 'next';
2+
import { Inter } from 'next/font/google';
3+
import './globals.css';
4+
5+
const inter = Inter({ subsets: ['latin'] });
6+
7+
export const metadata: Metadata = {
8+
title: 'Knative Bookstore',
9+
description: 'Bookstore Sample Application from Knative',
10+
icons: {
11+
icon: '/images/knative-logo.png',
12+
},
13+
};
14+
15+
export default function RootLayout({
16+
children,
17+
}: Readonly<{
18+
children: React.ReactNode;
19+
}>) {
20+
return (
21+
<html lang='en'>
22+
<body className={inter.className}>{children}</body>
23+
</html>
24+
);
25+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use client';
2+
import Main from '../client/pages/Main';
3+
import { ThemeProvider } from 'next-themes';
4+
5+
export default function Home() {
6+
return (
7+
<ThemeProvider attribute='class'>
8+
<Main />
9+
</ThemeProvider>
10+
);
11+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const BookDetail = ({ book }) => {
2+
return (
3+
<div className='flex flex-col md:flex-row md:items-start p-8 space-x-8 justify-center items-center font-sans'>
4+
<div className='mb-4 md:mb-0 md:mr-8'>
5+
<img src={book.img} alt='Book Cover' className='w-48 h-auto' />
6+
</div>
7+
<div>
8+
<div className='space-y-4'>
9+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
10+
<span className='font-bold text-left'>Title:</span>
11+
<span className='text-left'>{book.title}</span>
12+
</div>
13+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
14+
<span className='font-bold text-left'>Author:</span>
15+
<span className='text-left'>{book.author}</span>
16+
</div>
17+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
18+
<span className='font-bold text-left'>ISBN:</span>
19+
<span>{book.ISBN}</span>
20+
</div>
21+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
22+
<span className='font-bold text-left'>Publisher:</span>
23+
<span>{book.publisher}</span>
24+
</div>
25+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
26+
<span className='font-bold text-left'>Published Date:</span>
27+
<span>{book.publishedDate}</span>
28+
</div>
29+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
30+
<span className='font-bold text-left'>Description:</span>
31+
<span>{book.description}</span>
32+
</div>
33+
<div className='grid grid-cols-[auto_1fr] gap-x-2 items-center'>
34+
<span className='font-bold text-left'>Price:</span>
35+
<span>{book.price}</span>
36+
</div>
37+
</div>
38+
</div>
39+
</div>
40+
);
41+
};
42+
43+
export default BookDetail;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Emoji from './Emoji';
2+
const CommentDisplay = ({ comment }) => {
3+
// Assume receiving a comment object
4+
let emoji;
5+
if (comment.emotion === 'Positive') {
6+
emoji = '😃';
7+
} else if (comment.emotion === 'Neutral') {
8+
emoji = '😐';
9+
} else {
10+
emoji = '😡';
11+
}
12+
return (
13+
<div className='flex my-4 p-4 justify-center align-middle items-center'>
14+
<div className='comment-display w-full w-7/12 flex flex-row rounded-lg p-4 bg-gray-800 text-white dark:bg-white dark:text-black'>
15+
<div className='flex items-center justify-center md:w-1/12'>
16+
<img
17+
src={comment.avatar}
18+
alt='Avatar'
19+
className='rounded-full w-8 h-8'
20+
/>
21+
</div>
22+
<div className='md:w-1/12 flex items-center content-center text-gray-200 dark:text-black'>
23+
{comment.time}
24+
</div>
25+
<div className='md:w-9/12 '>
26+
<span className='h-full flex items-center content-center'>
27+
{comment.text}
28+
</span>
29+
</div>
30+
<div className='md:w-1/12 text-4xl flex items-center content-center'>
31+
<Emoji symbol={emoji} label={comment.emotion} size='text-2xl' />
32+
</div>
33+
</div>
34+
</div>
35+
);
36+
};
37+
38+
export default CommentDisplay;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use-client';
2+
import { useState } from 'react';
3+
const CommentForm = () => {
4+
const [hover, setHover] = useState(false);
5+
const [comment, setComment] = useState('');
6+
7+
const handleInputChange = (event) => {
8+
setComment(event.target.value);
9+
};
10+
11+
const handleSubmit = (event) => {
12+
event.preventDefault();
13+
console.log('Submitted comment:', comment); // Use inspect to see
14+
};
15+
return (
16+
<div className='flex my-4 p-4 justify-center'>
17+
<form
18+
className='w-full w-8/12 flex flex-col items-end '
19+
onSubmit={handleSubmit}
20+
>
21+
<textarea
22+
className='form-textarea w-full mb-2 p-2 border border-2 border-black rounded-lg p-4'
23+
rows='3'
24+
placeholder='Leave your comment here...'
25+
value={comment}
26+
onChange={handleInputChange}
27+
></textarea>
28+
<button
29+
type='submit'
30+
className={`font-bold py-2 px-9 rounded ${
31+
hover ? '' : 'bg-blue-600'
32+
}`}
33+
style={{ backgroundColor: hover ? '#A0DDFF' : '#A5D8FF' }}
34+
onMouseEnter={() => setHover(true)}
35+
onMouseLeave={() => setHover(false)}
36+
>
37+
Submit
38+
</button>
39+
</form>
40+
</div>
41+
);
42+
};
43+
44+
export default CommentForm;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import CommentDisplay from './CommentDisplay';
2+
const CommentList = () => {
3+
const comment = {
4+
avatar: '/images/avatar.jpg',
5+
time: '10:05',
6+
text: 'I used this provider to insert a different theme object depending on a person ',
7+
emotion: 'Neutral',
8+
};
9+
return <CommentDisplay comment={comment} />;
10+
};
11+
12+
export default CommentList;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from 'react';
2+
const Emoji = (props) => (
3+
<span
4+
className='emoji'
5+
role='img'
6+
aria-label={props.label ? props.label : ''}
7+
aria-hidden={props.label ? 'false' : 'true'}
8+
>
9+
{props.symbol}
10+
</span>
11+
);
12+
export default Emoji;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import Image from 'next/image';
2+
import Toggle from './Toggle';
3+
4+
const Header = () => {
5+
return (
6+
<div className='flex justify-between p-4'>
7+
<header className='flex items-center p-4'>
8+
<Image
9+
src='/images/knative-logo.png'
10+
alt='Knative BookStore Logo'
11+
width={50}
12+
height={50}
13+
className='mr-2'
14+
/>
15+
<h1 className='text-3xl font-bold'>Knative BookStore</h1>
16+
</header>
17+
<Toggle />
18+
</div>
19+
);
20+
};
21+
22+
export default Header;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
'use client';
2+
import React from 'react';
3+
import { useTheme } from 'next-themes';
4+
import { useEffect } from 'react';
5+
6+
const Toggle = () => {
7+
const { systemTheme, theme, setTheme } = useTheme();
8+
useEffect(() => {
9+
const systemPreference = window.matchMedia('(prefers-color-scheme: dark)')
10+
.matches
11+
? 'dark'
12+
: 'light';
13+
14+
setTheme(systemPreference);
15+
}, []);
16+
return (
17+
<button
18+
onClick={() => (theme == 'dark' ? setTheme('light') : setTheme('dark'))}
19+
className='bg-gray-800 dark:bg-gray-50 hover:bg-gray-600 dark:hover:bg-gray-300 transition-all duration-100 text-white dark:text-gray-800 px-6 py-1 text-xl md:text-2xl rounded-md'
20+
>
21+
Mode
22+
</button>
23+
);
24+
};
25+
26+
export default Toggle;

0 commit comments

Comments
 (0)