Web Mobile Features TypeScript Samples

Web TypeScript mobile-specific features examples including device info, network status, and vibration

💻 Device Information typescript

🟢 simple ⭐⭐⭐

Get device information including type, OS, browser, screen, and hardware capabilities

⏱️ 20 min 🏷️ typescript, web, mobile features
Prerequisites: Basic TypeScript, Navigator API, Screen API
// Web TypeScript Device Information Examples
// Using Navigator API and Screen API for device detection

// 1. Device Info Manager
class DeviceInfoManager {
  // Get basic device info
  getDeviceInfo(): {
    userAgent: string;
    platform: string;
    vendor: string;
    language: string;
    cookiesEnabled: boolean;
    onLine: boolean;
    hardwareConcurrency: number;
    deviceMemory: number;
    maxTouchPoints: number;
  } {
    const nav = navigator as any;

    return {
      userAgent: navigator.userAgent,
      platform: navigator.platform,
      vendor: navigator.vendor,
      language: navigator.language,
      cookiesEnabled: navigator.cookieEnabled,
      onLine: navigator.onLine,
      hardwareConcurrency: navigator.hardwareConcurrency || 0,
      deviceMemory: nav.deviceMemory || 0,
      maxTouchPoints: navigator.maxTouchPoints || 0
    };
  }

  // Get device type
  getDeviceType(): 'desktop' | 'mobile' | 'tablet' {
    const userAgent = navigator.userAgent.toLowerCase();
    const maxTouchPoints = navigator.maxTouchPoints || 0;

    // Check for mobile
    const isMobile = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);

    // Check for tablet
    const isTablet = /ipad|android(?!.*mobile)|tablet/i.test(userAgent) ||
                     (maxTouchPoints > 0 && /macintosh/i.test(userAgent));

    if (isTablet) return 'tablet';
    if (isMobile) return 'mobile';
    return 'desktop';
  }

  // Get OS information
  getOSInfo(): {
    name: string;
    version: string;
  } {
    const userAgent = navigator.userAgent;
    let name = 'Unknown';
    let version = 'Unknown';

    if (/windows/i.test(userAgent)) {
      name = 'Windows';
      const match = userAgent.match(/Windows NT (\d+\.\d+)/);
      if (match) version = match[1];
    } else if (/macintosh|mac os x/i.test(userAgent)) {
      name = 'macOS';
      const match = userAgent.match(/Mac OS X (\d+[._]\d+)/);
      if (match) version = match[1].replace(/_/g, '.');
    } else if (/android/i.test(userAgent)) {
      name = 'Android';
      const match = userAgent.match(/Android (\d+\.\d+)/);
      if (match) version = match[1];
    } else if (/iphone|ipad|ipod/i.test(userAgent)) {
      name = 'iOS';
      const match = userAgent.match(/OS (\d+_\d+)/);
      if (match) version = match[1].replace(/_/g, '.');
    } else if (/linux/i.test(userAgent)) {
      name = 'Linux';
    }

    return { name, version };
  }

  // Get browser info
  getBrowserInfo(): {
    name: string;
    version: string;
  } {
    const userAgent = navigator.userAgent;
    let name = 'Unknown';
    let version = 'Unknown';

    if (/chrome/i.test(userAgent) && !/edge|opr/i.test(userAgent)) {
      name = 'Chrome';
      const match = userAgent.match(/Chrome\/(\d+\.\d+\.\d+\.\d+)/);
      if (match) version = match[1];
    } else if (/safari/i.test(userAgent) && !/chrome/i.test(userAgent)) {
      name = 'Safari';
      const match = userAgent.match(/Version\/(\d+\.\d+)/);
      if (match) version = match[1];
    } else if (/firefox/i.test(userAgent)) {
      name = 'Firefox';
      const match = userAgent.match(/Firefox\/(\d+\.\d+)/);
      if (match) version = match[1];
    } else if (/edge/i.test(userAgent)) {
      name = 'Edge';
      const match = userAgent.match(/Edge\/(\d+\.\d+)/);
      if (match) version = match[1];
    } else if (/opr/i.test(userAgent)) {
      name = 'Opera';
      const match = userAgent.match(/OPR\/(\d+\.\d+)/);
      if (match) version = match[1];
    }

    return { name, version };
  }

  // Get screen info
  getScreenInfo(): {
    width: number;
    height: number;
    availWidth: number;
    availHeight: number;
    colorDepth: number;
    pixelDepth: number;
    orientation: string;
    devicePixelRatio: number;
  } {
    const screen = window.screen;
    const orientation = (screen.orientation?.type || 'unknown');

    return {
      width: screen.width,
      height: screen.height,
      availWidth: screen.availWidth,
      availHeight: screen.availHeight,
      colorDepth: screen.colorDepth,
      pixelDepth: screen.pixelDepth,
      orientation,
      devicePixelRatio: window.devicePixelRatio
    };
  }

  // Get viewport info
  getViewportInfo(): {
    width: number;
    height: number;
    scrollX: number;
    scrollY: number;
  } {
    return {
      width: window.innerWidth,
      height: window.innerHeight,
      scrollX: window.scrollX,
      scrollY: window.scrollY
    };
  }

  // Check if touch device
  isTouchDevice(): boolean {
    return 'ontouchstart' in window ||
           navigator.maxTouchPoints > 0 ||
           (navigator as any).msMaxTouchPoints > 0;
  }

  // Check if retina display
  isRetinaDisplay(): boolean {
    return window.devicePixelRatio > 1;
  }

  // Get complete device report
  getCompleteReport(): {
    device: any;
    os: any;
    browser: any;
    screen: any;
    viewport: any;
    capabilities: any;
  } {
    return {
      device: {
        type: this.getDeviceType(),
        info: this.getDeviceInfo()
      },
      os: this.getOSInfo(),
      browser: this.getBrowserInfo(),
      screen: this.getScreenInfo(),
      viewport: this.getViewportInfo(),
      capabilities: {
        touch: this.isTouchDevice(),
        retina: this.isRetinaDisplay(),
        webGL: this.checkWebGL(),
        webWorker: 'Worker' in window,
        serviceWorker: 'serviceWorker' in navigator,
        localStorage: this.checkLocalStorage(),
        sessionStorage: this.checkSessionStorage()
      }
    };
  }

  private checkWebGL(): boolean {
    try {
      const canvas = document.createElement('canvas');
      return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
    } catch {
      return false;
    }
  }

  private checkLocalStorage(): boolean {
    try {
      localStorage.setItem('test', 'test');
      localStorage.removeItem('test');
      return true;
    } catch {
      return false;
    }
  }

  private checkSessionStorage(): boolean {
    try {
      sessionStorage.setItem('test', 'test');
      sessionStorage.removeItem('test');
      return true;
    } catch {
      return false;
    }
  }
}

