Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/bouzayenilyes/meetup

video conferencing app using Next.js 14, Stream, and Tailwind CSS.
https://github.com/bouzayenilyes/meetup

clerkauth nextjs14 shadcn-ui stream tailwindcss typescript

Last synced: 21 days ago
JSON representation

video conferencing app using Next.js 14, Stream, and Tailwind CSS.

Awesome Lists containing this project

README

        

## βš™οΈ Tech Stack

- Next.js
- TypeScript
- Clerk
- getstream
- shadcn
- Tailwind CSS

## πŸ”‹ Features

πŸ‘‰ **Authentication**: Implements authentication and authorization features using Clerk, allowing users to securely log in via social sign-on or traditional email and password methods, while ensuring appropriate access levels and permissions within the platform.

πŸ‘‰ **New Meeting**: Quickly start a new meeting, configuring camera and microphone settings before joining.

πŸ‘‰ **Meeting Controls**: Participants have full control over meeting aspects, including recording, emoji reactions, screen sharing, muting/unmuting, sound adjustments, grid layout, participant list view, and individual participant management (pinning, muting, unmuting, blocking, allowing video share).

πŸ‘‰ **Exit Meeting**: Participants can leave a meeting, or creators can end it for all attendees.

πŸ‘‰ **Schedule Future Meetings**: Input meeting details (date, time) to schedule future meetings, accessible on the 'Upcoming Meetings' page for sharing the link or immediate start.

πŸ‘‰ **Past Meetings List**: Access a list of previously held meetings, including details and metadata.

πŸ‘‰ **View Recorded Meetings**: Access recordings of past meetings for review or reference.

πŸ‘‰ **Personal Room**: Users have a personal room with a unique meeting link for instant meetings, shareable with others.

πŸ‘‰ **Join Meetings via Link**: Easily join meetings created by others by providing a link.

πŸ‘‰ **Secure Real-time Functionality**: All interactions within the platform are secure and occur in real-time, maintaining user privacy and data integrity.

πŸ‘‰ **Responsive Design**: Follows responsive design principles to ensure optimal user experience across devices, adapting seamlessly to different screen sizes and resolutions.

and many more, including code architecture and reusability.

## 🀸 Quick Start

Follow these steps to set up the project locally on your machine.

**Prerequisites**

Make sure you have the following installed on your machine:

- [Git](https://git-scm.com/)
- [Node.js](https://nodejs.org/en)
- [npm](https://www.npmjs.com/) (Node Package Manager)

**Cloning the Repository**

```bash
git clone https://github.com/bouzayenilyes/meetup.git
cd meetup
```

**Installation**

Install the project dependencies using npm:

```bash
npm install
```

**Set Up Environment Variables**

Create a new file named `.env` in the root of your project and add the following content:

```env
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=

NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up

NEXT_PUBLIC_STREAM_API_KEY=
STREAM_SECRET_KEY=
```

Replace the placeholder values with your actual Clerk & getstream credentials. You can obtain these credentials by signing up on the [Clerk website](https://clerk.com/) and [getstream website](https://getstream.io/)

**Running the Project**

```bash
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) in your browser to view the project.

## πŸ•ΈοΈ Snippets

app/globals.css

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

/* ======== stream css overrides ======== */
.str-video__call-stats {
max-width: 500px;
position: relative;
}

.str-video__speaker-layout__wrapper {
max-height: 700px;
}

.str-video__participant-details {
color: white;
}

.str-video__menu-container {
color: white;
}

.str-video__notification {
color: white;
}

.str-video__participant-list {
background-color: #1c1f2e;
padding: 10px;
border-radius: 10px;
color: white;
height: 100%;
}

.str-video__call-controls__button {
height: 40px;
}

.glassmorphism {
background: rgba(255, 255, 255, 0.25);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.glassmorphism2 {
background: rgba(18, 17, 17, 0.25);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}

/* ==== clerk class override ===== */

.cl-userButtonPopoverActionButtonIcon {
color: white;
}

.cl-logoBox {
height: 40px;
}
.cl-dividerLine {
background: #252a41;
height: 2px;
}

.cl-socialButtonsIconButton {
border: 3px solid #565761;
}

.cl-internal-wkkub3 {
color: white;
}
.cl-userButtonPopoverActionButton {
color: white;
}

/* =============================== */

@layer utilities {
.flex-center {
@apply flex justify-center items-center;
}

.flex-between {
@apply flex justify-between items-center;
}
}

/* animation */

.show-block {
width: 100%;
max-width: 350px;
display: block;
animation: show 0.7s forwards linear;
}

@keyframes show {
0% {
animation-timing-function: ease-in;
width: 0%;
}

100% {
animation-timing-function: ease-in;
width: 100%;
}
}
```

tailwind.config.ts

```typescript
import type { Config } from 'tailwindcss';

const config = {
darkMode: ['class'],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
prefix: '',
theme: {
container: {
center: true,
padding: '2rem',
screens: {
'2xl': '1400px',
},
},
extend: {
colors: {
dark: {
1: '#1C1F2E',
2: '#161925',
3: '#252A41',
4: '#1E2757',
},
blue: {
1: '#0E78F9',
},
sky: {
1: '#C9DDFF',
2: '#ECF0FF',
3: '#F5FCFF',
},
orange: {
1: '#FF742E',
},
purple: {
1: '#830EF9',
},
yellow: {
1: '#F9A90E',
},
},
keyframes: {
'accordion-down': {
from: { height: '0' },
to: { height: 'var(--radix-accordion-content-height)' },
},
'accordion-up': {
from: { height: 'var(--radix-accordion-content-height)' },
to: { height: '0' },
},
},
animation: {
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out',
},
backgroundImage: {
hero: "url('/images/hero-background.png')",
},
},
},
plugins: [require('tailwindcss-animate')],
} satisfies Config;

export default config;
```

components/MeetingCard.tsx

```typescript
"use client";

import Image from "next/image";

import { cn } from "@/lib/utils";
import { Button } from "./ui/button";
import { avatarImages } from "@/constants";
import { useToast } from "./ui/use-toast";

interface MeetingCardProps {
title: string;
date: string;
icon: string;
isPreviousMeeting?: boolean;
buttonIcon1?: string;
buttonText?: string;
handleClick: () => void;
link: string;
}

const MeetingCard = ({
icon,
title,
date,
isPreviousMeeting,
buttonIcon1,
handleClick,
link,
buttonText,
}: MeetingCardProps) => {
const { toast } = useToast();

return (





{title}


{date}







{avatarImages.map((img, index) => (
0 })}
style={{ top: 0, left: index * 28 }}
/>
))}

+5


{!isPreviousMeeting && (


{buttonIcon1 && (

)}
Β  {buttonText}

{
navigator.clipboard.writeText(link);
toast({
title: "Link Copied",
});
}}
className="bg-dark-4 px-6"
>

Β  Copy Link


)}


);
};

export default MeetingCard;
```