diff --git a/README.md b/README.md index 334c116..7059a96 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ -These are the sequence of commands to run this chat application on any laptop:- - -1. mkdir chat-project -2. cd chat-project -3. Initialize a new Vite React project:- npm create vite@latest -4. Install the required dependencies:- npm install -5. Replace the default files with our chat application code: - a. Create the component files in the src/components directory - b. Update App.jsx, App.css, and other files as we have in this code. -6. Start the development server:- npm run dev -7. Open the application in your browser:- - a. The terminal will show a URL (usually http://localhost:5173/) - b. Open this URL in your browser +# React + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. diff --git a/package-lock.json b/package-lock.json index 19e24d3..28967fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "chat-project", + "name": "instagram-stories-project", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "chat-project", + "name": "instagram-stories-project", "version": "0.0.0", "dependencies": { "react": "^19.1.0", diff --git a/package.json b/package.json index 726a895..0296aa2 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "chat-project", + "name": "instagram-stories-project", "private": true, "version": "0.0.0", "type": "module", @@ -24,4 +24,4 @@ "globals": "^16.0.0", "vite": "^6.3.5" } -} +} \ No newline at end of file diff --git a/src/App.css b/src/App.css index 4816779..6ade16d 100644 --- a/src/App.css +++ b/src/App.css @@ -1,349 +1,14 @@ -#root { - max-width: 100%; - margin: 0; - padding: 0; - text-align: left; - height: 100vh; -} - -.chat-app { - display: flex; - height: 100vh; - width: 100%; - overflow: hidden; -} - -.sidebar { - width: 280px; - background-color: #f5f5f5; - border-right: 1px solid #e0e0e0; - display: flex; - flex-direction: column; -} - -.new-chat { - padding: 15px; - border-bottom: 1px solid #e0e0e0; -} - -.new-chat-btn { - width: 100%; - padding: 10px; - background-color: #0078d4; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; -} - -.new-chat form { - display: flex; - flex-direction: column; - gap: 10px; -} - -.new-chat input { - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; -} - -.new-chat .buttons { - display: flex; - gap: 10px; -} - -.new-chat .cancel { - background-color: #f0f0f0; - color: #333; -} - -.chat-list { - flex: 1; - overflow-y: auto; -} - -.chat-list h2 { - padding: 0 15px; - font-size: 16px; - color: #666; -} - -.chat-list ul { - list-style: none; - padding: 0; - margin: 0; -} - -.chat-list li { - padding: 12px 15px; - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - border-bottom: 1px solid #eee; -} - -.chat-list li:hover { - background-color: #eaeaea; -} - -.chat-list li.active { - background-color: #e1effa; - border-left: 3px solid #0078d4; -} - -.delete-btn { - background: none; - border: none; - color: #999; - font-size: 18px; - cursor: pointer; -} - -.delete-btn:hover { - color: #d32f2f; -} - -.chat-window { - flex: 1; - display: flex; - flex-direction: column; - background-color: #fff; -} - -.chat-header { - padding: 15px; - border-bottom: 1px solid #e0e0e0; - background-color: #f9f9f9; -} - -.chat-header h2 { - margin: 0; - font-size: 18px; -} - -.message-list { - flex: 1; - overflow-y: auto; - padding: 15px; - display: flex; - flex-direction: column; - gap: 10px; - background-color: #f5f5f5; -} - -.empty-message { - text-align: center; - color: #999; - margin-top: 40px; -} - -.message { - max-width: 70%; - margin-bottom: 10px; -} - -.message.sent { - align-self: flex-end; -} - -.message.received { - align-self: flex-start; -} - -.message-content { - padding: 10px 15px; - border-radius: 18px; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); -} - -.message.sent .message-content { - background-color: #0078d4; - color: white; - border-bottom-right-radius: 4px; -} - -.message.received .message-content { - background-color: white; - border-bottom-left-radius: 4px; -} - -.message-header { - display: flex; - justify-content: space-between; - margin-bottom: 5px; - font-size: 12px; -} - -.message p { +* { margin: 0; - word-break: break-word; -} - -.message-input { - display: flex; - padding: 15px; - border-top: 1px solid #e0e0e0; - background-color: #f9f9f9; -} - -.message-input input { - flex: 1; - padding: 10px 15px; - border: 1px solid #ccc; - border-radius: 20px; - margin-right: 10px; - font-size: 14px; -} - -.message-input button { - padding: 10px 20px; - background-color: #0078d4; - color: white; - border: none; - border-radius: 20px; - cursor: pointer; -} - -.chat-info { - display: flex; - align-items: center; - gap: 8px; - flex: 1; -} - -.chat-icon { - width: 20px; - text-align: center; -} - -.member-count { - background-color: #e0e0e0; - border-radius: 10px; - padding: 2px 6px; - font-size: 12px; - color: #666; -} - -.chat-header-info { - display: flex; - justify-content: space-between; - align-items: center; -} - -.members-toggle { - background-color: #f0f0f0; - border: 1px solid #ddd; - border-radius: 4px; - padding: 5px 10px; - font-size: 12px; - cursor: pointer; -} - -.chat-content { - display: flex; - flex: 1; - overflow: hidden; -} - -.members-panel { - width: 250px; - border-right: 1px solid #e0e0e0; - padding: 15px; - background-color: #f9f9f9; - overflow-y: auto; -} - -.members-panel h3 { - margin-top: 0; - font-size: 16px; - color: #666; - margin-bottom: 15px; -} - -.members-list { - list-style: none; padding: 0; - margin: 0 0 15px 0; -} - -.member-item { - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px 0; - border-bottom: 1px solid #eee; + box-sizing: border-box; } -.remove-member { - background: none; - border: none; - color: #999; - font-size: 16px; - cursor: pointer; +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; } -.add-member-form { - display: flex; - margin-top: 15px; - gap: 8px; -} - -.add-member-form input { - flex: 1; - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; -} - -.add-member-form button { - padding: 8px 12px; - background-color: #0078d4; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; -} - -.messages-container { - flex: 1; - display: flex; - flex-direction: column; - overflow: hidden; -} - -@media (max-width: 768px) { - .chat-app { - flex-direction: column; - } - - .sidebar { - width: 100%; - height: 30%; - border-right: none; - border-bottom: 1px solid #e0e0e0; - } - - .message { - max-width: 85%; - } - - .chat-content { - flex-direction: column; - } - - .members-panel { - width: 100%; - height: 200px; - border-right: none; - border-bottom: 1px solid #e0e0e0; - } -} - -.chat-type-select { - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; - margin-bottom: 10px; +.app-container { + max-width: 100%; + overflow-x: hidden; } diff --git a/src/App.jsx b/src/App.jsx index ba129ae..4ba74ff 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,121 +1,10 @@ -import { useState } from 'react' import './App.css' -import ChatList from './components/ChatList' -import ChatWindow from './components/ChatWindow' -import NewChatButton from './components/NewChatButton' +import Stories from './components/Stories' function App() { - const [chats, setChats] = useState([ - { - id: 1, - name: 'Personal Notes', - type: 'direct', - members: [], - messages: [] - } - ]) - - const [activeChat, setActiveChat] = useState(1) - - const createChat = (name, type = 'direct', members = []) => { - const newChat = { - id: Date.now(), - name: name || `Chat ${chats.length + 1}`, - type, - members, - messages: [] - } - - setChats([...chats, newChat]) - setActiveChat(newChat.id) - } - - const createGroupChat = (name, members) => { - createChat(name, 'group', members) - } - - const createChannel = (name) => { - createChat(name, 'channel') - } - - const deleteChat = (chatId) => { - setChats(chats.filter(chat => chat.id !== chatId)) - if (activeChat === chatId) { - setActiveChat(chats[0]?.id || null) - } - } - - const addMemberToChat = (chatId, memberId, memberName) => { - setChats(chats.map(chat => { - if (chat.id === chatId) { - return { - ...chat, - members: [...chat.members, { id: memberId, name: memberName }] - } - } - return chat - })) - } - - const removeMemberFromChat = (chatId, memberId) => { - setChats(chats.map(chat => { - if (chat.id === chatId) { - return { - ...chat, - members: chat.members.filter(member => member.id !== memberId) - } - } - return chat - })) - } - - const sendMessage = (content, sender = 'You') => { - if (!content.trim()) return - - const newMessage = { - id: Date.now(), - content, - sender, - timestamp: new Date() - } - - setChats(chats.map(chat => { - if (chat.id === activeChat) { - return { - ...chat, - messages: [...chat.messages, newMessage] - } - } - return chat - })) - } - - const currentChat = chats.find(chat => chat.id === activeChat) || chats[0] - return ( -
-
- - -
- - {currentChat && ( - - )} +
+
) } diff --git a/src/components/ChatList.jsx b/src/components/ChatList.jsx deleted file mode 100644 index 7e5af6f..0000000 --- a/src/components/ChatList.jsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react' - -function ChatList({ chats, activeChat, onSelectChat, onDeleteChat }) { - const getChatIcon = (type) => { - if (type === 'direct') return '👤' - if (type === 'group') return '👥' - if (type === 'channel') return '#' - return '💬' - } - - return ( -
-