// 2. Battery Manager
class BatteryManager {
  private battery: any = null;

  // Initialize battery API
  async initialize(): Promise<void> {
    if ('getBattery' in navigator) {
      this.battery = await (navigator as any).getBattery();
    }
  }

  // Check if battery API is supported
  isSupported(): boolean {
    return 'getBattery' in navigator;
  }

  // Get battery info
  getBatteryInfo(): {
    charging: boolean;
    level: number;
    chargingTime: number;
    dischargingTime: number;
  } | null {
    if (!this.battery) {
      return null;
    }

    return {
      charging: this.battery.charging,
      level: this.battery.level,
      chargingTime: this.battery.chargingTime,
      dischargingTime: this.battery.dischargingTime
    };
  }

  // Add battery change listener
  addChangeListener(callback: (info: any) => void): void {
    if (this.battery) {
      this.battery.addEventListener('levelchange', () => callback(this.getBatteryInfo()));
      this.battery.addEventListener('chargingchange', () => callback(this.getBatteryInfo()));
      this.battery.addEventListener('chargingtimechange', () => callback(this.getBatteryInfo()));
      this.battery.addEventListener('dischargingtimechange', () => callback(this.getBatteryInfo()));
    }
  }
}

// 3. Memory Manager
class MemoryManager {
  // Get memory info (Chrome only)
  getMemoryInfo(): {
    jsHeapSizeLimit: number;
    totalJSHeapSize: number;
    usedJSHeapSize: number;
  } | null {
    const performance = (window as any).performance;
    if (performance && performance.memory) {
      return {
        jsHeapSizeLimit: performance.memory.jsHeapSizeLimit,
        totalJSHeapSize: performance.memory.totalJSHeapSize,
        usedJSHeapSize: performance.memory.usedJSHeapSize
      };
    }
    return null;
  }

  // Get memory usage percentage
  getMemoryUsage(): number | null {
    const memory = this.getMemoryInfo();
    if (!memory) return null;

    return (memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100;
  }

  // Format bytes to readable string
  formatBytes(bytes: number): string {
    const mb = bytes / (1024 * 1024);
    return mb.toFixed(2) + ' MB';
  }
}

// 4. Connection Manager
class ConnectionManager {
  // Get connection info
  getConnectionInfo(): {
    effectiveType: string;
    downlink: number;
    rtt: number;
    saveData: boolean;
  } | null {
    const connection = (navigator as any).connection || (navigator as any).mozConnection || (navigator as any).webkitConnection;

    if (!connection) {
      return null;
    }

    return {
      effectiveType: connection.effectiveType || 'unknown',
      downlink: connection.downlink || 0,
      rtt: connection.rtt || 0,
      saveData: connection.saveData || false
    };
  }

  // Check if slow connection
  isSlowConnection(): boolean {
    const info = this.getConnectionInfo();
    if (!info) return false;

    return info.effectiveType === 'slow-2g' || info.effectiveType === '2g';
  }

  // Check if fast connection
  isFastConnection(): boolean {
    const info = this.getConnectionInfo();
    if (!info) return false;

    return info.effectiveType === '4g';
  }
}

// 5. Orientation Manager
class OrientationManager {
  // Get current orientation
  getOrientation(): 'portrait' | 'landscape' {
    return window.innerHeight > window.innerWidth ? 'portrait' : 'landscape';
  }

  // Lock orientation (experimental)
  async lockOrientation(orientation: 'portrait' | 'landscape'): Promise<boolean> {
    try {
      if ((screen.orientation as any).lock) {
        await screen.orientation.lock(orientation);
        return true;
      }
      return false;
    } catch {
      return false;
    }
  }

  // Unlock orientation
  unlockOrientation(): void {
    if ((screen.orientation as any).unlock) {
      screen.orientation.unlock();
    }
  }

  // Add orientation change listener
  addChangeListener(callback: (orientation: 'portrait' | 'landscape') => void): void {
    window.addEventListener('orientationchange', () => {
      callback(this.getOrientation());
    });

    window.addEventListener('resize', () => {
      callback(this.getOrientation());
    });
  }
}

// 6. Device Capability Detector
class DeviceCapabilityDetector {
  // Check for camera support
  async hasCamera(): Promise<boolean> {
    try {
      const devices = await navigator.mediaDevices.enumerateDevices();
      return devices.some(device => device.kind === 'videoinput');
    } catch {
      return false;
    }
  }

