Skip to content

iamwujiabao/24hr-Stories

Repository files navigation

24hr Stories

A client-side Instagram-style Stories feature built with React. Users can upload images that appear as ephemeral stories, auto-expire after 24 hours, and are viewable in a fullscreen player with progress bars and swipe navigation.


Features

  • Add stories — tap the + button to pick any image from your device
  • Auto-resize — images are scaled down to a maximum of 1080×1920px on a canvas before being stored, keeping localStorage usage lean
  • 24-hour expiry — stories are timestamped on creation and automatically pruned when they exceed 24 hours old
  • Fullscreen viewer — tap any story ring to open the viewer
  • Segmented progress bars — one bar per story at the top of the viewer; the active bar fills over 3 seconds
  • Auto-advance — moves to the next story when the timer completes, and closes the viewer after the last one
  • Tap to navigate — tap the left half of the screen to go back, right half to go forward
  • Swipe to navigate — swipe left or right to move between stories; holding pauses the timer
  • Persistent storage — stories survive page refreshes via localStorage
  • Responsive — works on both mobile and desktop

Project Structure

stories/
├── App.jsx                    # Root component — state, story management, layout
├── App.css                    # Global resets, CSS variables, layout, feed skeleton
├── components/
│   ├── StoryViewer.jsx        # Fullscreen overlay with rAF progress loop and gestures
│   ├── StoryViewer.css        # Viewer-specific styles
│   ├── StoryRing.jsx          # Gradient ring thumbnail button
│   ├── AddButton.jsx          # File picker trigger with image processing
│   └── TrayItems.css          # Shared tray button and circle styles
└── utils/
    ├── image-utils.js         # resizeImage(), formatAge()
    └── storage-utils.js       # loadStories(), saveStories(), createStory(), pruneExpiredStories()

Getting Started

Prerequisites

  • Node.js 18+
  • A React project scaffolded with Vite or Create React App

Installation

  1. Copy the stories/ folder into your project's src/ directory.

  2. Install dependencies (the project has none beyond React itself):

npm install
  1. Mount App.jsx as your root component in main.jsx:
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./stories/App.jsx";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <App />
  </StrictMode>
);
  1. Start the dev server:
npm run dev

How It Works

Image Upload & Resize

When a user selects a file, AddButton passes it to resizeImage() in image-utils.js. The function creates an off-screen <canvas>, calculates the scale ratio needed to fit within 1080×1920px without upscaling, draws the image, and returns a base64 JPEG data URL at 85% quality.

Storage & Expiry

Stories are saved to localStorage under the key stories_v1 as a JSON array. Each story object has the shape:

{ id: number, src: string, createdAt: number }

loadStories() filters out any entries where createdAt is older than 24 hours before returning them, so expired stories are never rendered. App.jsx also runs pruneExpiredStories() on a 60-second interval to keep storage clean during long sessions.

Progress Animation

StoryViewer drives progress with requestAnimationFrame rather than setInterval, giving smooth sub-frame accuracy. A startRef stores the timestamp when the current story began. On each frame, elapsed time is divided by the 3000ms duration to produce a 0–1 progress value used to set the active bar's width. Touching the screen sets a pausedRef flag that freezes startRef, effectively pausing the clock without cancelling the loop.


Configuration

Constants you may want to adjust:

Location Constant Default Description
utils/image-utils.js MAX_W 1080 Max image width in px
utils/image-utils.js MAX_H 1920 Max image height in px
components/StoryViewer.jsx STORY_DURATION 3000 Ms each story is displayed
utils/storage-utils.js TTL_MS 86400000 Story lifetime in ms (24h)
utils/storage-utils.js STORAGE_KEY "stories_v1" localStorage key
App.jsx PRUNE_INTERVAL_MS 60000 How often to prune expired stories

Browser Support

Requires support for:

  • localStorage
  • requestAnimationFrame
  • HTMLCanvasElement.toDataURL
  • URL.createObjectURL
  • CSS dvh units (falls back gracefully in older browsers)

All modern browsers (Chrome, Firefox, Safari, Edge) are supported. The touch swipe gestures work on any touch-enabled device.


Limitations

  • Storage quotalocalStorage is limited to ~5MB per origin. High-resolution images encoded as base64 are roughly 33% larger than their original file size. Users adding many large images may hit this limit. A future improvement could compress more aggressively or use the StorageManager API to check available quota before saving.
  • No multi-user support — stories are local to the browser and user. There is no backend or sync layer.
  • Single author — all stories belong to the same local user. Extending to multiple user profiles would require additional data modelling in storage-utils.js.

About

A client-side Instagram-style Stories feature built with React. Users can upload images that appear as ephemeral stories, auto-expire after 24 hours, and are viewable in a fullscreen player with progress bars and swipe navigation.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors