Marketplace screenfull-fullscreen-api
Implement fullscreen functionality using screenfull library for cross-browser fullscreen support in ng-events project
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/7spade/screenfull-fullscreen-api" ~/.claude/skills/aiskillstore-marketplace-screenfull-fullscreen-api && rm -rf "$T"
manifest:
skills/7spade/screenfull-fullscreen-api/SKILL.mdsource content
Screenfull Fullscreen API Skill
This skill guides the implementation of fullscreen functionality using the screenfull library in the ng-events construction site management system.
When to Use This Skill
Triggers: "fullscreen", "screenfull", "full screen mode", "toggle fullscreen", "exit fullscreen"
Use this skill when:
- Adding fullscreen toggle buttons
- Creating fullscreen viewers (images, videos, dashboards)
- Implementing presentation modes
- Building immersive UI experiences
- Providing fullscreen for specific components
Installation & Setup
# Already installed in package.json yarn add screenfull@^6.0.2
Core Patterns
1. Basic Fullscreen Toggle
import { Component, inject, signal } from '@angular/core'; import screenfull from 'screenfull'; @Component({ selector: 'app-fullscreen-toggle', standalone: true, template: ` <button (click)="toggleFullscreen()" class="fullscreen-btn"> @if (isFullscreen()) { <i nz-icon nzType="fullscreen-exit" nzTheme="outline"></i> Exit Fullscreen } @else { <i nz-icon nzType="fullscreen" nzTheme="outline"></i> Enter Fullscreen } </button> ` }) export class FullscreenToggleComponent { isFullscreen = signal(false); toggleFullscreen(): void { if (screenfull.isEnabled) { screenfull.toggle(); this.updateFullscreenState(); // Listen for fullscreen changes screenfull.on('change', () => { this.updateFullscreenState(); }); } else { console.warn('Fullscreen API not supported'); } } private updateFullscreenState(): void { this.isFullscreen.set(screenfull.isFullscreen); } }
2. Fullscreen Specific Element
import { Component, ElementRef, ViewChild, signal } from '@angular/core'; import screenfull from 'screenfull'; @Component({ selector: 'app-dashboard-fullscreen', standalone: true, template: ` <div #dashboardContainer class="dashboard-container"> <div class="dashboard-header"> <h2>Construction Progress Dashboard</h2> <button (click)="toggleFullscreen()" class="btn-fullscreen"> @if (isFullscreen()) { <i nz-icon nzType="fullscreen-exit"></i> } @else { <i nz-icon nzType="fullscreen"></i> } </button> </div> <div class="dashboard-content"> <app-progress-charts /> <app-task-summary /> <app-recent-activities /> </div> </div> `, styles: [` .dashboard-container { position: relative; background: white; padding: 20px; } .dashboard-container:-webkit-full-screen { background: #1f1f1f; color: white; } .dashboard-container:fullscreen { background: #1f1f1f; color: white; } .btn-fullscreen { position: absolute; top: 20px; right: 20px; } `] }) export class DashboardFullscreenComponent { @ViewChild('dashboardContainer', { static: true }) container!: ElementRef; isFullscreen = signal(false); toggleFullscreen(): void { if (screenfull.isEnabled) { screenfull.toggle(this.container.nativeElement); screenfull.on('change', () => { this.isFullscreen.set(screenfull.isFullscreen); }); } } }
3. Image Gallery Fullscreen
import { Component, signal } from '@angular/core'; import screenfull from 'screenfull'; import { NzImageModule } from 'ng-zorro-antd/image'; @Component({ selector: 'app-construction-photos', standalone: true, imports: [NzImageModule], template: ` <div class="photo-gallery"> <h3>Construction Site Photos</h3> <div class="photo-grid"> @for (photo of photos(); track photo.id) { <div class="photo-item" (click)="viewFullscreen(photo)"> <img [src]="photo.thumbnailUrl" [alt]="photo.title" /> <div class="photo-overlay"> <i nz-icon nzType="fullscreen" nzTheme="outline"></i> </div> </div> } </div> </div> @if (currentPhoto()) { <div class="fullscreen-viewer" #viewer> <button class="close-btn" (click)="exitFullscreen()"> <i nz-icon nzType="close"></i> </button> <img [src]="currentPhoto()!.fullUrl" [alt]="currentPhoto()!.title" /> <div class="photo-info"> <h4>{{ currentPhoto()!.title }}</h4> <p>{{ currentPhoto()!.description }}</p> <span>{{ currentPhoto()!.date | date }}</span> </div> </div> } `, styles: [` .photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; } .photo-item { position: relative; cursor: pointer; overflow: hidden; border-radius: 4px; } .photo-item img { width: 100%; height: 200px; object-fit: cover; transition: transform 0.3s; } .photo-item:hover img { transform: scale(1.1); } .photo-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s; } .photo-item:hover .photo-overlay { opacity: 1; } .fullscreen-viewer { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.95); display: flex; align-items: center; justify-content: center; z-index: 9999; } .fullscreen-viewer img { max-width: 90%; max-height: 90%; object-fit: contain; } .close-btn { position: absolute; top: 20px; right: 20px; background: rgba(255, 255, 255, 0.2); border: none; color: white; font-size: 24px; cursor: pointer; padding: 10px; border-radius: 4px; } .photo-info { position: absolute; bottom: 20px; left: 20px; color: white; text-align: left; } `] }) export class ConstructionPhotosComponent { photos = signal([ { id: '1', title: 'Foundation Work', description: 'Foundation concrete pouring', thumbnailUrl: 'assets/photos/thumb1.jpg', fullUrl: 'assets/photos/full1.jpg', date: new Date() } // ... more photos ]); currentPhoto = signal<Photo | null>(null); viewFullscreen(photo: Photo): void { this.currentPhoto.set(photo); if (screenfull.isEnabled) { const viewer = document.querySelector('.fullscreen-viewer'); if (viewer) { screenfull.request(viewer as HTMLElement); screenfull.on('change', () => { if (!screenfull.isFullscreen) { this.currentPhoto.set(null); } }); } } } exitFullscreen(): void { if (screenfull.isEnabled && screenfull.isFullscreen) { screenfull.exit(); } this.currentPhoto.set(null); } }
4. Presentation Mode
import { Component, signal, OnInit, OnDestroy } from '@angular/core'; import screenfull from 'screenfull'; @Component({ selector: 'app-presentation-mode', standalone: true, template: ` <div class="presentation-container" [class.presentation-active]="isPresenting()"> <div class="presentation-header"> <h2>{{ currentSlide().title }}</h2> <div class="controls"> <button (click)="previousSlide()" [disabled]="currentSlideIndex() === 0"> <i nz-icon nzType="left"></i> Previous </button> <span>{{ currentSlideIndex() + 1 }} / {{ slides().length }}</span> <button (click)="nextSlide()" [disabled]="currentSlideIndex() === slides().length - 1"> Next <i nz-icon nzType="right"></i> </button> <button (click)="togglePresentation()" class="btn-present"> @if (isPresenting()) { <i nz-icon nzType="fullscreen-exit"></i> Exit } @else { <i nz-icon nzType="fullscreen"></i> Present } </button> </div> </div> <div class="slide-content"> <div [innerHTML]="currentSlide().content"></div> </div> </div> `, styles: [` .presentation-container { background: white; padding: 20px; } .presentation-active { background: #1a1a1a; color: white; padding: 40px; } .presentation-active .slide-content { font-size: 1.5em; } `] }) export class PresentationModeComponent implements OnInit, OnDestroy { slides = signal([ { title: 'Project Overview', content: '<h1>Construction Site Progress</h1><p>Q4 2025 Update</p>' }, { title: 'Milestones Achieved', content: '<ul><li>Foundation Complete</li><li>Structural Work 75%</li></ul>' } // ... more slides ]); currentSlideIndex = signal(0); isPresenting = signal(false); currentSlide = computed(() => this.slides()[this.currentSlideIndex()]); ngOnInit(): void { // Listen for keyboard shortcuts document.addEventListener('keydown', this.handleKeyPress.bind(this)); } ngOnDestroy(): void { document.removeEventListener('keydown', this.handleKeyPress.bind(this)); if (screenfull.isEnabled) { screenfull.off('change'); } } togglePresentation(): void { if (screenfull.isEnabled) { screenfull.toggle(); screenfull.on('change', () => { this.isPresenting.set(screenfull.isFullscreen); }); } } nextSlide(): void { if (this.currentSlideIndex() < this.slides().length - 1) { this.currentSlideIndex.update(i => i + 1); } } previousSlide(): void { if (this.currentSlideIndex() > 0) { this.currentSlideIndex.update(i => i - 1); } } private handleKeyPress(event: KeyboardEvent): void { if (!this.isPresenting()) return; switch (event.key) { case 'ArrowRight': case 'PageDown': this.nextSlide(); break; case 'ArrowLeft': case 'PageUp': this.previousSlide(); break; case 'Escape': if (screenfull.isEnabled && screenfull.isFullscreen) { screenfull.exit(); } break; } } }
API Reference
screenfull Methods
// Check if fullscreen API is supported screenfull.isEnabled // boolean // Toggle fullscreen screenfull.toggle() // Toggle document screenfull.toggle(element) // Toggle specific element // Request fullscreen screenfull.request() // Request for document screenfull.request(element) // Request for specific element // Exit fullscreen screenfull.exit() // Check if currently fullscreen screenfull.isFullscreen // boolean // Get fullscreen element screenfull.element // Element | null // Event listeners screenfull.on('change', () => {}) screenfull.on('error', (event) => {}) screenfull.off('change', handler)
Integration Checklist
When using screenfull:
- Check
before using APIscreenfull.isEnabled - Handle browser compatibility gracefully
- Clean up event listeners on component destroy
- Provide exit fullscreen button
- Test on different browsers (Chrome, Firefox, Safari)
- Handle keyboard shortcuts (Escape to exit)
- Style fullscreen mode appropriately
- Consider mobile browsers (limited support)
Best Practices
DO ✅
- Always check
before usescreenfull.isEnabled - Provide clear UI to exit fullscreen
- Use Escape key to exit fullscreen
- Style fullscreen elements appropriately
- Clean up event listeners
- Handle errors gracefully
DON'T ❌
- Assume fullscreen API is always available
- Force fullscreen without user interaction
- Forget to remove event listeners
- Ignore mobile browser limitations
- Use fullscreen for sensitive actions
Browser Compatibility
| Browser | Support |
|---|---|
| Chrome | ✅ Full support |
| Firefox | ✅ Full support |
| Safari | ✅ Full support (iOS limited) |
| Edge | ✅ Full support |
| iOS Safari | ⚠️ Limited (video only) |
| Android Chrome | ✅ Full support |
References
Version: 1.0.0
Compatible with: screenfull 6.0.x
Last Updated: 2025-12-25