  // Check for microphone support
  async hasMicrophone(): Promise<boolean> {
    try {
      const devices = await navigator.mediaDevices.enumerateDevices();
      return devices.some(device => device.kind === 'audioinput');
    } catch {
      return false;
    }
  }

  // Check for geolocation support
  hasGeolocation(): boolean {
    return 'geolocation' in navigator;
  }

  // Check for vibration support
  hasVibration(): boolean {
    return 'vibrate' in navigator;
  }

  // Check for Bluetooth support
  hasBluetooth(): boolean {
    return 'bluetooth' in navigator;
  }

  // Check for USB support
  hasUSB(): boolean {
    return 'usb' in navigator;
  }

  // Get all capabilities
  async getAllCapabilities(): Promise<{
    camera: boolean;
    microphone: boolean;
    geolocation: boolean;
    vibration: boolean;
    bluetooth: boolean;
    usb: boolean;
    touch: boolean;
    webGL: boolean;
  }> {
    return {
      camera: await this.hasCamera(),
      microphone: await this.hasMicrophone(),
      geolocation: this.hasGeolocation(),
      vibration: this.hasVibration(),
      bluetooth: this.hasBluetooth(),
      usb: this.hasUSB(),
      touch: 'ontouchstart' in window,
      webGL: this.checkWebGL()
    };
  }

  private checkWebGL(): boolean {
    try {
      const canvas = document.createElement('canvas');
      return !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
    } catch {
      return false;
    }
  }
}

// Usage Examples
async function demonstrateDeviceInfo() {
  console.log('=== Web TypeScript Device Information Examples ===\n');

  const deviceManager = new DeviceInfoManager();
  const batteryManager = new BatteryManager();
  const memoryManager = new MemoryManager();
  const connectionManager = new ConnectionManager();
  const orientationManager = new OrientationManager();
  const capabilityDetector = new DeviceCapabilityDetector();

  // 1. Basic device info
  console.log('--- 1. Device Info ---');
  const deviceInfo = deviceManager.getDeviceInfo();
  console.log('User Agent:', deviceInfo.userAgent);
  console.log('Platform:', deviceInfo.platform);
  console.log('Device Type:', deviceManager.getDeviceType());

  // 2. OS and browser
  console.log('\n--- 2. OS & Browser ---');
  const osInfo = deviceManager.getOSInfo();
  console.log('OS:', `${osInfo.name} ${osInfo.version}`);

  const browserInfo = deviceManager.getBrowserInfo();
  console.log('Browser:', `${browserInfo.name} ${browserInfo.version}`);

  // 3. Screen info
  console.log('\n--- 3. Screen Info ---');
  const screenInfo = deviceManager.getScreenInfo();
  console.log(`Screen: ${screenInfo.width}x${screenInfo.height}`);
  console.log(`Available: ${screenInfo.availWidth}x${screenInfo.availHeight}`);
  console.log(`Device Pixel Ratio: ${screenInfo.devicePixelRatio}`);

  // 4. Capabilities
  console.log('\n--- 4. Capabilities ---');
  console.log('Touch Device:', deviceManager.isTouchDevice());
  console.log('Retina Display:', deviceManager.isRetinaDisplay());

  // 5. Battery
  console.log('\n--- 5. Battery ---');
  await batteryManager.initialize();
  const batteryInfo = batteryManager.getBatteryInfo();
  if (batteryInfo) {
    console.log(`Battery Level: ${Math.round(batteryInfo.level * 100)}%`);
    console.log(`Charging: ${batteryInfo.charging}`);
  } else {
    console.log('Battery API not supported');
  }

  // 6. Memory
  console.log('\n--- 6. Memory ---');
  const memoryInfo = memoryManager.getMemoryInfo();
  if (memoryInfo) {
    console.log(`Used Memory: ${memoryManager.formatBytes(memoryInfo.usedJSHeapSize)}`);
    console.log(`Memory Limit: ${memoryManager.formatBytes(memoryInfo.jsHeapSizeLimit)}`);
    console.log(`Memory Usage: ${memoryManager.getMemoryUsage()?.toFixed(2)}%`);
  }

  // 7. Connection
  console.log('\n--- 7. Connection ---');
  const connInfo = connectionManager.getConnectionInfo();
  if (connInfo) {
    console.log(`Connection Type: ${connInfo.effectiveType}`);
    console.log(`Downlink: ${connInfo.downlink} Mbps`);
    console.log(`RTT: ${connInfo.rtt} ms`);
  }

  // 8. Capabilities detection
  console.log('\n--- 8. Device Capabilities ---');
  const capabilities = await capabilityDetector.getAllCapabilities();
  console.log('Camera:', capabilities.camera);
  console.log('Microphone:', capabilities.microphone);
  console.log('Geolocation:', capabilities.geolocation);
  console.log('Vibration:', capabilities.vibration);
  console.log('Bluetooth:', capabilities.bluetooth);

  // 9. Complete report
  console.log('\n--- 9. Complete Report ---');
  const report = deviceManager.getCompleteReport();
  console.log(JSON.stringify(report, null, 2));

  console.log('\n=== All Device Information Examples Completed ===');
}

// Export functions
export { DeviceInfoManager, BatteryManager, MemoryManager, ConnectionManager, OrientationManager, DeviceCapabilityDetector };
export { demonstrateDeviceInfo };

💻 Network Status typescript

🟢 simple ⭐⭐⭐

Monitor network connectivity status with online/offline events and connection quality

⏱️ 20 min 🏷️ typescript, web, mobile features
Prerequisites: Basic TypeScript, Network API, Navigator API
// Web TypeScript Network Status Examples
// Monitoring network connectivity and connection quality

// 1. Network Status Monitor
class NetworkStatusMonitor {
  private isOnline: boolean = navigator.onLine;
  private listeners: Array<(online: boolean) => void> = [];