Chats

-
    - {chats.map(chat => ( -
  • onSelectChat(chat.id)} - > -
    - {getChatIcon(chat.type)} - {chat.name} - - {chat.type !== 'direct' && chat.members.length > 0 && ( - {chat.members.length} - )} -
    - - -
  • - ))} -
-
- ) -} - -export default ChatList diff --git a/src/components/ChatWindow.jsx b/src/components/ChatWindow.jsx deleted file mode 100644 index 1ac1cf4..0000000 --- a/src/components/ChatWindow.jsx +++ /dev/null @@ -1,95 +0,0 @@ -import React, { useState, useRef, useEffect } from 'react' -import MessageList from './MessageList' -import MessageInput from './MessageInput' - -function ChatWindow({ chat, onSendMessage, onAddMember, onRemoveMember }) { - const [showMembers, setShowMembers] = useState(false) - const [newMember, setNewMember] = useState('') - - const messagesEndRef = useRef(null) - - useEffect(() => { - messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) - }, [chat.messages]) - - const handleAddMember = (e) => { - e.preventDefault() - if (newMember.trim()) { - onAddMember(chat.id, Date.now(), newMember) - setNewMember('') - } - } - - return ( -
-
-
-

- {chat.type !== 'direct' && ( - - {chat.type === 'group' ? '👥' : '#'} - - )} - {chat.name} -

- - {(chat.type === 'group' || chat.type === 'channel') && ( - - )} -
-
- -
- {showMembers && (chat.type === 'group' || chat.type === 'channel') && ( -
-

Members

- {chat.members.length > 0 ? ( -
    - {chat.members.map(member => ( -
  • - {member.name} - -
  • - ))} -
- ) : ( -

No members yet

- )} - -
- setNewMember(e.target.value)} - placeholder="Add member..." - /> - -
-
- )} - -
- -
-
-
- - -
- ) -} - -export default ChatWindow diff --git a/src/components/MembersList.jsx b/src/components/MembersList.jsx deleted file mode 100644 index 5f3d2c3..0000000 --- a/src/components/MembersList.jsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react' - -function MembersList({ members, onRemoveMember, chatId }) { - if (members.length === 0) { - return

No members yet

- } - - return ( -
    - {members.map(member => ( -
  • - {member.name} - -
  • - ))} -
- ) -} - -export default MembersList \ No newline at end of file diff --git a/src/components/Message.jsx b/src/components/Message.jsx deleted file mode 100644 index 277fd4a..0000000 --- a/src/components/Message.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react' - -function Message({ message }) { - const formatTime = (timestamp) => { - return new Intl.DateTimeFormat('en-US', { - hour: '2-digit', - minute: '2-digit' - }).format(timestamp) - } - - return ( -
-
-
- {message.sender} - {formatTime(message.timestamp)} -
-

{message.content}

-
-
- ) -} - -export default Message \ No newline at end of file diff --git a/src/components/MessageInput.jsx b/src/components/MessageInput.jsx deleted file mode 100644 index b86877c..0000000 --- a/src/components/MessageInput.jsx +++ /dev/null @@ -1,27 +0,0 @@ -import React, { useState } from 'react' - -function MessageInput({ onSendMessage, placeholder = "Type a message..." }) { - const [message, setMessage] = useState('') - - const handleSubmit = (e) => { - e.preventDefault() - if (message.trim()) { - onSendMessage(message) - setMessage('') - } - } - - return ( -
- setMessage(e.target.value)} - placeholder={placeholder} - /> - -
- ) -} - -export default MessageInput diff --git a/src/components/MessageList.jsx b/src/components/MessageList.jsx deleted file mode 100644 index fd326f5..0000000 --- a/src/components/MessageList.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react' -import Message from './Message' - -function MessageList({ messages }) { - if (messages.length === 0) { - return ( -
-

No messages yet. Start the conversation!

-
- ) - } - - return ( -
- {messages.map(message => ( - - ))} -
- ) -} - -export default MessageList \ No newline at end of file diff --git a/src/components/NewChatButton.jsx b/src/components/NewChatButton.jsx deleted file mode 100644 index 3e310ab..0000000 --- a/src/components/NewChatButton.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import React, { useState } from 'react' - -function NewChatButton({ onCreateChat, onCreateGroupChat, onCreateChannel }) { - const [isCreating, setIsCreating] = useState(false) - const [chatName, setChatName] = useState('') - const [chatType, setChatType] = useState('direct') - const [members, setMembers] = useState('') - - const handleSubmit = (e) => { - e.preventDefault() - - if (chatType === 'direct') { - onCreateChat(chatName) - } else if (chatType === 'group') { - const membersList = members - .split(',') - .map(m => m.trim()) - .filter(m => m !== '') - .map(name => ({ - id: Date.now() + Math.random(), - name - })) - - onCreateGroupChat(chatName, membersList) - } else if (chatType === 'channel') { - onCreateChannel(chatName) - } - - setChatName('') - setMembers('') - setChatType('direct') - setIsCreating(false) - } - - return ( -
- {isCreating ? ( -
- setChatName(e.target.value)} - placeholder="Chat name" - autoFocus - /> - - - - {chatType === 'group' && ( - setMembers(e.target.value)} - placeholder="Members (comma-separated)" - /> - )} - -
- - -
-
- ) : ( - - )} -
- ) -} - -export default NewChatButton diff --git a/src/components/Stories.jsx b/src/components/Stories.jsx new file mode 100644 index 0000000..a2860a5 --- /dev/null +++ b/src/components/Stories.jsx @@ -0,0 +1,54 @@ +import { useState, useEffect } from 'react' +import '../styles/Stories.css' +import StoriesList from './StoriesList' +import StoryView from './StoryView' +import storiesData from '../data/stories.json' + +function Stories() { + const [stories, setStories] = useState([]) + const [currentStoryIndex, setCurrentStoryIndex] = useState(null) + const [loading, setLoading] = useState(true) + + useEffect(() => { + const fetchStories = async () => { + try { + setStories(storiesData) + } catch (error) { + console.error('Error fetching stories:', error) + } finally { + setLoading(false) + } + } + + fetchStories() + }, []) + + const openStory = (index) => { + setCurrentStoryIndex(index) + } + + const closeStory = () => { + setCurrentStoryIndex(null) + } + + return ( +
+ {loading ? ( +
Loading stories...
+ ) : ( + <> + + {currentStoryIndex !== null && ( + + )} + + )} +
+ ) +} + +export default Stories \ No newline at end of file diff --git a/src/components/StoriesList.jsx b/src/components/StoriesList.jsx new file mode 100644 index 0000000..ac0d9eb --- /dev/null +++ b/src/components/StoriesList.jsx @@ -0,0 +1,24 @@ +import '../styles/StoriesList.css' + +function StoriesList({ stories, onStoryClick }) { + return ( +
+ {stories.map((story, index) => ( +
onStoryClick(index)} + > + {`Story + {story.username} +
+ ))} +
+ ) +} + +export default StoriesList \ No newline at end of file diff --git a/src/components/StoryView.jsx b/src/components/StoryView.jsx new file mode 100644 index 0000000..987dfac --- /dev/null +++ b/src/components/StoryView.jsx @@ -0,0 +1,106 @@ +import { useState, useEffect, useRef } from 'react' +import '../styles/StoryView.css' + +function StoryView({ stories, initialIndex, onClose }) { + const [currentIndex, setCurrentIndex] = useState(initialIndex) + const [progress, setProgress] = useState(0) + const timerRef = useRef(null) + + const currentStory = stories[currentIndex] + + useEffect(() => { + setProgress(0) + + if (timerRef.current) { + clearInterval(timerRef.current) + } + + const intervalTime = 50 // Update progress every 50ms + const totalTime = 5000 // 5 seconds total + const increment = (intervalTime / totalTime) * 100 + + timerRef.current = setInterval(() => { + setProgress(prev => { + const newProgress = prev + increment + if (newProgress >= 100) { + goToNextStory() + return 0 + } + return newProgress + }) + }, intervalTime) + + return () => { + if (timerRef.current) { + clearInterval(timerRef.current) + } + } + }, [currentIndex, stories.length]) + + const goToPrevStory = () => { + if (currentIndex > 0) { + setCurrentIndex(currentIndex - 1) + } else { + onClose() + } + } + + const goToNextStory = () => { + if (currentIndex < stories.length - 1) { + setCurrentIndex(currentIndex + 1) + } else { + onClose() + } + } + + const handleTap = (e) => { + const screenWidth = window.innerWidth + const tapPosition = e.clientX + + if (tapPosition < screenWidth / 2) { + goToPrevStory() + } else { + goToNextStory() + } + } + + return ( +
+
+
+ {stories.map((_, index) => ( +
+
+
+ ))} +
+ +
+
+
+ {currentStory.username} +
+
{currentStory.username}
+
+ +
+ +
+ Story content +
+
+
+ ) +} + +export default StoryView \ No newline at end of file diff --git a/src/data/image0.jpeg b/src/data/image0.jpeg new file mode 100644 index 0000000..90e12a0 Binary files /dev/null and b/src/data/image0.jpeg differ diff --git a/src/data/image2.jpeg b/src/data/image2.jpeg new file mode 100644 index 0000000..df23570 Binary files /dev/null and b/src/data/image2.jpeg differ diff --git a/src/data/image3.jpeg b/src/data/image3.jpeg new file mode 100644 index 0000000..e12155c Binary files /dev/null and b/src/data/image3.jpeg differ diff --git a/src/data/image4.jpeg b/src/data/image4.jpeg new file mode 100644 index 0000000..a3a873f Binary files /dev/null and b/src/data/image4.jpeg differ diff --git a/src/data/image5.jpeg b/src/data/image5.jpeg new file mode 100644 index 0000000..a696b57 Binary files /dev/null and b/src/data/image5.jpeg differ diff --git a/src/data/stories.json b/src/data/stories.json new file mode 100644 index 0000000..cd8482d --- /dev/null +++ b/src/data/stories.json @@ -0,0 +1,32 @@ +[ + { + "id": "1", + "username": "user1", + "userAvatar": "src/data/image0.jpeg", + "imageUrl": "src/data/image0.jpeg" + }, + { + "id": "2", + "username": "user2", + "userAvatar": "src/data/image2.jpeg", + "imageUrl": "src/data/image2.jpeg" + }, + { + "id": "3", + "username": "user3", + "userAvatar": "src/data/image3.jpeg", + "imageUrl": "src/data/image3.jpeg" + }, + { + "id": "4", + "username": "user4", + "userAvatar": "src/data/image4.jpeg", + "imageUrl": "src/data/image4.jpeg" + }, + { + "id": "5", + "username": "user5", + "userAvatar": "src/data/image5.jpeg", + "imageUrl": "src/data/image5.jpeg" + } +] \ No newline at end of file diff --git a/src/styles/Stories.css b/src/styles/Stories.css new file mode 100644 index 0000000..2bc6ae7 --- /dev/null +++ b/src/styles/Stories.css @@ -0,0 +1,12 @@ +.stories-container { + width: 100%; + max-width: 500px; + margin: 0 auto; + padding: 10px; +} + +.loading { + text-align: center; + padding: 20px; + font-size: 16px; +} \ No newline at end of file diff --git a/src/styles/StoriesList.css b/src/styles/StoriesList.css new file mode 100644 index 0000000..c97d8a5 --- /dev/null +++ b/src/styles/StoriesList.css @@ -0,0 +1,36 @@ +.stories-list { + display: flex; + overflow-x: auto; + padding: 10px 0; + gap: 15px; + scrollbar-width: none; +} + +.stories-list::-webkit-scrollbar { + display: none; /* Chrome, Safari, Edge */ +} + +.story-item { + display: flex; + flex-direction: column; + align-items: center; + cursor: pointer; +} + +.story-thumbnail { + width: 60px; + height: 60px; + border-radius: 50%; + object-fit: cover; + border: 2px solid #e1306c; + padding: 2px; +} + +.story-username { + font-size: 12px; + margin-top: 5px; + max-width: 70px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} \ No newline at end of file diff --git a/src/styles/StoryView.css b/src/styles/StoryView.css new file mode 100644 index 0000000..a055b2f --- /dev/null +++ b/src/styles/StoryView.css @@ -0,0 +1,98 @@ +.story-view-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.9); + z-index: 1000; + display: flex; + justify-content: center; + align-items: center; +} + +.story-view { + position: relative; + width: 100%; + height: 100%; + max-width: 500px; + display: flex; + flex-direction: column; +} + +.progress-container { + display: flex; + gap: 2px; + padding: 10px; + position: absolute; + top: 0; + left: 0; + right: 0; + z-index: 10; +} + +.progress-bar-container { + height: 2px; + background-color: rgba(255, 255, 255, 0.3); + flex-grow: 1; + border-radius: 2px; + overflow: hidden; +} + +.progress-bar { + height: 100%; + background-color: white; + transition: width 0.05s linear; +} + +.story-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px 10px; + color: white; + position: absolute; + top: 15px; + left: 0; + right: 0; + z-index: 10; +} + +.user-info { + display: flex; + align-items: center; + gap: 10px; +} + +.user-avatar img { + width: 30px; + height: 30px; + border-radius: 50%; + object-fit: cover; +} + +.username { + font-weight: bold; +} + +.close-button { + background: none; + border: none; + color: white; + font-size: 24px; + cursor: pointer; +} + +.story-content { + flex-grow: 1; + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} + +.story-image { + width: 100%; + height: 100%; + object-fit: contain; +} \ No newline at end of file