Maxim Salnikov
@webmaxru
How do we want web apps to feel like
Developer Audience Lead at Microsoft
Web App Manifest
Service Worker with "fetch"
{
{
  "name": "BPM Techno",
  "short_name": "BPM Techno Counter",
  "start_url": "?utm_source=homescreen",
  "display": "standalone",
  "background_color": "#fff",
  "description": "A free online BPM counter",
  "icons": [{
    "src": "images/touch/48x48.png",
    "sizes": "48x48",
    "type": "image/png"
  }]
}"shortcuts": [
  {
    "name": "Upload MP3 File",
    "short_name": "Upload MP3r",
    "description": "Count BPM of the uploaded file",
    "url": "/upload-mp3?utm_source=homescreen",
    "icons": [{ "src": "/icon-mp3.png", "sizes": "192x192" }]
  }
]"launch_handler": {
  "client_mode": "auto" | "navigate-new" | "navigate-existing" | "focus-existing"
}launchQueue.setConsumer(launchParams => {
  const url = launchParams.targetURL;
});{
  "display": "fullscreen" | "standalone" |
    "minimal-ui" | "browser",
  "display_override": ["window-control-overlay",
    "minimal-ui"],
}titlebar-area-x
titlebar-area-y
titlebar-area-width
titlebar-area-heightnavigator.windowControlsOverlay.
  getBoundingClientRect()
navigator.windowControlsOverlay.visible{
  "display_override": "tabbed"
}if (navigator.share) {
  navigator.share({
    title: 'BPM Techno',
    text: 'Check out BPMTech.no',
    url: 'https://bpmtech.no',
  })
    .then(() => console.log('Successful share'))
    .catch((err) => console.error(err));
}const props = ['name', 'email', 'tel'];
const opts = {multiple: true};
try {
  const contacts =
    await navigator.contacts.select(props, opts);
  handleResults(contacts);
} catch (err) {
  console.error(err));
}let openFileHandle;
btnOpen.addEventListener('click', async () => {
  [openFileHandle] =
    await window.showOpenFilePicker();
  const file = await fileHandle.getFile();
  const contents = await file.text();
});const saveFileHandle =
  await window.showSaveFilePicker();
const directoryHandle = 
  await window.showDirectoryPicker();"url_handlers": [
  {
    "origin": "https://bpmtech.no"
  },
  {
    "origin": "https://partnerapp.com"
  }
]"web_apps": [
  {
    "manifest": "https://partnerapp.com/manifest.json",
    "details": {
      "paths": [
        "/public/data/*"
      ]
    }
  }
]"capture_links":
  "none" | "new-client" |
    "existing-client-navigate""protocol_handlers": [
  {
    "protocol": "web+bpm",
    "url": "index.html?bpm=%s"
  }
]web+bpm://bpm=120
"file_handlers": [
  {
    "action": "/open-mp3",
    "accept": { "audio/mpeg": [".mp3"] },
    "icons": [
      {
        "src": "./images/mp3-file.png",
        "sizes": "144x144"
      }
    ]
  }
]window.launchQueue.setConsumer(launchParams => {
  const fileHandle = launchParams.files[0];
});"share_target": {
  "action": "/share",
  "method": "GET",
  "params": {
    "title": "title",
    "text": "text",
    "url": "url"
  }
}window.addEventListener('DOMContentLoaded', ()=> {
  const parsedUrl = new URL(window.location);
  const url = parsedUrl.searchParams.get('url');
});navigator.setAppBadge(42).catch((err) => {
  console.error(err)
});
navigator.clearAppBadge().catch((err) => {
  console.error(err)
});#30DaysOfPWA