  constructor() {
    this.initialize();
  }

  // Initialize event listeners
  private initialize(): void {
    window.addEventListener('online', this.handleOnline);
    window.addEventListener('offline', this.handleOffline);
  }

  // Handle online event
  private handleOnline = (): void => {
    this.isOnline = true;
    this.notifyListeners(true);
    console.log('Network status: Online');
  };

  // Handle offline event
  private handleOffline = (): void => {
    this.isOnline = false;
    this.notifyListeners(false);
    console.log('Network status: Offline');
  };

  // Notify all listeners
  private notifyListeners(online: boolean): void {
    this.listeners.forEach(listener => {
      try {
        listener(online);
      } catch (error) {
        console.error('Error in network status listener:', error);
      }
    });
  }

  // Get current status
  isCurrentlyOnline(): boolean {
    return this.isOnline;
  }

  // Add status change listener
  addListener(listener: (online: boolean) => void): void {
    this.listeners.push(listener);
  }

  // Remove status change listener
  removeListener(listener: (online: boolean) => void): void {
    const index = this.listeners.indexOf(listener);
    if (index > -1) {
      this.listeners.splice(index, 1);
    }
  }

  // Cleanup
  destroy(): void {
    window.removeEventListener('online', this.handleOnline);
    window.removeEventListener('offline', this.handleOffline);
    this.listeners = [];
  }
}

// 2. Connection Quality Monitor
class ConnectionQualityMonitor {
  private connection: any = null;
  private listeners: Array<(info: any) => void> = [];

  constructor() {
    this.initialize();
  }

  // Initialize connection monitoring
  private initialize(): void {
    this.connection = (navigator as any).connection ||
                     (navigator as any).mozConnection ||
                     (navigator as any).webkitConnection;

    if (this.connection) {
      this.connection.addEventListener('change', this.handleChange);
    }
  }

  // Handle connection change
  private handleChange = (): void => {
    const info = this.getConnectionInfo();
    this.notifyListeners(info);
    console.log('Connection quality changed:', info);
  };

  // Notify all listeners
  private notifyListeners(info: any): void {
    this.listeners.forEach(listener => {
      try {
        listener(info);
      } catch (error) {
        console.error('Error in connection quality listener:', error);
      }
    });
  }

  // Get connection info
  getConnectionInfo(): {
    effectiveType: string;
    downlink: number;
    rtt: number;
    saveData: boolean;
  } | null {
    if (!this.connection) {
      return null;
    }

    return {
      effectiveType: this.connection.effectiveType || 'unknown',
      downlink: this.connection.downlink || 0,
      rtt: this.connection.rtt || 0,
      saveData: this.connection.saveData || false
    };
  }

  // Check if slow connection
  isSlowConnection(): boolean {
    const info = this.getConnectionInfo();
    if (!info) return false;

    const slowTypes = ['slow-2g', '2g', '3g'];
    return slowTypes.includes(info.effectiveType);
  }

  // Check if fast connection
  isFastConnection(): boolean {
    const info = this.getConnectionInfo();
    if (!info) return false;

    return info.effectiveType === '4g';
  }

  // Get connection quality description
  getQualityDescription(): string {
    const info = this.getConnectionInfo();
    if (!info) return 'Unknown';

    const descriptions: Record<string, string> = {
      'slow-2g': 'Very Slow (2G)',
      '2g': 'Slow (2G)',
      '3g': 'Moderate (3G)',
      '4g': 'Fast (4G)'
    };

    return descriptions[info.effectiveType] || 'Unknown';
  }

  // Add change listener
  addChangeListener(listener: (info: any) => void): void {
    this.listeners.push(listener);
  }

  // Remove change listener
  removeChangeListener(listener: (info: any) => void): void {
    const index = this.listeners.indexOf(listener);
    if (index > -1) {
      this.listeners.splice(index, 1);
    }
  }

  // Cleanup
  destroy(): void {
    if (this.connection) {
      this.connection.removeEventListener('change', this.handleChange);
    }
    this.listeners = [];
  }
}

// 3. Network Speed Tester
class NetworkSpeedTester {
  private testUrl: string;

  constructor(testUrl: string = 'https://www.google.com/favicon.ico') {
    this.testUrl = testUrl;
  }

  // Test download speed
  async testDownloadSpeed(): Promise<{
    speedKbps: number;
    latency: number;
  }> {
    const startTime = performance.now();
    let downloadSize = 0;

    try {
      const response = await fetch(this.testUrl + '?t=' + Date.now());
      const blob = await response.blob();
      downloadSize = blob.size;

      const endTime = performance.now();
      const duration = (endTime - startTime) / 1000; // Convert to seconds
      const speedKbps = ((downloadSize * 8) / duration) / 1000; // Convert to kbps
      const latency = endTime - startTime;

      return { speedKbps, latency };
    } catch (error) {
      console.error('Speed test failed:', error);
      return { speedKbps: 0, latency: 0 };
    }
  }

  // Test latency (ping)
  async testLatency(): Promise<number> {
    const start = performance.now();

    try {
      await fetch(this.testUrl + '?t=' + Date.now(), { method: 'HEAD' });
      return performance.now() - start;
    } catch {
      return -1;
    }
  }

  // Test multiple times and get average
  async testAverage(iterations: number = 3): Promise<{
    avgSpeedKbps: number;
    avgLatency: number;
  }> {
    const speeds: number[] = [];
    const latencies: number[] = [];

    for (let i = 0; i < iterations; i++) {
      const result = await this.testDownloadSpeed();
      speeds.push(result.speedKbps);
      latencies.push(result.latency);

      // Wait a bit between tests
      await new Promise(resolve => setTimeout(resolve, 500));
    }

    const avgSpeedKbps = speeds.reduce((a, b) => a + b, 0) / speeds.length;
    const avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length;

    return { avgSpeedKbps, avgLatency };
  }
}

// 4. Offline Manager
class OfflineManager {
  private networkMonitor: NetworkStatusMonitor;
  private offlineQueue: Array<{ url: string; options: RequestInit }> = [];
  private isOfflineMode: boolean = false;

  constructor() {
    this.networkMonitor = new NetworkStatusMonitor();
    this.initialize();
  }

  // Initialize offline manager
  private initialize(): void {
    this.networkMonitor.addListener((online) => {
      this.isOfflineMode = !online;

      if (online) {
        this.syncOfflineRequests();
      }
    });
  }

  // Add request to offline queue
  queueRequest(url: string, options: RequestInit = {}): void {
    this.offlineQueue.push({ url, options });
    console.log(`Request queued: ${url}`);
  }

  // Sync offline requests when back online
  private async syncOfflineRequests(): Promise<void> {
    if (this.offlineQueue.length === 0) {
      return;
    }

    console.log(`Syncing ${this.offlineQueue.length} offline requests...`);

    const queue = [...this.offlineQueue];
    this.offlineQueue = [];

    for (const request of queue) {
      try {
        await fetch(request.url, request.options);
        console.log(`Synced: ${request.url}`);
      } catch (error) {
        console.error(`Failed to sync ${request.url}:`, error);
        // Re-queue failed requests
        this.queueRequest(request.url, request.options);
      }
    }
  }

  // Check if currently in offline mode
  isOffline(): boolean {
    return this.isOfflineMode;
  }

  // Get offline queue size
  getQueueSize(): number {
    return this.offlineQueue.length;
  }

  // Clear offline queue
  clearQueue(): void {
    this.offlineQueue = [];
  }
}

// 5. Network Health Checker
class NetworkHealthChecker {
  private connectionMonitor: ConnectionQualityMonitor;
  private speedTester: NetworkSpeedTester;

  constructor() {
    this.connectionMonitor = new ConnectionQualityMonitor();
    this.speedTester = new NetworkSpeedTester();
  }

  // Get comprehensive health report
  async getHealthReport(): Promise<{
    online: boolean;
    connectionInfo: any;
    speedTest: {
      speedKbps: number;
      latency: number;
    } | null;
    health: 'excellent' | 'good' | 'fair' | 'poor';
  }> {
    const online = navigator.onLine;
    const connectionInfo = this.connectionMonitor.getConnectionInfo();
    let speedTest = null;
    let health: 'excellent' | 'good' | 'fair' | 'poor' = 'poor';

    if (online) {
      speedTest = await this.speedTester.testDownloadSpeed();

      // Determine health based on speed and latency
      if (speedTest.speedKbps > 5000 && speedTest.latency < 50) {
        health = 'excellent';
      } else if (speedTest.speedKbps > 1000 && speedTest.latency < 100) {
        health = 'good';
      } else if (speedTest.speedKbps > 500 && speedTest.latency < 200) {
        health = 'fair';
      } else {
        health = 'poor';
      }
    }

    return {
      online,
      connectionInfo,
      speedTest,
      health
    };
  }

  // Simple health check (quick)
  quickHealthCheck(): {
    online: boolean;
    connectionType: string;
    estimatedQuality: 'good' | 'fair' | 'poor';
  } {
    const online = navigator.onLine;
    const connInfo = this.connectionMonitor.getConnectionInfo();

    let estimatedQuality: 'good' | 'fair' | 'poor' = 'poor';

    if (connInfo) {
      if (connInfo.effectiveType === '4g' && connInfo.downlink >= 10) {
        estimatedQuality = 'good';
      } else if (connInfo.effectiveType === '3g' || connInfo.effectiveType === '4g') {
        estimatedQuality = 'fair';
      }
    }

    return {
      online,
      connectionType: connInfo?.effectiveType || 'unknown',
      estimatedQuality
    };
  }
}

// 6. Network Usage Tracker
class NetworkUsageTracker {
  private requests: Map<string, number> = new Map();

  // Track request
  trackRequest(url: string, size: number): void {
    const current = this.requests.get(url) || 0;
    this.requests.set(url, current + size);
  }

  // Get total usage
  getTotalUsage(): number {
    let total = 0;
    for (const size of this.requests.values()) {
      total += size;
    }
    return total;
  }

  // Get usage by URL pattern
  getUsageByPattern(pattern: RegExp): number {
    let total = 0;
    for (const [url, size] of this.requests) {
      if (pattern.test(url)) {
        total += size;
      }
    }
    return total;
  }

  // Get top consumers
  getTopConsumers(limit: number = 10): Array<{ url: string; size: number }> {
    const consumers = Array.from(this.requests.entries())
      .map(([url, size]) => ({ url, size }))
      .sort((a, b) => b.size - a.size)
      .slice(0, limit);

    return consumers;
  }

  // Clear tracking data
  clear(): void {
    this.requests.clear();
  }

  // Get usage in readable format
  getUsageReport(): {
    totalBytes: number;
    totalMB: number;
    topConsumers: Array<{ url: string; size: number; sizeKB: number }>;
  } {
    const totalBytes = this.getTotalUsage();
    const topConsumers = this.getTopConsumers(10);

    return {
      totalBytes,
      totalMB: totalBytes / (1024 * 1024),
      topConsumers: topConsumers.map(c => ({
        ...c,
        sizeKB: c.size / 1024
      }))
    };
  }
}

// Usage Examples
async function demonstrateNetworkStatus() {
  console.log('=== Web TypeScript Network Status Examples ===\n');

  const networkMonitor = new NetworkStatusMonitor();
  const connectionMonitor = new ConnectionQualityMonitor();
  const speedTester = new NetworkSpeedTester();
  const offlineManager = new OfflineManager();
  const healthChecker = new NetworkHealthChecker();

  // 1. Network status
  console.log('--- 1. Network Status ---');
  console.log('Currently Online:', networkMonitor.isCurrentlyOnline());

  // Add listener
  networkMonitor.addListener((online) => {
    console.log(`Status changed: ${online ? 'Online' : 'Offline'}`);
  });

  // 2. Connection quality
  console.log('\n--- 2. Connection Quality ---');
  const connInfo = connectionMonitor.getConnectionInfo();
  if (connInfo) {
    console.log('Effective Type:', connInfo.effectiveType);
    console.log('Downlink:', connInfo.downlink, 'Mbps');
    console.log('RTT:', connInfo.rtt, 'ms');
    console.log('Quality Description:', connectionMonitor.getQualityDescription());
    console.log('Slow Connection:', connectionMonitor.isSlowConnection());
    console.log('Fast Connection:', connectionMonitor.isFastConnection());
  }

  // 3. Speed test
  console.log('\n--- 3. Speed Test ---');
  const speedResult = await speedTester.testDownloadSpeed();
  console.log(`Speed: ${speedResult.speedKbps.toFixed(2)} kbps`);
  console.log(`Latency: ${speedResult.latency.toFixed(2)} ms`);

  // 4. Average speed test
  console.log('\n--- 4. Average Speed Test ---');
  const avgResult = await speedTester.testAverage(2);
  console.log(`Average Speed: ${avgResult.avgSpeedKbps.toFixed(2)} kbps`);
  console.log(`Average Latency: ${avgResult.avgLatency.toFixed(2)} ms`);

  // 5. Health check
  console.log('\n--- 5. Health Check ---');
  const healthReport = await healthChecker.getHealthReport();
  console.log('Health:', healthReport.health);
  console.log('Online:', healthReport.online);

  // 6. Quick health check
  console.log('\n--- 6. Quick Health Check ---');
  const quickHealth = healthChecker.quickHealthCheck();
  console.log('Quick Health:', quickHealth);

  // 7. Offline manager
  console.log('\n--- 7. Offline Manager ---');
  console.log('Is Offline:', offlineManager.isOffline());
  console.log('Queue Size:', offlineManager.getQueueSize());

  console.log('\n=== All Network Status Examples Completed ===');
}

// Export functions
export { NetworkStatusMonitor, ConnectionQualityMonitor, NetworkSpeedTester, OfflineManager, NetworkHealthChecker, NetworkUsageTracker };
export { demonstrateNetworkStatus };

💻 Vibration API typescript

🟢 simple ⭐⭐

Control device vibration for haptic feedback with patterns and timing

⏱️ 15 min 🏷️ typescript, web, mobile features
Prerequisites: Basic TypeScript, Vibration API
// Web TypeScript Vibration API Examples
// Using Vibration API for haptic feedback

// 1. Vibration Manager
class VibrationManager {
  // Check if vibration is supported
  isSupported(): boolean {
    return 'vibrate' in navigator;
  }

  // Vibrate for specified duration
  vibrate(duration: number): boolean {
    if (!this.isSupported()) {
      console.warn('Vibration API not supported');
      return false;
    }

    return navigator.vibrate(duration);
  }

  // Vibrate with pattern
  vibratePattern(pattern: number[]): boolean {
    if (!this.isSupported()) {
      console.warn('Vibration API not supported');
      return false;
    }

    return navigator.vibrate(pattern);
  }

  // Stop vibration
  stop(): boolean {
    if (!this.isSupported()) {
      return false;
    }

    return navigator.vibrate(0);
  }
}

// 2. Haptic Feedback Patterns
class HapticFeedbackPatterns {
  private vibrate: VibrationManager;

  constructor() {
    this.vibrate = new VibrationManager();
  }

  // Short tap feedback
  tap(): void {
    this.vibrate.vibrate(10);
  }

  // Medium tap feedback
  mediumTap(): void {
    this.vibrate.vibrate(25);
  }

  // Strong tap feedback
  strongTap(): void {
    this.vibrate.vibrate(50);
  }

  // Success feedback
  success(): void {
    this.vibrate.vibratePattern([50, 50, 50]);
  }

  // Error feedback
  error(): void {
    this.vibrate.vibratePattern([100, 50, 100, 50, 100]);
  }

  // Warning feedback
  warning(): void {
    this.vibrate.vibratePattern([50, 100, 50]);
  }

  // Notification feedback
  notification(): void {
    this.vibrate.vibratePattern([100, 50, 100]);
  }

  // Confirmation feedback (ask)
  confirmation(): void {
    this.vibrate.vibratePattern([30, 50, 30]);
  }

  // Heartbeat pattern
  heartbeat(): void {
    this.vibrate.vibratePattern([50, 50, 50, 200, 50, 50, 50, 200]);
  }

  // SOS pattern
  sos(): void {
    this.vibrate.vibratePattern([
      100, 50, 100, 50, 100, 200,
      200, 50, 200, 50, 200, 200,
      100, 50, 100, 50, 100, 200
    ]);
  }

  // Ring pattern
  ring(repeat: boolean = false): void {
    const pattern = [1000, 500];

    if (repeat && this.vibrate.isSupported()) {
      // Note: Continuous vibration needs to be handled carefully
      this.vibrate.vibratePattern(pattern);
    } else {
      this.vibrate.vibratePattern(pattern);
    }
  }

  // Typing feedback
  typing(): void {
    this.vibrate.vibrate(15);
  }

  // Delete feedback
  delete(): void {
    this.vibrate.vibratePattern([50, 30, 50]);
  }

  // Scroll boundary feedback
  scrollBoundary(): void {
    this.vibrate.vibrate(25);
  }

  // Snap feedback
  snap(): void {
    this.vibrate.vibratePattern([20, 30, 40]);
  }

  // Brush feedback
  brush(): void {
    this.vibrate.vibratePattern([10, 20, 10, 20, 10]);
  }
}

// 3. Vibration Sequencer
class VibrationSequencer {
  private vibrate: VibrationManager;
  private sequences: Map<string, number[]> = new Map();

  constructor() {
    this.vibrate = new VibrationManager();
    this.initializeDefaultSequences();
  }

  // Initialize default sequences
  private initializeDefaultSequences(): void {
    this.sequences.set('dot', [30]);
    this.sequences.set('dash', [100]);
    this.sequences.set('dot-dot-dot', [30, 50, 30, 50, 30]);
    this.sequences.set('dash-dash-dash', [100, 50, 100, 50, 100]);
    this.sequences.set('dot-dash', [30, 50, 100]);
    this.sequences.set('dash-dot', [100, 50, 30]);
  }

  // Play sequence by name
  play(name: string): boolean {
    const pattern = this.sequences.get(name);

    if (pattern) {
      return this.vibrate.vibratePattern(pattern);
    }

    return false;
  }

  // Register custom sequence
  registerSequence(name: string, pattern: number[]): void {
    this.sequences.set(name, pattern);
  }

  // Play sequence with delay
  playDelayed(name: string, delay: number): void {
    setTimeout(() => {
      this.play(name);
    }, delay);
  }

  // Play sequences in sequence
  playSequence(names: string[], delay: number = 500): void {
    names.forEach((name, index) => {
      this.playDelayed(name, index * delay);
    });
  }

  // Create rhythm pattern
  createRhythm(beats: string): number[] {
    const pattern: number[] = [];

    for (const char of beats) {
      if (char === '.') {
        pattern.push(30, 50);
      } else if (char === '-') {
        pattern.push(100, 50);
      } else if (char === ' ') {
        pattern.push(0, 200);
      }
    }

    // Remove trailing pause
    if (pattern.length > 0 && pattern[pattern.length - 1] === 0) {
      pattern.pop();
      pattern.pop();
    }

    return pattern;
  }

  // Play rhythm
  playRhythm(beats: string): boolean {
    const pattern = this.createRhythm(beats);
    return this.vibrate.vibratePattern(pattern);
  }
}

// 4. Notification Vibrations
class NotificationVibrations {
  private haptic: HapticFeedbackPatterns;

  constructor() {
    this.haptic = new HapticFeedbackPatterns();
  }

  // New message vibration
  newMessage(): void {
    this.haptic.notification();
  }

  // New email vibration
  newEmail(): void {
    this.haptic.vibratePattern([50, 100, 50, 100, 100, 100, 50, 200]);
  }

  // Calendar reminder
  calendarReminder(): void {
    this.haptic.vibratePattern([100, 50, 100, 50, 100, 200, 200]);
  }

  // Alarm vibration
  alarm(): void {
    // Repeating pattern - would need interval in real implementation
    this.haptic.vibratePattern([500, 200, 500, 200]);
  }

  // Phone call
  phoneCall(): void {
    this.haptic.ring(true);
  }

  // Missed call
  missedCall(): void {
    this.haptic.vibratePattern([100, 100, 100, 100, 100]);
  }
}

// 5. Game Feedback Vibrations
class GameFeedbackVibrations {
  private haptic: HapticFeedbackPatterns;

  constructor() {
    this.haptic = new HapticFeedbackPatterns();
  }

  // Button press
  buttonPress(): void {
    this.haptic.tap();
  }

  // Button hold
  buttonHold(): void {
    this.haptic.vibratePattern([20, 10, 20]);
  }

  // Hit feedback
  hit(light: boolean = false): void {
    if (light) {
      this.haptic.tap();
    } else {
      this.haptic.mediumTap();
    }
  }

  // Critical hit
  criticalHit(): void {
    this.haptic.vibratePattern([50, 30, 100]);
  }

  // Miss feedback
  miss(): void {
    this.haptic.vibrate(15);
  }

  // Explosion
  explosion(): void {
    this.haptic.vibratePattern([200, 50, 100, 50, 50]);
  }

  // Power-up
  powerUp(): void {
    this.haptic.vibratePattern([30, 30, 50, 30, 70, 30, 100, 30, 150]);
  }

  // Level complete
  levelComplete(): void {
    this.haptic.success();
  }

  // Game over
  gameOver(): void {
    this.haptic.error();
  }

  // Achievement unlocked
  achievement(): void {
    this.haptic.vibratePattern([
      50, 50, 50, 50, 50, 50,
      100, 50, 100, 50, 100, 50,
      200
    ]);
  }
}

// 6. Accessibility Vibrations
class AccessibilityVibrations {
  private haptic: HapticFeedbackPatterns;

  constructor() {
    this.haptic = new HapticFeedbackPatterns();
  }

  // Tick sound (for clock, timer)
  tick(): void {
    this.haptic.vibrate(10);
  }

  // Tock sound
  tock(): void {
    this.haptic.vibrate(15);
  }

  // Hour chime
  hourChime(): void {
    this.haptic.vibratePattern([100, 200, 100]);
  }

  // Timer complete
  timerComplete(): void {
    this.haptic.notification();
  }

  // Boundary warning
  boundaryWarning(): void {
    this.haptic.warning();
  }

  // Focus reminder
  focusReminder(): void {
    this.haptic.vibratePattern([30, 100, 30]);
  }

  // Step counter (each step)
  step(): void {
    this.haptic.vibrate(20);
  }

  // Goal reached
  goalReached(): void {
    this.haptic.success();
  }

  // Distance warning (getting closer)
  proximityAlert(level: 1 | 2 | 3): void {
    switch (level) {
      case 1:
        this.haptic.vibrate(20);
        break;
      case 2:
        this.haptic.vibratePattern([30, 100, 30]);
        break;
      case 3:
        this.haptic.vibratePattern([50, 50, 50, 50]);
        break;
    }
  }
}

// 7. Vibration Composer
class VibrationComposer {
  private vibrate: VibrationManager;

  constructor() {
    this.vibrate = new VibrationManager();
  }

  // Compose custom vibration from notes
  compose(notes: Array<{ duration: number; pause?: number }>): void {
    const pattern: number[] = [];

    for (let i = 0; i < notes.length; i++) {
      const note = notes[i];
      pattern.push(note.duration);

      if (i < notes.length - 1) {
        pattern.push(note.pause || 50);
      }
    }

    this.vibrate.vibratePattern(pattern);
  }

  // Compose melody
  composeMelody(notes: number[], tempo: number = 200): void {
    const pattern: number[] = [];

    for (let i = 0; i < notes.length; i++) {
      pattern.push(notes[i]);

      if (i < notes.length - 1) {
        pattern.push(tempo);
      }
    }

    this.vibrate.vibratePattern(pattern);
  }

  // Fade in/out
  fadeIn(maxDuration: number, steps: number = 5): void {
    const pattern: number[] = [];
    const stepDuration = maxDuration / steps;

    for (let i = 1; i <= steps; i++) {
      pattern.push(stepDuration * i, 50);
    }

    this.vibrate.vibratePattern(pattern);
  }

  fadeOut(maxDuration: number, steps: number = 5): void {
    const pattern: number[] = [];
    const stepDuration = maxDuration / steps;

    for (let i = steps; i >= 1; i--) {
      pattern.push(stepDuration * i, 50);
    }

    this.vibrate.vibratePattern(pattern);
  }

  // Ramping vibration
  ramp(startDuration: number, endDuration: number, steps: number = 5): void {
    const pattern: number[] = [];
    const increment = (endDuration - startDuration) / (steps - 1);

    for (let i = 0; i < steps; i++) {
      const duration = startDuration + (increment * i);
      pattern.push(duration, 50);
    }

    this.vibrate.vibratePattern(pattern);
  }
}

// Usage Examples
async function demonstrateVibration() {
  console.log('=== Web TypeScript Vibration API Examples ===\n');

  const vibrationManager = new VibrationManager();
  const hapticPatterns = new HapticFeedbackPatterns();
  const sequencer = new VibrationSequencer();
  const gameFeedback = new GameFeedbackVibrations();
  const composer = new VibrationComposer();

  // 1. Check support
  console.log('--- 1. Vibration Support ---');
  console.log('Vibration Supported:', vibrationManager.isSupported());

  if (!vibrationManager.isSupported()) {
    console.log('Vibration API is not supported on this device');
    return;
  }

  // 2. Basic vibration
  console.log('\n--- 2. Basic Vibration ---');
  console.log('Short vibration...');
  vibrationManager.vibrate(100);
  await new Promise(resolve => setTimeout(resolve, 500));

  // 3. Haptic patterns
  console.log('\n--- 3. Haptic Patterns ---');
  console.log('Success pattern...');
  hapticPatterns.success();
  await new Promise(resolve => setTimeout(resolve, 1000));

  console.log('Error pattern...');
  hapticPatterns.error();
  await new Promise(resolve => setTimeout(resolve, 1000));

  console.log('Warning pattern...');
  hapticPatterns.warning();
  await new Promise(resolve => setTimeout(resolve, 1000));

  // 4. Sequencer
  console.log('\n--- 4. Sequencer ---');
  console.log('SOS pattern...');
  hapticPatterns.sos();
  await new Promise(resolve => setTimeout(resolve, 2000));

  // 5. Game feedback
  console.log('\n--- 5. Game Feedback ---');
  console.log('Hit...');
  gameFeedback.hit();
  await new Promise(resolve => setTimeout(resolve, 300));

  console.log('Critical hit...');
  gameFeedback.criticalHit();
  await new Promise(resolve => setTimeout(resolve, 500));

  console.log('Power up...');
  gameFeedback.powerUp();
  await new Promise(resolve => setTimeout(resolve, 1000));

  // 6. Composer
  console.log('\n--- 6. Vibration Composer ---');
  console.log('Composed melody...');
  composer.composeMelody([100, 150, 200, 150, 100], 150);
  await new Promise(resolve => setTimeout(resolve, 1500));

  console.log('\n=== All Vibration API Examples Completed ===');
}

// Export functions
export { VibrationManager, HapticFeedbackPatterns, VibrationSequencer, NotificationVibrations, GameFeedbackVibrations, AccessibilityVibrations, VibrationComposer };
export { demonstrateVibration };