├── code-splitting ├── app │ ├── static │ │ ├── mp4.js │ │ ├── database.js │ │ ├── videoencoder.js │ │ ├── about.js │ │ ├── index.js │ │ ├── images │ │ │ └── spinner.png │ │ ├── contact.js │ │ ├── misc.js │ │ ├── app.js │ │ ├── superstyles.css │ │ └── sc-view.js │ ├── footer.partial.html │ ├── favicon.ico │ ├── index.html │ ├── misc │ │ └── index.html │ ├── about │ │ └── index.html │ ├── contact │ │ └── index.html │ ├── sitemap.xml │ └── header.partial.html ├── .gitignore ├── README.md ├── package.json └── index.js ├── .gitignore ├── service-worker ├── app │ ├── index.html │ ├── misc │ │ └── index.html │ ├── about │ │ └── index.html │ ├── contact │ │ └── index.html │ ├── favicon.ico │ ├── static │ │ ├── images │ │ │ └── spinner.png │ │ ├── app.js │ │ ├── sc-view.js │ │ └── superstyles.css │ ├── footer.partial.html │ └── header.partial.html ├── README.md ├── package.json ├── cert.pem ├── key.pem └── index.js ├── server-side-rendering ├── app │ ├── index.html │ ├── misc │ │ └── index.html │ ├── about │ │ └── index.html │ ├── contact │ │ └── index.html │ ├── favicon.ico │ ├── static │ │ ├── images │ │ │ └── spinner.png │ │ ├── app.js │ │ ├── sc-view.js │ │ └── superstyles.css │ ├── footer.partial.html │ └── header.partial.html ├── README.md ├── package.json ├── cert.pem ├── key.pem └── index.js ├── router ├── favicon.ico ├── app.yaml ├── index.yaml ├── README.md ├── main.py ├── static │ ├── sc-view.js │ └── superstyles.css └── index.html ├── firebase-firestore-comments ├── .gitignore ├── .babelrc ├── .firebaserc ├── firebase.json ├── package.json └── src │ ├── components │ ├── sc-element.js │ ├── sc-comment.js │ ├── sc-comment-form.js │ ├── sc-login.js │ └── sc-comment-list.js │ ├── client │ └── index.js │ └── server │ ├── index.js │ └── index.html ├── parallax └── images │ ├── sea.jpg │ ├── stars.jpg │ ├── sunset.jpg │ └── screengrab.jpg ├── custom-scrollbar ├── cat.gif ├── step-1.html ├── step-2.html ├── step-3.html ├── step-4.html ├── step-5.html ├── index.html └── step-6.html ├── image-zoomer ├── gibraltar.jpg ├── index.html └── styles.css ├── router-advanced ├── favicon.ico ├── static │ ├── images │ │ └── spinner.png │ ├── app.js │ ├── sc-view.js │ └── superstyles.css ├── README.md ├── misc │ └── index.html ├── contact │ └── index.html ├── index.html └── about │ └── index.html ├── animated-blur ├── images │ ├── chrome.png │ ├── gmail.png │ ├── maps.png │ ├── photos.png │ ├── search.png │ ├── android.png │ ├── youtube.png │ └── translate.png ├── reallybadblur.html ├── badblur.html ├── goodblur.html └── index.html ├── expand-collapse ├── images │ └── img.jpg └── index.html ├── lazy-image ├── static │ ├── images │ │ ├── a.jpg │ │ ├── b.jpg │ │ ├── c.jpg │ │ └── d.jpg │ ├── styles.css │ ├── index.html │ └── sc-img.js ├── package.json └── index.js ├── webgl-image-processing ├── image.jpg └── index.html ├── 3d-card-flip ├── images │ ├── supercharged.jpg │ ├── umbra.svg │ └── penumbra.svg ├── index.html └── styles.css ├── infinite-scroller ├── images │ ├── avatar0.jpg │ ├── avatar1.jpg │ ├── avatar2.jpg │ ├── avatar3.jpg │ ├── image0.jpg │ ├── image1.jpg │ ├── image10.jpg │ ├── image11.jpg │ ├── image12.jpg │ ├── image13.jpg │ ├── image14.jpg │ ├── image15.jpg │ ├── image16.jpg │ ├── image17.jpg │ ├── image18.jpg │ ├── image19.jpg │ ├── image2.jpg │ ├── image20.jpg │ ├── image21.jpg │ ├── image22.jpg │ ├── image23.jpg │ ├── image24.jpg │ ├── image25.jpg │ ├── image26.jpg │ ├── image27.jpg │ ├── image28.jpg │ ├── image29.jpg │ ├── image3.jpg │ ├── image30.jpg │ ├── image31.jpg │ ├── image32.jpg │ ├── image33.jpg │ ├── image34.jpg │ ├── image35.jpg │ ├── image36.jpg │ ├── image37.jpg │ ├── image38.jpg │ ├── image39.jpg │ ├── image4.jpg │ ├── image40.jpg │ ├── image41.jpg │ ├── image42.jpg │ ├── image43.jpg │ ├── image44.jpg │ ├── image45.jpg │ ├── image46.jpg │ ├── image47.jpg │ ├── image48.jpg │ ├── image49.jpg │ ├── image5.jpg │ ├── image50.jpg │ ├── image51.jpg │ ├── image52.jpg │ ├── image53.jpg │ ├── image54.jpg │ ├── image55.jpg │ ├── image56.jpg │ ├── image57.jpg │ ├── image58.jpg │ ├── image59.jpg │ ├── image6.jpg │ ├── image60.jpg │ ├── image61.jpg │ ├── image62.jpg │ ├── image63.jpg │ ├── image64.jpg │ ├── image65.jpg │ ├── image66.jpg │ ├── image67.jpg │ ├── image68.jpg │ ├── image69.jpg │ ├── image7.jpg │ ├── image70.jpg │ ├── image71.jpg │ ├── image72.jpg │ ├── image73.jpg │ ├── image74.jpg │ ├── image75.jpg │ ├── image76.jpg │ ├── image8.jpg │ ├── image9.jpg │ └── unknown.jpg ├── stats.min.js └── styles │ └── messages.css ├── streaming-service-worker ├── static │ ├── favicon.ico │ ├── imgs │ │ ├── me.jpg │ │ ├── icon.png │ │ └── browser-icons │ │ │ ├── chrome.png │ │ │ ├── edge.png │ │ │ ├── safari.png │ │ │ └── firefox.png │ └── css │ │ └── imgs │ │ ├── check.png │ │ ├── graph-tile.png │ │ └── social-icons.png ├── server │ ├── error404.js │ ├── marked.js │ ├── index.js │ └── rev.js ├── templates │ ├── shell.njk │ ├── offline-inc.njk │ ├── who.njk │ ├── base-side.njk │ ├── post-inc.njk │ ├── 404.njk │ ├── post.njk │ ├── base.njk │ ├── index.njk │ └── who-inc.njk ├── posts │ ├── combining-fonts │ │ └── meta.json │ ├── es-modules-in-browsers │ │ └── meta.json │ └── h2-push-tougher-than-i-thought │ │ └── meta.json ├── package.json └── client │ └── sw.js ├── .editorconfig ├── stream-progress ├── README.md ├── index.html ├── stream.js └── dial.js ├── web-workers ├── main.css ├── worker.js └── index.html ├── .eslintrc ├── template ├── element.js ├── index.html └── element.css ├── swipeable-cards ├── cards.css └── index.html ├── CONTRIBUTING.md ├── accordion ├── sc-pane.js └── styles.css ├── flip-switch └── index.html ├── side-nav ├── index.html └── detabinator.js ├── README.md └── animated-clip └── advanced └── index.html /code-splitting/app/static/mp4.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code-splitting/.gitignore: -------------------------------------------------------------------------------- 1 | _*.js 2 | -------------------------------------------------------------------------------- /code-splitting/app/static/database.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code-splitting/app/footer.partial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /code-splitting/app/static/videoencoder.js: -------------------------------------------------------------------------------- 1 | import '/static/mp4.js'; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.pyc 4 | serve 5 | *.pem 6 | .vscode 7 | -------------------------------------------------------------------------------- /service-worker/app/index.html: -------------------------------------------------------------------------------- 1 | Home 2 | -------------------------------------------------------------------------------- /server-side-rendering/app/index.html: -------------------------------------------------------------------------------- 1 | Home 2 | -------------------------------------------------------------------------------- /router/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/router/favicon.ico -------------------------------------------------------------------------------- /service-worker/app/misc/index.html: -------------------------------------------------------------------------------- 1 | Misc 2 | -------------------------------------------------------------------------------- /firebase-firestore-comments/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | functions 3 | node_modules 4 | public 5 | firebase-debug.log 6 | -------------------------------------------------------------------------------- /parallax/images/sea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/parallax/images/sea.jpg -------------------------------------------------------------------------------- /server-side-rendering/app/misc/index.html: -------------------------------------------------------------------------------- 1 | Misc 2 | -------------------------------------------------------------------------------- /service-worker/app/about/index.html: -------------------------------------------------------------------------------- 1 | About 2 | -------------------------------------------------------------------------------- /custom-scrollbar/cat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/custom-scrollbar/cat.gif -------------------------------------------------------------------------------- /firebase-firestore-comments/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-modules-commonjs" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /firebase-firestore-comments/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "supercharged-comments" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /image-zoomer/gibraltar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/image-zoomer/gibraltar.jpg -------------------------------------------------------------------------------- /parallax/images/stars.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/parallax/images/stars.jpg -------------------------------------------------------------------------------- /parallax/images/sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/parallax/images/sunset.jpg -------------------------------------------------------------------------------- /server-side-rendering/app/about/index.html: -------------------------------------------------------------------------------- 1 | About 2 | -------------------------------------------------------------------------------- /service-worker/app/contact/index.html: -------------------------------------------------------------------------------- 1 | Contact 2 | -------------------------------------------------------------------------------- /router-advanced/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/router-advanced/favicon.ico -------------------------------------------------------------------------------- /animated-blur/images/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/chrome.png -------------------------------------------------------------------------------- /animated-blur/images/gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/gmail.png -------------------------------------------------------------------------------- /animated-blur/images/maps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/maps.png -------------------------------------------------------------------------------- /animated-blur/images/photos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/photos.png -------------------------------------------------------------------------------- /animated-blur/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/search.png -------------------------------------------------------------------------------- /code-splitting/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/code-splitting/app/favicon.ico -------------------------------------------------------------------------------- /code-splitting/app/static/about.js: -------------------------------------------------------------------------------- 1 | import '/static/sc-view.js'; 2 | import '/static/sc-router.js'; 3 | import '/static/app.js'; 4 | -------------------------------------------------------------------------------- /code-splitting/app/static/index.js: -------------------------------------------------------------------------------- 1 | import '/static/sc-view.js'; 2 | import '/static/sc-router.js'; 3 | import '/static/app.js'; 4 | -------------------------------------------------------------------------------- /expand-collapse/images/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/expand-collapse/images/img.jpg -------------------------------------------------------------------------------- /lazy-image/static/images/a.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/lazy-image/static/images/a.jpg -------------------------------------------------------------------------------- /lazy-image/static/images/b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/lazy-image/static/images/b.jpg -------------------------------------------------------------------------------- /lazy-image/static/images/c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/lazy-image/static/images/c.jpg -------------------------------------------------------------------------------- /lazy-image/static/images/d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/lazy-image/static/images/d.jpg -------------------------------------------------------------------------------- /parallax/images/screengrab.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/parallax/images/screengrab.jpg -------------------------------------------------------------------------------- /server-side-rendering/app/contact/index.html: -------------------------------------------------------------------------------- 1 | Contact 2 | -------------------------------------------------------------------------------- /service-worker/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/service-worker/app/favicon.ico -------------------------------------------------------------------------------- /animated-blur/images/android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/android.png -------------------------------------------------------------------------------- /animated-blur/images/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/youtube.png -------------------------------------------------------------------------------- /webgl-image-processing/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/webgl-image-processing/image.jpg -------------------------------------------------------------------------------- /3d-card-flip/images/supercharged.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/3d-card-flip/images/supercharged.jpg -------------------------------------------------------------------------------- /animated-blur/images/translate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/animated-blur/images/translate.png -------------------------------------------------------------------------------- /infinite-scroller/images/avatar0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/avatar0.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/avatar1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/avatar1.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/avatar2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/avatar2.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/avatar3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/avatar3.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image0.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image1.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image10.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image11.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image12.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image13.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image14.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image15.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image16.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image17.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image18.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image19.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image2.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image20.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image21.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image22.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image23.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image24.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image25.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image26.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image27.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image28.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image28.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image29.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image29.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image3.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image30.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image31.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image32.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image33.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image34.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image34.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image35.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image35.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image36.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image36.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image37.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image37.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image38.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image38.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image39.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image39.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image4.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image40.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image40.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image41.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image41.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image42.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image42.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image43.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image43.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image44.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image44.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image45.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image45.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image46.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image46.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image47.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image47.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image48.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image48.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image49.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image49.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image5.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image50.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image50.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image51.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image51.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image52.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image52.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image53.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image53.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image54.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image54.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image55.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image55.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image56.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image56.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image57.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image57.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image58.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image58.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image59.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image59.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image6.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image60.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image60.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image61.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image61.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image62.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image62.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image63.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image63.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image64.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image64.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image65.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image65.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image66.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image66.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image67.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image67.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image68.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image68.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image69.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image69.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image7.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image70.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image70.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image71.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image71.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image72.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image72.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image73.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image73.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image74.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image74.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image75.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image75.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image76.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image76.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image8.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/image9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/image9.jpg -------------------------------------------------------------------------------- /infinite-scroller/images/unknown.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/infinite-scroller/images/unknown.jpg -------------------------------------------------------------------------------- /server-side-rendering/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/server-side-rendering/app/favicon.ico -------------------------------------------------------------------------------- /router-advanced/static/images/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/router-advanced/static/images/spinner.png -------------------------------------------------------------------------------- /streaming-service-worker/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/favicon.ico -------------------------------------------------------------------------------- /streaming-service-worker/static/imgs/me.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/imgs/me.jpg -------------------------------------------------------------------------------- /code-splitting/app/static/images/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/code-splitting/app/static/images/spinner.png -------------------------------------------------------------------------------- /service-worker/app/static/images/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/service-worker/app/static/images/spinner.png -------------------------------------------------------------------------------- /streaming-service-worker/static/imgs/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/imgs/icon.png -------------------------------------------------------------------------------- /code-splitting/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | Home 3 | 4 | 5 | -------------------------------------------------------------------------------- /code-splitting/app/static/contact.js: -------------------------------------------------------------------------------- 1 | import '/static/sc-view.js'; 2 | import '/static/sc-router.js'; 3 | import '/static/app.js'; 4 | import '/static/database.js'; 5 | -------------------------------------------------------------------------------- /server-side-rendering/app/static/images/spinner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/server-side-rendering/app/static/images/spinner.png -------------------------------------------------------------------------------- /streaming-service-worker/static/css/imgs/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/css/imgs/check.png -------------------------------------------------------------------------------- /code-splitting/app/misc/index.html: -------------------------------------------------------------------------------- 1 | 2 | Misc 3 | 4 | 5 | -------------------------------------------------------------------------------- /streaming-service-worker/static/css/imgs/graph-tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/css/imgs/graph-tile.png -------------------------------------------------------------------------------- /code-splitting/app/about/index.html: -------------------------------------------------------------------------------- 1 | 2 | About 3 | 4 | 5 | -------------------------------------------------------------------------------- /streaming-service-worker/static/css/imgs/social-icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/css/imgs/social-icons.png -------------------------------------------------------------------------------- /streaming-service-worker/static/imgs/browser-icons/chrome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/imgs/browser-icons/chrome.png -------------------------------------------------------------------------------- /streaming-service-worker/static/imgs/browser-icons/edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/imgs/browser-icons/edge.png -------------------------------------------------------------------------------- /streaming-service-worker/static/imgs/browser-icons/safari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/imgs/browser-icons/safari.png -------------------------------------------------------------------------------- /code-splitting/app/contact/index.html: -------------------------------------------------------------------------------- 1 | 2 | Contact 3 | 4 | 5 | -------------------------------------------------------------------------------- /streaming-service-worker/static/imgs/browser-icons/firefox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleChromeLabs/ui-element-samples/HEAD/streaming-service-worker/static/imgs/browser-icons/firefox.png -------------------------------------------------------------------------------- /code-splitting/app/static/misc.js: -------------------------------------------------------------------------------- 1 | import '/static/sc-view.js'; 2 | import '/static/sc-router.js'; 3 | import '/static/app.js'; 4 | import '/static/database.js'; 5 | import '/static/videoencoder.js'; 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /streaming-service-worker/server/error404.js: -------------------------------------------------------------------------------- 1 | class Error404 extends Error { 2 | constructor(message) { 3 | super(message); 4 | this.name = 'Error404'; 5 | } 6 | } 7 | 8 | module.exports = Error404; -------------------------------------------------------------------------------- /firebase-firestore-comments/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "public", 4 | "rewrites": [ 5 | { 6 | "source": "**", 7 | "function": "supercharged" 8 | } 9 | ] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/shell.njk: -------------------------------------------------------------------------------- 1 | {% extends 'base-side.njk' %} 2 | {% block title %}Loading{% endblock %} 3 | {% block author_action %} streamed…{% endblock %} 4 | 5 | {% block mainContent %} 6 | 7 | {% endblock %} -------------------------------------------------------------------------------- /service-worker/app/footer.partial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /stream-progress/README.md: -------------------------------------------------------------------------------- 1 | # Stream progress 2 | 3 | This sample loads a fairly big file via fetch, decodes it using TransformStream and displays a radial progress bar while loading. 4 | 5 | Probably best enjoyed with network throttling enabled in DevTools. 6 | -------------------------------------------------------------------------------- /server-side-rendering/app/footer.partial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /server-side-rendering/README.md: -------------------------------------------------------------------------------- 1 | # Server-side Rendering 2 | 3 | This is a small backend for the `router-advances` using Node. Make sure you have node5 for HTTP/2 support! 4 | 5 | Run `npm install` to install all dependencies and run the server with `node index.js`. 6 | -------------------------------------------------------------------------------- /router-advanced/README.md: -------------------------------------------------------------------------------- 1 | # Router (Advanced) 2 | 3 | This router build on the previous SPA-like one, but does not require a server-side component, 4 | and works if the user does not have JavaScript. 5 | 6 | It also loads content over XHR rather than baking it into the page. 7 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/offline-inc.njk: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

Massive connectivity breakdown

7 |

Try refreshing and waving your phone around a bit.

8 |
-------------------------------------------------------------------------------- /code-splitting/README.md: -------------------------------------------------------------------------------- 1 | # Code Splitting 2 | 3 | This is mostly the code from the `server-side-rendering` sample. We have added `build.js` to perform code splitting and 4 | route-based chunking. 5 | 6 | Run `npm install` to install all dependencies. Run `node build.js` and then run the server with `node index.js`. 7 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/who.njk: -------------------------------------------------------------------------------- 1 | {% extends 'base.njk' %} 2 | 3 | {% block title %}Who?{% endblock %} 4 | 5 | {% block content %} 6 |
7 |
8 |

Who?

9 | {% include 'who-inc.njk' %} 10 |
11 |
12 | {% endblock %} -------------------------------------------------------------------------------- /streaming-service-worker/templates/base-side.njk: -------------------------------------------------------------------------------- 1 | {% extends 'base.njk' %} 2 | 3 | {% block content %} 4 |
5 |
6 | {% block mainContent %}{% endblock %} 7 |
8 |
{% include 'who-inc.njk' %}
9 |
10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /server-side-rendering/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-side-rendering", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "express": "^4.14.0", 7 | "handlebars": "^4.0.5", 8 | "spdy": "^3.4.0", 9 | "http2": "^3.3.5", 10 | "mz": "^2.4.0" 11 | }, 12 | "devDependencies": {} 13 | } 14 | -------------------------------------------------------------------------------- /service-worker/README.md: -------------------------------------------------------------------------------- 1 | # Service-Worker 2 | 3 | This is a service-worker for our server-side-rendering session. 4 | 5 | Run `npm install` to install all dependencies and run the server with `node index.js`. 6 | Start Chrome Canary using `npm run chrome`, since HTTP/2 and ServiceWorker development 7 | on localhost doesn’t play nicely currently. 8 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/post-inc.njk: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

{{ meta.title }}

7 | 10 | {{ content|safe }} 11 |
-------------------------------------------------------------------------------- /code-splitting/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-side-rendering", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "babel-core": "^6.25.0", 7 | "express": "^4.14.0", 8 | "handlebars": "^4.0.5", 9 | "http2": "^3.3.5", 10 | "mz": "^2.4.0", 11 | "spdy": "^3.4.0", 12 | "xml2js": "^0.4.17" 13 | }, 14 | "devDependencies": {} 15 | } 16 | -------------------------------------------------------------------------------- /custom-scrollbar/step-1.html: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 |
20 |
21 |
22 | -------------------------------------------------------------------------------- /web-workers/main.css: -------------------------------------------------------------------------------- 1 | canvas { 2 | margin-top: 2em; 3 | } 4 | 5 | #input { 6 | height: 0; 7 | overflow: hidden; 8 | width: 0; 9 | } 10 | 11 | #input + label { 12 | background-color: #777; 13 | color: #f3f3f3; 14 | display: inline-block; 15 | font-family: sans-serif; 16 | font-size: 2em; 17 | padding: 5px; 18 | } 19 | 20 | #input:focus + label { 21 | outline: 5px solid teal; 22 | } 23 | -------------------------------------------------------------------------------- /3d-card-flip/images/umbra.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /streaming-service-worker/posts/combining-fonts/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Combining fonts", 3 | "posted": "2017-04-28", 4 | "summary": "I love the font [Just Another Hand](https://fonts.google.com/specimen/Just+Another+Hand), but I don't like the positioning of the hyphen & equals glyphs. Thankfully I can use CSS fonts to fix it!", 5 | "description": "Using @font-face to replace glyphs of one font with another." 6 | } -------------------------------------------------------------------------------- /3d-card-flip/images/penumbra.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lazy-image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "polysum", 3 | "version": "0.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Surma ", 11 | "license": "MIT", 12 | "dependencies": { 13 | "express": "^4.15.4", 14 | "gm": "^1.23.0", 15 | "nodemon": "^1.11.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code-splitting/app/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | http://www.example.com/ 5 | 6 | 7 | http://www.example.com/about.html 8 | 9 | 10 | http://www.example.com/contact.html 11 | 12 | 13 | http://www.example.com/misc.html 14 | 15 | 16 | -------------------------------------------------------------------------------- /streaming-service-worker/posts/es-modules-in-browsers/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "ECMAScript modules in browsers", 3 | "posted": "2017-05-02", 4 | "summary": "ES modules are starting to land in browsers! Modules in general are [pretty well documented](https://ponyfoo.com/articles/es6-modules-in-depth), but here are some browser-specific differences…", 5 | "description": "ES modules are landing in browsers! Here are the HTML-specific differences you need to be aware of." 6 | } -------------------------------------------------------------------------------- /router/app.yaml: -------------------------------------------------------------------------------- 1 | application: router 2 | version: 1 3 | runtime: python27 4 | api_version: 1 5 | threadsafe: yes 6 | 7 | handlers: 8 | - url: /favicon\.ico 9 | static_files: favicon.ico 10 | upload: favicon\.ico 11 | 12 | - url: /static/(.*) 13 | static_files: static/\1 14 | upload: static/(.*) 15 | application_readable: true 16 | 17 | - url: .* 18 | script: main.app 19 | 20 | libraries: 21 | - name: webapp2 22 | version: "2.5.2" 23 | - name: jinja2 24 | version: latest 25 | -------------------------------------------------------------------------------- /custom-scrollbar/step-2.html: -------------------------------------------------------------------------------- 1 | 2 | 24 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/404.njk: -------------------------------------------------------------------------------- 1 | {% extends 'base-side.njk' %} 2 | 3 | {% block title %}404{% endblock %} 4 | {% block author_action %} is sorry about the...{% endblock %} 5 | 6 | {% block mainContent %} 7 |
8 |

Alarming 404 situation

9 |

10 | Hmm, that page couldn't be found. You should leave a comment 11 | below letting me know how angry you are about this. The more sweary 12 | the better. 13 |

14 |
15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /router/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | 13 | -------------------------------------------------------------------------------- /custom-scrollbar/step-3.html: -------------------------------------------------------------------------------- 1 | 2 | 25 |
26 |
27 |
28 | -------------------------------------------------------------------------------- /service-worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server-side-rendering", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "dependencies": { 6 | "dot": "^1.0.3", 7 | "express": "^4.14.0", 8 | "http2": "^3.3.5", 9 | "mz": "^2.4.0", 10 | "spdy": "^3.4.0" 11 | }, 12 | "devDependencies": {}, 13 | "scripts": { 14 | "chrome": "rm -rf /tmp/foo && open -a 'Google Chrome Canary' -n --args --user-data-dir=/tmp/foo --ignore-certificate-errors --unsafely-treat-insecure-origin-as-secure=https://localhost:8081 https://localhost:8081/" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /router/README.md: -------------------------------------------------------------------------------- 1 | # Router 2 | 3 | The router requires a server-side component because of the deeplinking. In order to get that to work, you should clone the repo and do the following: 4 | 5 | 1. Clone the project. 6 | 1. Install the [Google App Engine SDK For Python](https://cloud.google.com/appengine/downloads#Google_App_Engine_SDK_for_Python). 7 | 1. Run the SDK app to create symlinks. 8 | 1. Add it to the GAE Launcher you downloaded (Existing app, (Ctrl|Cmd)+Shift+N, /path/to/router). 9 | 1. Enjoy your local version of the router sample, probably at [localhost:8080](http://localhost:8080). 10 | -------------------------------------------------------------------------------- /animated-blur/reallybadblur.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 28 |
29 | 30 |
31 | -------------------------------------------------------------------------------- /custom-scrollbar/step-4.html: -------------------------------------------------------------------------------- 1 | 2 | 32 |
33 |
34 | 35 |
36 | -------------------------------------------------------------------------------- /streaming-service-worker/posts/h2-push-tougher-than-i-thought/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "HTTP/2 push is tougher than I thought", 3 | "posted": "2017-05-30", 4 | "summary": "\"HTTP/2 push will solve that\" is something I've heard a lot when it comes to page load performance problems, but I didn't know much about it, so I decided to dig in.\n HTTP/2 push is more complicated and low-level than I initially thought, but what really caught me off-guard is how inconsistent it is between browsers – I'd assumed it was a done deal & totally ready for production.", 5 | "description": "There are lots of edge cases I hadn't considered, and it's very inconsistent between browsers. Here's what I found…" 6 | } -------------------------------------------------------------------------------- /streaming-service-worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sw-blog", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "serve": "nodemon -e js,njk server/index.js" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "del": "^3.0.0", 13 | "escape-string-regexp": "^1.0.5", 14 | "express": "^4.15.3", 15 | "glob": "^7.1.2", 16 | "highlight.js": "^9.12.0", 17 | "marked": "^0.3.6", 18 | "mkdirp": "^0.5.1", 19 | "nodemon": "^1.11.0", 20 | "nunjucks": "^3.0.1", 21 | "nunjucks-date-filter": "^0.1.1", 22 | "static-module": "^1.4.0", 23 | "through2": "^2.0.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/post.njk: -------------------------------------------------------------------------------- 1 | {% extends 'base-side.njk' %} 2 | 3 | {% block title %}{{ meta.title }}{% endblock %} 4 | {% block author_action %} wrote...{% endblock %} 5 | {% block extra_head %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | {% endblock %} 13 | 14 | {% block mainContent %} 15 | {% include 'post-inc.njk' %} 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /webgl-image-processing/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google", 3 | "env": { 4 | "browser": true, 5 | "es6": true 6 | }, 7 | "rules": { 8 | "space-before-function-paren": [2, {"named": "always", "anonymous": "always"}], 9 | "max-len": [2, 100, { 10 | "ignoreComments": true, 11 | "ignoreUrls": true, 12 | "tabWidth": 2 13 | }], 14 | "no-implicit-coercion": [2, { 15 | "boolean": false, 16 | "number": true, 17 | "string": true 18 | }], 19 | "no-unused-expressions": [2, { 20 | "allowShortCircuit": true, 21 | "allowTernary": false 22 | }], 23 | "no-unused-vars": [2, { 24 | "vars": "all", 25 | "args": "after-used", 26 | "argsIgnorePattern": "(^reject$|^_$)", 27 | "varsIgnorePattern": "(^_$)" 28 | }], 29 | "quotes": [2, "single"], 30 | "require-jsdoc": 0, 31 | "valid-jsdoc": 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lazy-image/static/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2017 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | body { 18 | padding: 50px; 19 | max-width: 720px; 20 | margin: 0 auto; 21 | } 22 | 23 | .spacer { 24 | height: 120vh; 25 | } 26 | 27 | img { 28 | display: block; 29 | width: 100%; 30 | } 31 | -------------------------------------------------------------------------------- /firebase-firestore-comments/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "supercharged", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "yarn build:client && yarn build:server && yarn build:components && yarn babel:components", 8 | "build:server": "cpx src/server/**/* functions", 9 | "build:client": "cpx src/client/**/* public", 10 | "build:components": "cpx src/components/**/* public/components", 11 | "babel:components": "babel src/components -d functions/components", 12 | "serve": "firebase serve --only functions,hosting" 13 | }, 14 | "dependencies": { 15 | "express": "^4.16.2", 16 | "firebase": "^4.9.0", 17 | "firebase-functions": "^0.8.1" 18 | }, 19 | "devDependencies": { 20 | "babel-cli": "^6.26.0", 21 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 22 | "cpx": "^1.5.0", 23 | "firebase-tools": "~3.17.4" 24 | } 25 | } -------------------------------------------------------------------------------- /template/element.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2015 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class Element { 21 | 22 | constructor () { 23 | this.addEventListeners(); 24 | } 25 | 26 | addEventListeners () { 27 | } 28 | 29 | removeEventListeners () { 30 | } 31 | 32 | } 33 | 34 | new Element(); 35 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/base.njk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block title %}{% endblock %} - JakeArchibald.com 5 | 6 | 7 | {% block extra_head %}{% endblock %} 8 | 9 | 10 | 16 |
17 | {% block content %}{% endblock %} 18 |
19 | {% block extra_body %}{% endblock %} 20 | 23 | 24 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/index.njk: -------------------------------------------------------------------------------- 1 | {% extends 'base-side.njk' %} 2 | 3 | {% block title %}Blog{% endblock %} 4 | {% block page_class %}blog-index{% endblock %} 5 | {% block author_action %} wrote...{% endblock %} 6 | 7 | {% block mainContent %} 8 | {% for post in posts %} 9 |
10 |
11 |

{{ post.title }}

12 | 15 |
16 |
17 | {{ post.summary|safe }} 18 |

Read on…

19 |
20 |
21 | {% endfor %} 22 | {% endblock %} 23 | -------------------------------------------------------------------------------- /lazy-image/static/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 |
23 | 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /service-worker/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6DCCAdCgAwIBAgIRANPICMcz6V25HmlVLSMGZc8wDQYJKoZIhvcNAQELBQAw 3 | EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA5MTUxMzA3NDVaFw0xNzA5MTUxMzA3 4 | NDVaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 5 | ggEKAoIBAQC+m69KqEYeVECwOUgDqB1uER5UMgUTRBdYKN6LmWtqsaYCVttk6jBu 6 | 2sHpaXO4n1nbIh+vFpzIPlW8/yZEzjOhXbJfTjcjJ+OQIXFuLGoaYmZH+Oowh6Cw 7 | ToKxDiOGythEpBXkAMI9T/O3LuAz2PCvsRU90DX9mJ9uaBvpqaOe4Z7JpEXTxV2P 8 | uB2btMpUX74Jze99ldta7n+lxPDk7Btjtx8UC7VqAx0Sv6etXBMfhkIHKQgVAj1i 9 | C8ue05/eqS+VfxVcuZFQ2cb69d67tmjnruLlImjq1nI5RntytlakRb9mvUxti35d 10 | JFdRSYIjX1YpXs6EEY0BGXddnr1QZrm9AgMBAAGjOTA3MA4GA1UdDwEB/wQEAwIC 11 | pDAPBgNVHRMBAf8EBTADAQH/MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG 12 | 9w0BAQsFAAOCAQEABv2xV9MaI7ziuEkD7SxaR7m5jta67gRQA8HO/t2v+nq/hbRb 13 | FktF7v4kh7jCTRogn2bBaGUp8wpoHNCaEfoeCqFzeTOGXESS7/PzBiY6dozOHM35 14 | piuzHXbwcxo3y9EUi/RxEgL4JP4YafNsQ6hcIbYTPqW+c7oD2VZPrLWsF0YvU9TR 15 | 0EikiSsbVpXtbPRsQmKxRR+1oI2AbWpRLfJ367FvUH7y00KoikQkMYesk+ImdkHZ 16 | U2Q3ujGq7HyK38SWmWZWSfkOucpYHOiljRd+Nj4Nm3yJSnfZdy7+Npy/GrJsnl78 17 | xW/q8QyED0WEsoDhTzTSLG90df7V6pVz0i3F0A== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /server-side-rendering/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6DCCAdCgAwIBAgIRANPICMcz6V25HmlVLSMGZc8wDQYJKoZIhvcNAQELBQAw 3 | EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA5MTUxMzA3NDVaFw0xNzA5MTUxMzA3 4 | NDVaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 5 | ggEKAoIBAQC+m69KqEYeVECwOUgDqB1uER5UMgUTRBdYKN6LmWtqsaYCVttk6jBu 6 | 2sHpaXO4n1nbIh+vFpzIPlW8/yZEzjOhXbJfTjcjJ+OQIXFuLGoaYmZH+Oowh6Cw 7 | ToKxDiOGythEpBXkAMI9T/O3LuAz2PCvsRU90DX9mJ9uaBvpqaOe4Z7JpEXTxV2P 8 | uB2btMpUX74Jze99ldta7n+lxPDk7Btjtx8UC7VqAx0Sv6etXBMfhkIHKQgVAj1i 9 | C8ue05/eqS+VfxVcuZFQ2cb69d67tmjnruLlImjq1nI5RntytlakRb9mvUxti35d 10 | JFdRSYIjX1YpXs6EEY0BGXddnr1QZrm9AgMBAAGjOTA3MA4GA1UdDwEB/wQEAwIC 11 | pDAPBgNVHRMBAf8EBTADAQH/MBQGA1UdEQQNMAuCCWxvY2FsaG9zdDANBgkqhkiG 12 | 9w0BAQsFAAOCAQEABv2xV9MaI7ziuEkD7SxaR7m5jta67gRQA8HO/t2v+nq/hbRb 13 | FktF7v4kh7jCTRogn2bBaGUp8wpoHNCaEfoeCqFzeTOGXESS7/PzBiY6dozOHM35 14 | piuzHXbwcxo3y9EUi/RxEgL4JP4YafNsQ6hcIbYTPqW+c7oD2VZPrLWsF0YvU9TR 15 | 0EikiSsbVpXtbPRsQmKxRR+1oI2AbWpRLfJ367FvUH7y00KoikQkMYesk+ImdkHZ 16 | U2Q3ujGq7HyK38SWmWZWSfkOucpYHOiljRd+Nj4Nm3yJSnfZdy7+Npy/GrJsnl78 17 | xW/q8QyED0WEsoDhTzTSLG90df7V6pVz0i3F0A== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /code-splitting/app/static/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class App { 21 | constructor () { 22 | const router = document.querySelector('sc-router'); 23 | const links = Array.from(document.querySelectorAll('a')); 24 | 25 | function onClick (evt) { 26 | evt.preventDefault(); 27 | router.go(evt.target.href); 28 | } 29 | 30 | links.forEach(link => { 31 | link.addEventListener('click', onClick); 32 | }); 33 | } 34 | } 35 | 36 | (_ => new App())(); 37 | -------------------------------------------------------------------------------- /router-advanced/static/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class App { 21 | constructor () { 22 | const router = document.querySelector('sc-router'); 23 | const links = Array.from(document.querySelectorAll('a')); 24 | 25 | function onClick (evt) { 26 | evt.preventDefault(); 27 | router.go(evt.target.href); 28 | } 29 | 30 | links.forEach(link => { 31 | link.addEventListener('click', onClick); 32 | }); 33 | } 34 | } 35 | 36 | (_ => new App())(); 37 | -------------------------------------------------------------------------------- /server-side-rendering/app/static/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class App { 21 | constructor () { 22 | const router = document.querySelector('sc-router'); 23 | const links = Array.from(document.querySelectorAll('a')); 24 | 25 | function onClick (evt) { 26 | evt.preventDefault(); 27 | router.go(evt.target.href); 28 | } 29 | 30 | links.forEach(link => { 31 | link.addEventListener('click', onClick); 32 | }); 33 | } 34 | } 35 | 36 | (_ => new App())(); 37 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/components/sc-element.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | // are you node? 18 | // yah 19 | // umm... use this HTMLElement class I made 20 | // okay... sure? 21 | 22 | // are you browser? 23 | // yah 24 | // umm... use your HTMLElement class 25 | // okay... I was gonna do that anyways? thx? 26 | 27 | let _HTMLElement; 28 | if(typeof process !== 'undefined') { 29 | _HTMLElement = class HTMLElement { } 30 | } else { 31 | _HTMLElement = HTMLElement; 32 | } 33 | 34 | export class SCElement extends _HTMLElement { } 35 | -------------------------------------------------------------------------------- /router/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright 2007 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | import webapp2 18 | import jinja2 19 | import os 20 | 21 | JINJA_ENVIRONMENT = jinja2.Environment( 22 | loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), 23 | extensions=['jinja2.ext.autoescape'], 24 | autoescape=True) 25 | 26 | class MainHandler(webapp2.RequestHandler): 27 | def get(self, req): 28 | template = JINJA_ENVIRONMENT.get_template('index.html') 29 | self.response.write(template.render()) 30 | 31 | app = webapp2.WSGIApplication([ 32 | ('/(.*)', MainHandler) 33 | ], debug=True) 34 | -------------------------------------------------------------------------------- /streaming-service-worker/server/marked.js: -------------------------------------------------------------------------------- 1 | const marked = require('marked'); 2 | const highlight = require('highlight.js'); 3 | 4 | const renderer = new marked.Renderer(); 5 | 6 | marked.setOptions({ 7 | renderer, 8 | highlight(code, lang) { 9 | if (lang) { 10 | return highlight.highlight(lang, code).value; 11 | } 12 | return highlight.highlightAuto(code).value; 13 | } 14 | }); 15 | 16 | renderer.heading = function (text, level, raw) { 17 | return marked.Renderer.prototype.heading.call(this, text, level + 1, raw); 18 | }; 19 | 20 | renderer.code = function (code, lang, escaped) { 21 | if (this.options.highlight) { 22 | var out = this.options.highlight(code, lang); 23 | if (out != null && out !== code) { 24 | escaped = true; 25 | code = out; 26 | } 27 | } 28 | 29 | if (!lang) { 30 | return '
'
31 |       + (escaped ? code : escape(code, true))
32 |       + '\n
'; 33 | } 34 | 35 | return '
'
39 |     + (escaped ? code : escape(code, true))
40 |     + '\n
\n'; 41 | }; 42 | 43 | module.exports = marked; -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | UI Element: [Element name] 26 | 27 | 28 | 29 | 30 |
31 |

[Element name]

32 |
33 |
34 |
35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /custom-scrollbar/step-5.html: -------------------------------------------------------------------------------- 1 | 2 | 37 |
38 |
39 | 40 |
41 | 48 | -------------------------------------------------------------------------------- /stream-progress/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /web-workers/worker.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Google Inc. All Rights Reserved. 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | 15 | /** 16 | * Handles incoming messages in the web worker. 17 | * In this case: increases each pixel's red color by 20%. 18 | * @param {!Object} d Incoming data. 19 | */ 20 | addEventListener('message', (d) => { 21 | const imageData = d.data; 22 | const w = imageData.width; 23 | const h = imageData.height; 24 | const data = imageData.data; 25 | 26 | // Iterate pixel rows and columns to change red color of each. 27 | for (let x = 0; x < w; x++) { 28 | for (let y = 0; y < h; y++) { 29 | let index = (x + (y * w)) * 4; 30 | data[index] = data[index] * 1.2; 31 | } 32 | } 33 | 34 | postMessage(imageData, [imageData.data.buffer]) 35 | }); 36 | -------------------------------------------------------------------------------- /swipeable-cards/cards.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | html, body { 18 | margin: 0; 19 | padding: 0; 20 | background: #FAFAFA; 21 | font-family: Arial; 22 | font-size: 30px; 23 | color: #333; 24 | } 25 | 26 | body { 27 | overflow-x: hidden; 28 | } 29 | 30 | * { 31 | box-sizing: border-box; 32 | } 33 | 34 | .card-container { 35 | width: 100%; 36 | max-width: 450px; 37 | padding: 16px; 38 | margin: 0 auto; 39 | } 40 | 41 | .card { 42 | background: #FFF; 43 | border-radius: 3px; 44 | box-shadow: 0 3px 4px rgba(0,0,0,0.3); 45 | margin: 20px 0; 46 | height: 120px; 47 | display: flex; 48 | align-items: center; 49 | justify-content: space-around; 50 | cursor: pointer; 51 | } 52 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/components/sc-comment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import { SCElement } from './sc-element.js'; 18 | 19 | const html = String.raw; 20 | 21 | export class Comment extends SCElement { 22 | static template(state) { 23 | return html` 24 |
25 | Profile Photo 26 |
${state.authorName}
27 |
28 |
${state.text}
29 | `; 30 | } 31 | static component(state, id) { 32 | return html` 33 | 34 | ${this.template(state)} 35 | 36 | `; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /streaming-service-worker/server/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const del = require('del'); 3 | const nunjucks = require('nunjucks'); 4 | const app = express(); 5 | 6 | const rev = require('./rev'); 7 | 8 | app.set('view engine', 'njk'); 9 | 10 | const nunjucksEnv = nunjucks.configure(__dirname + '/../templates', { 11 | watch: true, 12 | express: app 13 | }); 14 | 15 | require('nunjucks-date-filter').install(nunjucksEnv); 16 | nunjucksEnv.addFilter('rev', str => rev.get(str)); 17 | 18 | app.use(require('./routes')); 19 | 20 | // Rev static files 21 | (async function() { 22 | const staticRevPath = `${__dirname}/../static-rev`; 23 | await del(staticRevPath); 24 | await rev.copyAndRev(`${__dirname}/../static`, '**', staticRevPath); 25 | await rev.addAndRev('offline-inc.html', staticRevPath, nunjucksEnv.render('offline-inc.njk')); 26 | 27 | const shell = nunjucksEnv.render('shell.njk'); 28 | const splitAt = ''; 29 | 30 | await rev.addAndRev('shell-start.html', staticRevPath, shell.slice(0, shell.indexOf(splitAt))); 31 | await rev.addAndRev('shell-end.html', staticRevPath, shell.slice(shell.indexOf(splitAt) + splitAt.length)); 32 | await rev.replaceInFiles(`${__dirname}/../static-rev/**/*.css`); 33 | 34 | app.listen(3000, () => { 35 | console.log('Example app listening on port 3000!'); 36 | }); 37 | })(); -------------------------------------------------------------------------------- /3d-card-flip/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 3D Card Flip 19 | 20 | 21 | 22 | 23 |
24 |
25 | 26 |
27 |

Supercharged

28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /custom-scrollbar/index.html: -------------------------------------------------------------------------------- 1 | 2 | 36 |
37 |
Lorem
38 |
ipsum
39 |
dolor
40 |
sit
41 |
amet,
42 |
consectetur
43 |
adipiscing
44 |
elit
45 |
46 | 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to become a contributor and submit your own code 2 | 3 | ## Contributor License Agreements 4 | 5 | We'd love to accept your sample apps and patches! Before we can take them, we have to jump a couple of legal hurdles. 6 | 7 | Please fill out either the individual or corporate Contributor License Agreement (CLA). 8 | * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](https://developers.google.com/open-source/cla/individual). 9 | * If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA](https://developers.google.com/open-source/cla/corporate). 10 | 11 | Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to 12 | accept your pull requests. 13 | 14 | ## Contributing A Patch 15 | 16 | 1. Submit an issue describing your proposed change to the repo in question. 17 | 1. The repo owner will respond to your issue promptly. 18 | 1. If your proposed change is accepted, and you haven't already done so, sign a Contributor License Agreement (see details above). 19 | 1. Fork the desired repo, develop and test your code changes. 20 | 1. Ensure that your code adheres to the existing style in the sample to which you are contributing. 21 | 1. Submit a pull request. 22 | -------------------------------------------------------------------------------- /accordion/sc-pane.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCPane extends HTMLElement { 21 | 22 | get header () { 23 | if (!this._header) { 24 | this._header = this.querySelector('button[role="tab"]'); 25 | } 26 | 27 | return this._header; 28 | } 29 | 30 | get content () { 31 | if (!this._content) { 32 | this._content = this.querySelector('.content'); 33 | } 34 | 35 | return this._content; 36 | } 37 | 38 | connectedCallback () { 39 | this.header.addEventListener('click', _ => { 40 | const customEvent = new CustomEvent('panel-change', { 41 | bubbles: true 42 | }); 43 | 44 | this.dispatchEvent(customEvent); 45 | }); 46 | } 47 | } 48 | 49 | customElements.define('sc-pane', SCPane); 50 | -------------------------------------------------------------------------------- /flip-switch/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | Polymer Summit 19 | 20 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /swipeable-cards/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Swipeable cards 22 | 23 | 24 | 25 |
26 |
Das Surma
27 |
Aerotwist
28 |
Kinlanimus Maximus
29 |
Addyoooooooooo
30 |
Gaunty McGaunty Gaunt
31 |
Jack Archibungle
32 |
Sam "The Dutts" Dutton
33 |
34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /image-zoomer/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Image Zoomer 22 | 23 | 24 | 25 | 26 | 27 |
28 |

Image Zoomer

29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 | 39 |
40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /streaming-service-worker/templates/who-inc.njk: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Jake Archibald

4 |
5 | 6 |

7 | Hello, I’m Jake and that is my face. I’m a developer advocate for Google Chrome. 8 |

9 | 10 |

Elsewhere

11 | 43 |

Contact

44 |

45 | Feel free to 46 | throw me an email, 47 | unless you're a recruiter, in which case destroy every email-capable 48 | device you own to prevent this possibility. 49 |

50 |
-------------------------------------------------------------------------------- /template/element.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2015 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | margin: 0; 24 | padding: 0; 25 | width: 100%; 26 | height: 100%; 27 | background: #FAFAFA; 28 | font-family: 'Roboto', Arial, sans-serif; 29 | } 30 | 31 | body { 32 | display: flex; 33 | flex-direction: column; 34 | } 35 | 36 | .header { 37 | width: 100%; 38 | height: 56px; 39 | color: #FFF; 40 | background: #607D8B; 41 | font-size: 20px; 42 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14), 43 | 0 2px 9px 1px rgba(0,0,0,.12), 44 | 0 4px 2px -2px rgba(0,0,0,.2); 45 | padding: 16px 16px 0; 46 | position: relative; 47 | z-index: 1; 48 | } 49 | 50 | .header__title { 51 | font-weight: 400; 52 | font-size: 20px; 53 | margin: 0; 54 | } 55 | 56 | .main { 57 | flex: 1; 58 | overflow-x: hidden; 59 | overflow-y: scroll; 60 | padding: 16px; 61 | position: relative; 62 | z-index: 0; 63 | } 64 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/components/sc-comment-form.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import { SCElement } from './sc-element.js'; 18 | 19 | const html = String.raw; 20 | 21 | export class CommentForm extends SCElement { 22 | static template() { 23 | return html` 24 | 25 | 26 | `; 27 | } 28 | static component() { 29 | return html` 30 | 31 | ${this.template()} 32 | 33 | `; 34 | } 35 | connectedCallback() { 36 | this.btnSend = this.querySelector('#btnSend'); 37 | this.textarea = this.querySelector('textarea'); 38 | this.btnSend.addEventListener('click', e => { 39 | const text = this.textarea.value; 40 | const detail = { text }; 41 | const event = new CustomEvent('comment-sent', { detail }); 42 | this.dispatchEvent(event); 43 | this.textarea.value = ''; 44 | }); 45 | } 46 | } -------------------------------------------------------------------------------- /firebase-firestore-comments/src/components/sc-login.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | const html = String.raw; 19 | 20 | export class LoginButton extends HTMLElement { 21 | static template() { 22 | return html` 23 | 24 | `; 25 | } 26 | connectedCallback() { 27 | this.appendChild(template.content.cloneNode(true)); 28 | this.auth = firebase.auth(); 29 | this.btnLogin = this.querySelector('#btnLogin'); 30 | 31 | this.auth.onAuthStateChanged(user => { 32 | const event = new CustomEvent('on-auth', { detail: user }); 33 | this.user = user; 34 | this.dispatchEvent(event); 35 | }); 36 | 37 | this.btnLogin.addEventListener('click', e => { 38 | const google = new firebase.auth.GoogleAuthProvider(); 39 | this.auth.signInWithRedirect(google); 40 | }); 41 | } 42 | } 43 | 44 | let template = document.createElement('template'); 45 | template.innerHTML = LoginButton.template(); 46 | 47 | -------------------------------------------------------------------------------- /custom-scrollbar/step-6.html: -------------------------------------------------------------------------------- 1 | 2 | 38 |
39 |
40 | 41 |
42 | 63 | -------------------------------------------------------------------------------- /service-worker/app/static/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class App { 21 | constructor () { 22 | const router = document.querySelector('sc-router'); 23 | const links = Array.from(document.querySelectorAll('a')); 24 | 25 | function onClick (evt) { 26 | evt.preventDefault(); 27 | router.go(evt.target.href); 28 | } 29 | 30 | links.forEach(link => { 31 | link.addEventListener('click', onClick); 32 | }); 33 | } 34 | } 35 | 36 | (_ => new App())(); 37 | 38 | if ('serviceWorker' in navigator) { 39 | navigator.serviceWorker.register('/sw.js', {scope: '/'}); 40 | } 41 | 42 | window.addEventListener('offline', event => { 43 | document.body.classList.add('offline'); 44 | Array.from(document.querySelectorAll('nav a')) 45 | .forEach(link => { 46 | if(linkIsAvailableOffline(link)) 47 | link.classList.add('cached'); 48 | }); 49 | }); 50 | 51 | window.addEventListener('online', _ => { 52 | document.body.classList.remove('offline'); 53 | }); 54 | -------------------------------------------------------------------------------- /router/static/sc-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCView extends HTMLElement { 21 | get route () { 22 | return this.getAttribute('route') || null; 23 | } 24 | 25 | in (data) { 26 | return new Promise((resolve, reject) => { 27 | const onTransitionEnd = () => { 28 | this.removeEventListener('transitionend', onTransitionEnd); 29 | resolve(); 30 | }; 31 | 32 | this.classList.add('visible'); 33 | this.addEventListener('transitionend', onTransitionEnd); 34 | }); 35 | } 36 | 37 | out (data) { 38 | return new Promise((resolve, reject) => { 39 | const onTransitionEnd = () => { 40 | this.removeEventListener('transitionend', onTransitionEnd); 41 | resolve(); 42 | }; 43 | 44 | this.classList.remove('visible'); 45 | this.addEventListener('transitionend', onTransitionEnd); 46 | }); 47 | } 48 | 49 | update (data) { 50 | console.log(data); 51 | return Promise.resolve(); 52 | } 53 | } 54 | 55 | customElements.define('sc-view', SCView); 56 | -------------------------------------------------------------------------------- /service-worker/app/header.partial.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 32 | 33 | {{? it.item !== ""}} 34 | 35 | {{?}} 36 | {{? it.item !== "about"}} 37 | 38 | {{?}} 39 | {{? it.item !== "contact"}} 40 | 41 | {{?}} 42 | {{? it.item !== "misc"}} 43 | 44 | {{?}} 45 | -------------------------------------------------------------------------------- /animated-blur/badblur.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 66 |
67 | 68 | 69 | 70 | 71 |
72 | -------------------------------------------------------------------------------- /code-splitting/app/header.partial.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 25 | 33 | 34 | {{#ifNotEq item ""}} 35 | 36 | {{/ifNotEq}} 37 | {{#ifNotEq item "about"}} 38 | 39 | {{/ifNotEq}} 40 | {{#ifNotEq item "contact"}} 41 | 42 | {{/ifNotEq}} 43 | {{#ifNotEq item "misc"}} 44 | 45 | {{/ifNotEq}} 46 | -------------------------------------------------------------------------------- /service-worker/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAvpuvSqhGHlRAsDlIA6gdbhEeVDIFE0QXWCjei5lrarGmAlbb 3 | ZOowbtrB6WlzuJ9Z2yIfrxacyD5VvP8mRM4zoV2yX043IyfjkCFxbixqGmJmR/jq 4 | MIegsE6CsQ4jhsrYRKQV5ADCPU/zty7gM9jwr7EVPdA1/Zifbmgb6amjnuGeyaRF 5 | 08Vdj7gdm7TKVF++Cc3vfZXbWu5/pcTw5OwbY7cfFAu1agMdEr+nrVwTH4ZCBykI 6 | FQI9YgvLntOf3qkvlX8VXLmRUNnG+vXeu7Zo567i5SJo6tZyOUZ7crZWpEW/Zr1M 7 | bYt+XSRXUUmCI19WKV7OhBGNARl3XZ69UGa5vQIDAQABAoIBAQCsDu8aLnI1OIq4 8 | SMzX+C6wx6UgDZMFRCbqfuH9E/2h70DSxcMAAmK7/p6ia315f+bl55TAQWI/Y/2T 9 | QKMz4ws6M9ErNPiStJQ36+hvsooIzSBVAb2tFxEXdZeF6iRprbuxoojcK08rd3uh 10 | tR/PzZnejrSE+ulxxQ7N5A6mS2qWpLbjkIKAVqu4iyRASdUNblZ5bjxv/eZ5n1U/ 11 | oXV6pyG3MxSItOsC9/x19IihkUWi2hRTTdOsx+sLgQNvJ6OULlHmnfOUuyWMqqZ7 12 | sZ6uCsgIICGndRCsTguX4cNeGmn/pi8yqmZyZ4zQ4PSkV7jmlNG/BrYHCeUHQB+L 13 | tzBRwwMBAoGBAOQ+DvTFA18FunD0+pSMes/iDPFd1QHcqf4v5/BUjYdRCG+U5jc5 14 | nWY/qhvUZKUBND0Ihr95FxVjQIQiXwCDerKVqATofjfXZd6prWM7JqY0pjBuIJvB 15 | vVxgA5O9eLVevCbpG9mHW4eKVoMhugQG5D0OXOzbI5Lb9FxPx+k1hOH9AoGBANXJ 16 | 8mfayTHXwxriM6RTUIVZO9U5vMemQLy27h7gWCeyt1vPv+ArM0F3xODOLc5vd7FB 17 | SFyq+rsjwxnS0wHAaB+e0V98OtrgB/LmkQ3n1MJll24xyvGCKOkqQjP4C//d2Yjx 18 | ffovYBd3h2C39MOM6znoQkWULRUI0VEPSjvUw+LBAoGBAKWW7IzinnaDFme7JE0/ 19 | uh42F0PJ2q8WI/K5WOHAxkllHeSuN3PbhflXuReluTsJK5gYJoKl3Hx03KrAsQIT 20 | YaJM93BQKLpkuJCZs6SplnnA+s1qKJg4MCTjt9SpAvk6+PCV8NGZ5Wrpj6hlgKpJ 21 | Qa+WSw7AUgfLMncCnrvwSy8VAoGBAK9U9AzgjejmvwgpQ5kdCwiR6lQxCfXjD2y1 22 | ygxgiWvlUiNl+kLqqxqiE0EbVs3a9RrWI3Z8cy1PYw6mrI7fMYXdRnE8/TfMTDiV 23 | h5kT7JWRo+OnynzO9qZjFfBxGcY6N9Hr3Bl3CSO1z70uoPpPdAsFxHQz1dVOafxE 24 | wejX0d8BAoGBALvbmjzPJVp4XZYw9VFpc2+7jxuc8WdYJGS+uYxtziJkoG31Aik3 25 | cjwTHtRRnaHPfGEqj0pTgvbm22OoQ5wlvV8vxUIVkO33C5Nljnfy0pSYoIodq8+4 26 | WNbp0PzZ77USIhe5XuEhEJX+NRpycNjCOI21psuPS1trjxqIkUw7r6JO 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /server-side-rendering/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAvpuvSqhGHlRAsDlIA6gdbhEeVDIFE0QXWCjei5lrarGmAlbb 3 | ZOowbtrB6WlzuJ9Z2yIfrxacyD5VvP8mRM4zoV2yX043IyfjkCFxbixqGmJmR/jq 4 | MIegsE6CsQ4jhsrYRKQV5ADCPU/zty7gM9jwr7EVPdA1/Zifbmgb6amjnuGeyaRF 5 | 08Vdj7gdm7TKVF++Cc3vfZXbWu5/pcTw5OwbY7cfFAu1agMdEr+nrVwTH4ZCBykI 6 | FQI9YgvLntOf3qkvlX8VXLmRUNnG+vXeu7Zo567i5SJo6tZyOUZ7crZWpEW/Zr1M 7 | bYt+XSRXUUmCI19WKV7OhBGNARl3XZ69UGa5vQIDAQABAoIBAQCsDu8aLnI1OIq4 8 | SMzX+C6wx6UgDZMFRCbqfuH9E/2h70DSxcMAAmK7/p6ia315f+bl55TAQWI/Y/2T 9 | QKMz4ws6M9ErNPiStJQ36+hvsooIzSBVAb2tFxEXdZeF6iRprbuxoojcK08rd3uh 10 | tR/PzZnejrSE+ulxxQ7N5A6mS2qWpLbjkIKAVqu4iyRASdUNblZ5bjxv/eZ5n1U/ 11 | oXV6pyG3MxSItOsC9/x19IihkUWi2hRTTdOsx+sLgQNvJ6OULlHmnfOUuyWMqqZ7 12 | sZ6uCsgIICGndRCsTguX4cNeGmn/pi8yqmZyZ4zQ4PSkV7jmlNG/BrYHCeUHQB+L 13 | tzBRwwMBAoGBAOQ+DvTFA18FunD0+pSMes/iDPFd1QHcqf4v5/BUjYdRCG+U5jc5 14 | nWY/qhvUZKUBND0Ihr95FxVjQIQiXwCDerKVqATofjfXZd6prWM7JqY0pjBuIJvB 15 | vVxgA5O9eLVevCbpG9mHW4eKVoMhugQG5D0OXOzbI5Lb9FxPx+k1hOH9AoGBANXJ 16 | 8mfayTHXwxriM6RTUIVZO9U5vMemQLy27h7gWCeyt1vPv+ArM0F3xODOLc5vd7FB 17 | SFyq+rsjwxnS0wHAaB+e0V98OtrgB/LmkQ3n1MJll24xyvGCKOkqQjP4C//d2Yjx 18 | ffovYBd3h2C39MOM6znoQkWULRUI0VEPSjvUw+LBAoGBAKWW7IzinnaDFme7JE0/ 19 | uh42F0PJ2q8WI/K5WOHAxkllHeSuN3PbhflXuReluTsJK5gYJoKl3Hx03KrAsQIT 20 | YaJM93BQKLpkuJCZs6SplnnA+s1qKJg4MCTjt9SpAvk6+PCV8NGZ5Wrpj6hlgKpJ 21 | Qa+WSw7AUgfLMncCnrvwSy8VAoGBAK9U9AzgjejmvwgpQ5kdCwiR6lQxCfXjD2y1 22 | ygxgiWvlUiNl+kLqqxqiE0EbVs3a9RrWI3Z8cy1PYw6mrI7fMYXdRnE8/TfMTDiV 23 | h5kT7JWRo+OnynzO9qZjFfBxGcY6N9Hr3Bl3CSO1z70uoPpPdAsFxHQz1dVOafxE 24 | wejX0d8BAoGBALvbmjzPJVp4XZYw9VFpc2+7jxuc8WdYJGS+uYxtziJkoG31Aik3 25 | cjwTHtRRnaHPfGEqj0pTgvbm22OoQ5wlvV8vxUIVkO33C5Nljnfy0pSYoIodq8+4 26 | WNbp0PzZ77USIhe5XuEhEJX+NRpycNjCOI21psuPS1trjxqIkUw7r6JO 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /side-nav/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Side Nav 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | 29 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UI Elements 2 | 3 | A collection of UI element samples written with vanilla web platform features. 4 | 5 | **Please note: these are prototypes, and not production-ready. The aim is to demonstrate a solid approach for building performant UI elements.** 6 | 7 | ## Getting started 8 | 9 | 1. Clone the repo. 10 | 2. Open an element's subfolder. 11 | 3. Run index.html 12 | 13 | ## ES2015 and ES5 Transpilation 14 | 15 | Please note: these samples are written in ES2015 and, as such, require [direct browser support](https://kangax.github.io/compat-table/es6/). You can transpile the examples with [BabelJS](https://babeljs.io/docs/usage/cli/): 16 | 17 | ```bash 18 | babel --presets=es2015 swipeable-cards/cards.js --out-file swipeable-cards/cards-es5.js 19 | babel --presets=es2015 side-nav/side-nav.js --out-file side-nav/side-nav-es5.js 20 | ``` 21 | 22 | But to keep things as simple as possible for everyone, that's out of scope for this set of samples. 23 | 24 | ## License 25 | 26 | Copyright 2015 Google, Inc. 27 | 28 | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at 29 | 30 | http://www.apache.org/licenses/LICENSE-2.0 31 | 32 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 33 | 34 | Please note: this is not a Google product 35 | -------------------------------------------------------------------------------- /infinite-scroller/stats.min.js: -------------------------------------------------------------------------------- 1 | // stats.js - http://github.com/mrdoob/stats.js 2 | var Stats=function(){function h(a){c.appendChild(a.dom);return a}function k(a){for(var d=0;de+1E3&&(r.update(1E3*a/(c-e),100),e=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){g=this.end()},domElement:c,setMode:k}}; 4 | Stats.Panel=function(h,k,l){var c=Infinity,g=0,e=Math.round,a=e(window.devicePixelRatio||1),r=80*a,f=48*a,t=3*a,u=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=f;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,f);b.fillStyle=k;b.fillText(h,t,u);b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(f, 5 | v){c=Math.min(c,f);g=Math.max(g,f);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=k;b.fillText(e(f)+" "+h+" ("+e(c)+"-"+e(g)+")",t,u);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,e((1-f/v)*p))}}};"object"===typeof module&&(module.exports=Stats); 6 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/client/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import { LoginButton } from './components/sc-login.js'; 18 | import { CommentForm } from './components/sc-comment-form.js'; 19 | import { CommentList } from './components/sc-comment-list.js'; 20 | import { Comment } from './components/sc-comment.js'; 21 | 22 | customElements.define('sc-login', LoginButton); 23 | customElements.define('sc-comment-form', CommentForm); 24 | customElements.define('sc-comment-list', CommentList); 25 | customElements.define('sc-comment', Comment); 26 | 27 | const scLogin = document.querySelector('sc-login'); 28 | const scForm = document.querySelector('sc-comment-form'); 29 | 30 | scForm.addEventListener('comment-sent', e => { 31 | const commentsRef = firebase.firestore().collection('comments'); 32 | commentsRef.add({ 33 | text: e.detail.text, 34 | photoUrl: scLogin.user.photoURL, 35 | authorName: scLogin.user.displayName, 36 | timestamp: firebase.firestore.FieldValue.serverTimestamp() 37 | }); 38 | }); 39 | 40 | scLogin.addEventListener('on-auth', e => { 41 | if(e.detail) { 42 | scLogin.classList.add('sc-hidden'); 43 | } else { 44 | scLogin.classList.remove('sc-hidden'); 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /animated-blur/goodblur.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 64 |
65 |
66 | 67 |
68 |
69 | 70 |
71 |
72 | 73 |
74 |
75 | 76 |
77 |
78 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/components/sc-comment-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | import { SCElement } from './sc-element.js'; 18 | import { Comment } from './sc-comment.js'; 19 | 20 | const html = String.raw; 21 | 22 | export class CommentList extends SCElement { 23 | static component(state) { 24 | return html` 25 | 26 | ${state} 27 | 28 | `; 29 | } 30 | 31 | connectedCallback() { 32 | this.commentsRef = firebase.firestore().collection('comments'); 33 | this.commentsRef.orderBy('timestamp').onSnapshot(snap => { 34 | snap.docChanges.forEach(change => { 35 | const elInDOM = this.querySelector(`#_${change.doc.id}`); 36 | switch(change.type) { 37 | case 'added': 38 | if(elInDOM) { return; } 39 | this.addComment(change.doc); 40 | break; 41 | case 'removed': 42 | elInDOM.remove(); 43 | break; 44 | } 45 | }); 46 | }); 47 | } 48 | 49 | addComment(doc) { 50 | const element = document.createElement('sc-comment'); 51 | element.id = `_${doc.id}`; 52 | element.innerHTML = Comment.template(doc.data()); 53 | this.appendChild(element); 54 | } 55 | } -------------------------------------------------------------------------------- /animated-clip/advanced/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 |
25 |
26 |
27 |
    28 |
  • One
  • 29 |
  • Two
  • 30 |
  • Three
  • 31 |
  • Four
  • 32 |
33 | 34 | 35 |
36 | 37 | 43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /server-side-rendering/app/header.partial.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 | {{#ifNotEq item ""}} 38 | 39 | {{/ifNotEq}} 40 | {{#ifNotEq item "about"}} 41 | 42 | {{/ifNotEq}} 43 | {{#ifNotEq item "contact"}} 44 | 45 | {{/ifNotEq}} 46 | {{#ifNotEq item "misc"}} 47 | 48 | {{/ifNotEq}} 49 | -------------------------------------------------------------------------------- /router-advanced/misc/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 | 38 | 39 | 40 | Misc 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /router-advanced/contact/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 | 38 | 39 | Contact 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /router-advanced/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 |
Home
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /router-advanced/about/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 36 | 37 | 38 |
About
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /router/static/superstyles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | padding: 0; 24 | margin: 0; 25 | font-size: 24px; 26 | font-family: Arial, sans-serif; 27 | } 28 | 29 | sc-view { 30 | contain: strict; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: 100%; 35 | height: 100%; 36 | opacity: 0; 37 | pointer-events: none; 38 | transform: scale(0.95); 39 | transition: transform 0.3s cubic-bezier(0,0,0.3,1), 40 | opacity 0.3s cubic-bezier(0,0,0.3,1); 41 | font-size: 20vh; 42 | display: flex; 43 | flex-direction: row; 44 | justify-content: center; 45 | align-items: center; 46 | color: white; 47 | } 48 | 49 | sc-view.visible { 50 | opacity: 1; 51 | pointer-events: auto; 52 | transform: none; 53 | } 54 | 55 | .view-home { 56 | background: rgb(128,00,64); 57 | } 58 | 59 | .view-contact { 60 | background: rgb(00,128,64); 61 | } 62 | 63 | .view-about { 64 | background: rgb(00,64,128); 65 | } 66 | 67 | .view-misc { 68 | background: rgb(128,64,0); 69 | } 70 | 71 | nav { 72 | position: fixed; 73 | right: 10px; 74 | top: 10px; 75 | background: #FFF; 76 | box-shadow: 0 2px 4px rgba(0,0,0,0.3); 77 | padding: 10px 30px 10px 10px; 78 | border-radius: 3px; 79 | z-index: 1; 80 | } 81 | -------------------------------------------------------------------------------- /image-zoomer/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | padding: 0; 24 | margin: 0; 25 | background-color: #FAFAFA; 26 | width: 100%; 27 | height: 100%; 28 | overflow: hidden; 29 | font-family: 'Roboto', Arial, sans-serif; 30 | } 31 | 32 | body { 33 | display: flex; 34 | flex-direction: column; 35 | } 36 | 37 | .header { 38 | width: 100%; 39 | height: 56px; 40 | color: #FFF; 41 | background: #607D8B; 42 | font-size: 20px; 43 | box-shadow: 0 4px 5px 0 rgba(0,0,0,.14), 44 | 0 2px 9px 1px rgba(0,0,0,.12), 45 | 0 4px 2px -2px rgba(0,0,0,.2); 46 | padding: 16px 16px 0; 47 | position: relative; 48 | z-index: 1; 49 | } 50 | 51 | .header__title { 52 | font-weight: 400; 53 | font-size: 20px; 54 | margin: 0; 55 | } 56 | 57 | .main { 58 | flex: 1; 59 | padding: 16px; 60 | overflow-x: hidden; 61 | overflow-y: scroll; 62 | position: relative; 63 | width: 100%; 64 | display: flex; 65 | justify-content: space-around; 66 | } 67 | 68 | .main img { 69 | width: 100%; 70 | max-width: 650px; 71 | cursor: zoom-in; 72 | } 73 | 74 | .zoomer { 75 | width: 1px; 76 | height: 1px; 77 | position: fixed; 78 | left: 0; 79 | top: 0; 80 | pointer-events: none; 81 | } 82 | 83 | .zoomer__canvas { 84 | position: absolute; 85 | left: -64px; 86 | top: -134px; 87 | } 88 | -------------------------------------------------------------------------------- /accordion/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | margin: 0; 24 | padding: 0; 25 | height: 100vh; 26 | width: 100vw; 27 | font-family: Arial, Helvetica, sans-serif; 28 | } 29 | 30 | body { 31 | display: flex; 32 | flex-direction: column; 33 | align-items: center; 34 | justify-content: center; 35 | background: #EEE; 36 | } 37 | 38 | sc-accordion { 39 | width: 100%; 40 | max-width: 450px; 41 | box-shadow: 0 3px 4px rgba(0,0,0,0.4); 42 | background: #FFF; 43 | border-radius: 3px; 44 | } 45 | 46 | sc-accordion[enhanced] { 47 | visibility: hidden; 48 | height: 600px; 49 | overflow: hidden; 50 | position: relative; 51 | } 52 | 53 | sc-accordion[enhanced] sc-pane { 54 | position: absolute; 55 | top: 0; 56 | width: 100%; 57 | } 58 | 59 | sc-accordion[active] { 60 | visibility: visible; 61 | } 62 | 63 | sc-accordion[active] sc-pane { 64 | transition: transform 0.3s cubic-bezier(0, 0, 0.3, 1); 65 | } 66 | 67 | sc-pane button[role="tab"] { 68 | width: 100%; 69 | height: 48px; 70 | line-height: 48px; 71 | border: none; 72 | font-size: 16px; 73 | background: #666; 74 | color: #FFF; 75 | border-bottom: 1px solid #444; 76 | } 77 | 78 | sc-pane button[role="tab"]:focus { 79 | background: #333; 80 | } 81 | 82 | sc-pane .content { 83 | padding: 16px; 84 | overflow-y: scroll; 85 | background-color: #FFF; 86 | } 87 | -------------------------------------------------------------------------------- /lazy-image/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2017 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | const Express = require('express'); 18 | const fs = require('fs'); 19 | const {promisify} = require('util'); 20 | const readFile = promisify(fs.readFile); 21 | const im = require('gm').subClass({imageMagick: true}); 22 | const app = Express(); 23 | 24 | const thumbSize = 16; 25 | 26 | app.get('/', async (req, res) => { 27 | let filepath = req.url; 28 | if(filepath.endsWith('/')) 29 | filepath += 'index.html'; 30 | const buffer = await readFile('./static/'+filepath); 31 | const content = buffer.toString(); 32 | const newContent = await Promise.all( 33 | content 34 | .split(/(]+><\/sc-img>)/) 35 | .map(async item => { 36 | if(!item.startsWith('', `style="padding-top: ${height/width*100}%; background-image: url(${thumbURL});">`); 46 | }) 47 | ); 48 | res.send(newContent.join('')); 49 | }); 50 | app.use(Express.static('static')); 51 | app.listen(8080); 52 | -------------------------------------------------------------------------------- /animated-blur/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 18 | 19 | 78 | -------------------------------------------------------------------------------- /infinite-scroller/styles/messages.css: -------------------------------------------------------------------------------- 1 | #chat-timeline { 2 | margin: 0; 3 | padding: 0; 4 | overflow-x: hidden; 5 | overflow-y: scroll; 6 | -webkit-overflow-scrolling: touch; 7 | width: 100%; 8 | height: 100%; 9 | position: absolute; 10 | box-sizing: border-box; 11 | contain: layout; 12 | will-change: transform; 13 | } 14 | 15 | .chat-item { 16 | display: flex; 17 | padding: 10px 0; 18 | width: 100%; 19 | contain: layout; 20 | will-change: transform; 21 | } 22 | 23 | .avatar { 24 | border-radius: 500px; 25 | margin-left: 20px; 26 | margin-right: 6px; 27 | min-width: 48px; 28 | } 29 | 30 | .chat-item p { 31 | margin: 0; 32 | word-wrap: break-word; 33 | font-size: 13px; 34 | } 35 | 36 | .chat-item.tombstone p { 37 | width: 100%; 38 | height: 0.5em; 39 | background-color: #ccc; 40 | margin: 0.5em 0; 41 | } 42 | 43 | .chat-item .bubble img { 44 | max-width: 100%; 45 | height: auto; 46 | } 47 | 48 | .bubble { 49 | padding: 7px 10px; 50 | color: #333; 51 | background: #fff; 52 | box-shadow: 0 3px 2px rgba(0,0,0,0.1); 53 | position: relative; 54 | max-width: 420px; 55 | min-width: 80px; 56 | margin: 0 5px; 57 | } 58 | 59 | .bubble::before { 60 | content: ''; 61 | border-style: solid; 62 | border-width: 0 10px 10px 0; 63 | border-color: transparent #fff transparent transparent; 64 | position: absolute; 65 | top: 0; 66 | left: -10px; 67 | } 68 | 69 | /*.bubble img { 70 | width: 80%; 71 | }*/ 72 | 73 | .meta { 74 | font-size: 0.8rem; 75 | color: #999; 76 | margin-top: 3px; 77 | } 78 | 79 | .from-me { 80 | justify-content: flex-end; 81 | } 82 | 83 | .from-me .avatar { 84 | order: 1; 85 | margin-left: 6px; 86 | margin-right: 20px; 87 | } 88 | 89 | .from-me .bubble { 90 | background: #F9D7FF; 91 | } 92 | 93 | .from-me .bubble::before { 94 | left: 100%; 95 | border-width: 10px 10px 0 0; 96 | border-color: #F9D7FF transparent transparent transparent; 97 | } 98 | .state { 99 | display: none; 100 | } 101 | .invisible { 102 | display: none; 103 | } 104 | -------------------------------------------------------------------------------- /router/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | Router 21 | 22 | 23 | 24 | 32 | 33 | 34 | Home 35 | 36 | 37 | 38 | About 39 | 40 | 41 | 42 | Contact 43 | 44 | 45 | 46 | Misc 47 | 48 | 49 | 50 | 51 | 52 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /expand-collapse/index.html: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Expand + Collapse 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 |
36 | 37 |
38 |

Item Title

39 |
40 | 41 |
42 |
    43 |
  • List item 1
  • 44 |
  • List item 2
  • 45 |
  • List item 3
  • 46 |
  • List item 4
  • 47 |
  • List item 5
  • 48 |
  • List item 6
  • 49 |
  • List item 7
  • 50 |
  • List item 8
  • 51 |
  • List item 9
  • 52 |
  • List item 10
  • 53 |
  • List item 11
  • 54 |
  • List item 12
  • 55 |
  • List item 13
  • 56 |
  • List item 14
  • 57 |
  • List item 15
  • 58 |
  • List item 16
  • 59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /lazy-image/static/sc-img.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2017 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | const template = document.createElement('template'); 18 | template.innerHTML = ` 19 | 40 | `; 41 | 42 | const io = new IntersectionObserver(entries => { 43 | for(const entry of entries) { 44 | if(entry.isIntersecting) { 45 | entry.target.setAttribute('full', ''); 46 | } 47 | } 48 | }); 49 | 50 | class SCImg extends HTMLElement { 51 | static get observedAttributes() { 52 | return ['full']; 53 | } 54 | 55 | constructor() { 56 | super(); 57 | this.attachShadow({mode: 'open'}); 58 | this.shadowRoot.appendChild(template.content.cloneNode(true)); 59 | } 60 | 61 | connectedCallback() { 62 | io.observe(this); 63 | } 64 | 65 | disconnectedCallback() { 66 | io.unobserve(this); 67 | } 68 | 69 | get full() { 70 | return this.hasAttribute('full'); 71 | } 72 | 73 | get src() { 74 | return this.getAttribute('src'); 75 | } 76 | 77 | attributeChangedCallback() { 78 | if(this.loaded) 79 | return; 80 | const img = document.createElement('img'); 81 | img.src = this.src; 82 | img.onload = _ => { 83 | this.loaded = true; 84 | this.shadowRoot.appendChild(img); 85 | }; 86 | } 87 | } 88 | 89 | customElements.define('sc-img', SCImg); 90 | -------------------------------------------------------------------------------- /side-nav/detabinator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 19 | /** 20 | * Usage: 21 | * const detabinator = new Detabinator(element); 22 | * detabinator.inert = true; // Sets all focusable children of element to tabindex=-1 23 | * detabinator.inert = false; // Restores all focusable children of element 24 | * Limitations: Doesn't support Shadow DOM v0 :P 25 | */ 26 | 27 | class Detabinator { 28 | constructor(element) { 29 | if (!element) { 30 | throw new Error('Missing required argument. new Detabinator needs an element reference'); 31 | } 32 | this._inert = false; 33 | this._focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex], [contenteditable]'; 34 | this._focusableElements = Array.from( 35 | element.querySelectorAll(this._focusableElementsString) 36 | ); 37 | } 38 | 39 | get inert() { 40 | return this._inert; 41 | } 42 | 43 | set inert(isInert) { 44 | if (this._inert === isInert) { 45 | return; 46 | } 47 | 48 | this._inert = isInert; 49 | 50 | this._focusableElements.forEach((child) => { 51 | if (isInert) { 52 | // If the child has an explict tabindex save it 53 | if (child.hasAttribute('tabindex')) { 54 | child.__savedTabindex = child.tabIndex; 55 | } 56 | // Set ALL focusable children to tabindex -1 57 | child.setAttribute('tabindex', -1); 58 | } else { 59 | // If the child has a saved tabindex, restore it 60 | // Because the value could be 0, explicitly check that it's not false 61 | if (child.__savedTabindex === 0 || child.__savedTabindex) { 62 | return child.setAttribute('tabindex', child.__savedTabindex); 63 | } else { 64 | // Remove tabindex from ANY REMAINING children 65 | child.removeAttribute('tabindex'); 66 | } 67 | } 68 | }); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/server/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2018 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | const functions = require('firebase-functions'); 18 | const express = require('express'); 19 | const firebase = require('firebase/app'); 20 | const fs = require('fs'); 21 | require('firebase/firestore'); 22 | 23 | const router = express.Router(); 24 | const indexHtml = fs.readFileSync(`${__dirname}/index.html`, 'utf8'); 25 | const firebaseApp = firebase.initializeApp({ 26 | apiKey: "AIzaSyAs7CmNcvBSO-h14AgE8O_Ii9durQHvx0c", 27 | authDomain: "supercharged-comments.firebaseapp.com", 28 | databaseURL: "https://supercharged-comments.firebaseio.com", 29 | projectId: "supercharged-comments", 30 | storageBucket: "supercharged-comments.appspot.com", 31 | messagingSenderId: "116806762306" 32 | }); 33 | 34 | const { CommentForm } = require('./components/sc-comment-form'); 35 | const { CommentList } = require('./components/sc-comment-list'); 36 | const { Comment } = require('./components/sc-comment'); 37 | 38 | function pageBuilder(page) { 39 | return { 40 | page, 41 | replace(holder, replacement) { 42 | this.page = this.page.replace(holder, replacement); 43 | }, 44 | addCommentForm() { 45 | this.replace('', CommentForm.component()); 46 | return this; 47 | }, 48 | addCommentList(state) { 49 | const comments = state.map(c => Comment.component(c, c.id)).join(''); 50 | this.replace('', CommentList.component(comments)); 51 | return this; 52 | }, 53 | build() { 54 | return this.page; 55 | } 56 | } 57 | } 58 | 59 | router.get('/', (req, res) => { 60 | const commentsRef = firebase.firestore().collection('comments'); 61 | commentsRef.orderBy('timestamp').get().then(snap => { 62 | const state = snap.docs.map(d => Object.assign(d.data(), { id: d.id })); 63 | const page = pageBuilder(indexHtml) 64 | .addCommentForm() 65 | .addCommentList(state) 66 | .build(); 67 | res.send(page); 68 | }); 69 | }); 70 | 71 | exports.supercharged = functions.https.onRequest(router); 72 | -------------------------------------------------------------------------------- /service-worker/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * 5 | * Copyright 2016 Google Inc. All rights reserved. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 'use strict'; 21 | 22 | const express = require('express'); 23 | const fs = require('mz/fs'); 24 | const dot = require('dot'); 25 | dot.templateSettings.strip = false; 26 | 27 | const crypto = require('crypto'); 28 | 29 | const app = express(); 30 | app.use('/node_modules', express.static('node_modules')); 31 | // Matches paths like `/`, `/index.html`, `/about/` or `/about/index.html`. 32 | const toplevelSection = /([^/]*)(\/|\/index.html)$/; 33 | app.get(toplevelSection, (req, res) => { 34 | // Extract the menu item name from the path and attach it to 35 | // the request to have it available for template rendering. 36 | req.item = req.params[0]; 37 | 38 | // If the request has `?partial`, don't render header and footer. 39 | let files; 40 | if ('partial' in req.query) { 41 | files = [fs.readFile(`app/${req.item}/index.html`)]; 42 | } else { 43 | files = [ 44 | fs.readFile('app/header.partial.html'), 45 | fs.readFile(`app/${req.item}/index.html`), 46 | fs.readFile('app/footer.partial.html') 47 | ]; 48 | } 49 | 50 | Promise.all(files) 51 | .then(files => files.map(f => f.toString('utf-8'))) 52 | .then(files => files.map(f => dot.template(f)(req))) 53 | .then(files => { 54 | const content = files.join(''); 55 | // Let's use sha256 as a means to get an ETag 56 | const hash = crypto 57 | .createHash('sha256') 58 | .update(content) 59 | .digest('hex'); 60 | 61 | res.set({ 62 | 'ETag': hash, 63 | 'Cache-Control': 'public, no-cache' 64 | }); 65 | res.send(content); 66 | }) 67 | .catch(error => res.status(500).send(error.toString())); 68 | }); 69 | app.use(express.static('app')); 70 | 71 | // Self-signed certificate generated by `simplehttp2server` 72 | // @see https://github.com/GoogleChrome/simplehttp2server 73 | const options = { 74 | key: fs.readFileSync('key.pem'), 75 | cert: fs.readFileSync('cert.pem') 76 | }; 77 | // It says spdy, but it's actually HTTP/2 :) 78 | require('http').createServer(app).listen(8081); 79 | -------------------------------------------------------------------------------- /3d-card-flip/styles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | margin: 0; 24 | padding: 0; 25 | width: 100%; 26 | height: 100%; 27 | font-family: Arial, Helvetica, sans-serif; 28 | } 29 | 30 | body { 31 | display: flex; 32 | align-items: center; 33 | justify-content: center; 34 | background: #E2E2E2; 35 | overflow-x: hidden; 36 | overflow-y: scroll; 37 | } 38 | 39 | sc-card { 40 | width: 260px; 41 | height: 380px; 42 | position: relative; 43 | perspective: 500px; 44 | will-change: transform; 45 | } 46 | 47 | sc-card .front, 48 | sc-card .back { 49 | backface-visibility: hidden; 50 | position: absolute; 51 | width: 100%; 52 | height: 100%; 53 | display: flex; 54 | align-items: center; 55 | justify-content: center; 56 | border-radius: 3px; 57 | overflow: hidden; 58 | } 59 | 60 | sc-card button { 61 | position: absolute; 62 | top: 0; 63 | left: 0; 64 | width: 100%; 65 | height: 100%; 66 | background: none; 67 | border: none; 68 | text-indent: -10000px; 69 | /*display: none;*/ 70 | } 71 | 72 | sc-card .front { 73 | background: #444; 74 | color: #FFF; 75 | } 76 | 77 | sc-card .front h1 { 78 | font-size: 24px; 79 | } 80 | 81 | sc-card .back { 82 | background: url(images/supercharged.jpg) center center no-repeat; 83 | color: #FFF; 84 | transform: rotateY(180deg); 85 | } 86 | 87 | sc-card .umbra, 88 | sc-card .penumbra { 89 | width: 100%; 90 | height: 100%; 91 | position: absolute; 92 | top: 0; 93 | left: 0; 94 | backface-visibility: visible; 95 | } 96 | 97 | sc-card .umbra { 98 | width: 270px; 99 | height: 390px; 100 | top: -5px; 101 | left: -5px; 102 | background: url(images/umbra.svg) center center no-repeat; 103 | transform: translateY(2px); 104 | opacity: 0.3; 105 | } 106 | 107 | sc-card .penumbra { 108 | width: 330px; 109 | height: 450px; 110 | top: -35px; 111 | left: -35px; 112 | background: url(images/penumbra.svg) center center no-repeat; 113 | transform: translateY(2px); 114 | opacity: 0; 115 | } 116 | -------------------------------------------------------------------------------- /web-workers/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | SuperCharged 💫 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 |
26 | 27 | 28 | 29 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /streaming-service-worker/client/sw.js: -------------------------------------------------------------------------------- 1 | const toCache = require('static-to-cache')(); 2 | const version = require('static-version')(); 3 | const revGet = require('static-rev-get'); 4 | 5 | const staticCacheName = `static-${version}`; 6 | 7 | addEventListener('install', event => { 8 | skipWaiting(); 9 | 10 | event.waitUntil(async function () { 11 | const cache = await caches.open(staticCacheName); 12 | await cache.addAll(toCache); 13 | }()); 14 | }); 15 | 16 | addEventListener('activate', event => { 17 | event.waitUntil(async function () { 18 | const keys = await caches.keys(); 19 | await Promise.all( 20 | keys.map(key => { 21 | if (key !== staticCacheName) return caches.delete(key); 22 | }) 23 | ); 24 | }()); 25 | }); 26 | 27 | class IdentityStream { 28 | constructor() { 29 | let readableController; 30 | let writableController; 31 | 32 | this.readable = new ReadableStream({ 33 | start(controller) { 34 | readableController = controller; 35 | }, 36 | cancel(reason) { 37 | writableController.error(reason); 38 | } 39 | }); 40 | 41 | this.writable = new WritableStream({ 42 | start(controller) { 43 | writableController = controller; 44 | }, 45 | write(chunk) { 46 | readableController.enqueue(chunk); 47 | }, 48 | close() { 49 | readableController.close(); 50 | }, 51 | abort(reason) { 52 | readableController.error(reason); 53 | } 54 | }); 55 | } 56 | } 57 | 58 | async function streamArticle(event, url) { 59 | const includeUrl = new URL(url); 60 | includeUrl.pathname += 'include'; 61 | 62 | const parts = [ 63 | caches.match(revGet('/static/shell-start.html')), 64 | fetch(includeUrl).catch(() => caches.match(revGet('/static/offline-inc.html'))), 65 | caches.match(revGet('/static/shell-end.html')) 66 | ]; 67 | 68 | const identity = new IdentityStream(); 69 | 70 | event.waitUntil(async function() { 71 | for (const responsePromise of parts) { 72 | const response = await responsePromise; 73 | await response.body.pipeTo(identity.writable, { preventClose: true }); 74 | } 75 | identity.writable.getWriter().close(); 76 | }()); 77 | 78 | return new Response(identity.readable, { 79 | headers: { 'Content-Type': 'text/html; charset=utf-8' } 80 | }); 81 | } 82 | 83 | addEventListener('fetch', event => { 84 | if (event.request.method !== 'GET') return; 85 | const url = new URL(event.request.url); 86 | 87 | event.respondWith(async function () { 88 | if (url.origin === location.origin && /^\/\d{4}\/[\w-]+\/$/.test(url.pathname)) { 89 | return streamArticle(event, url); 90 | } 91 | 92 | const cachedReponse = await caches.match(event.request); 93 | if (cachedReponse) return cachedReponse; 94 | 95 | return await fetch(event.request); 96 | }()); 97 | }); -------------------------------------------------------------------------------- /server-side-rendering/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * 5 | * Copyright 2016 Google Inc. All rights reserved. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 'use strict'; 21 | 22 | const express = require('express'); 23 | const fs = require('mz/fs'); 24 | const handlebars = require('handlebars'); 25 | const crypto = require('crypto'); 26 | 27 | // Handlebars `if` only checks for truthy and falsy values, 28 | // so we have to write our own helper to check for equality (or inequality). 29 | handlebars.registerHelper('ifNotEq', function (a, b, opts) { 30 | if (a !== b) { 31 | return opts.fn(this); 32 | } 33 | }); 34 | 35 | const app = express(); 36 | // Matches paths like `/`, `/index.html`, `/about/` or `/about/index.html`. 37 | const toplevelSection = /([^/]*)(\/|\/index.html)$/; 38 | app.get(toplevelSection, (req, res) => { 39 | // Extract the menu item name from the path and attach it to 40 | // the request to have it available for template rendering. 41 | req.item = req.params[0]; 42 | 43 | // If the request has `?partial`, don't render header and footer. 44 | let files; 45 | if ('partial' in req.query) { 46 | files = [fs.readFile(`app/${req.item}/index.html`)]; 47 | } else { 48 | files = [ 49 | fs.readFile('app/header.partial.html'), 50 | fs.readFile(`app/${req.item}/index.html`), 51 | fs.readFile('app/footer.partial.html') 52 | ]; 53 | } 54 | 55 | Promise.all(files) 56 | .then(files => files.map(f => f.toString('utf-8'))) 57 | .then(files => files.map(f => handlebars.compile(f)(req))) 58 | .then(files => { 59 | const content = files.join(''); 60 | // Let's use sha256 as a means to get an ETag 61 | const hash = crypto 62 | .createHash('sha256') 63 | .update(content) 64 | .digest('hex'); 65 | 66 | res.set({ 67 | 'ETag': hash, 68 | 'Cache-Control': 'public, no-cache' 69 | }); 70 | res.send(content); 71 | }) 72 | .catch(error => res.status(500).send(error.toString())); 73 | }); 74 | app.use(express.static('app')); 75 | 76 | // Self-signed certificate generated by `simplehttp2server` 77 | // @see https://github.com/GoogleChrome/simplehttp2server 78 | const options = { 79 | key: fs.readFileSync('key.pem'), 80 | cert: fs.readFileSync('cert.pem') 81 | }; 82 | // It says spdy, but it's actually HTTP/2 :) 83 | require('spdy').createServer(options, app).listen(8081); 84 | -------------------------------------------------------------------------------- /stream-progress/stream.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import {TransformStream} from './third_party/transformstream.js'; 19 | 20 | class JSONTransformer { 21 | constructor() { 22 | this.chunks = []; 23 | this.depth = 0; 24 | this.inString = false; 25 | this.skipNext = false; 26 | this.decoder = new TextDecoder(); 27 | } 28 | 29 | start() {} 30 | flush() {} 31 | transform(chunk, controller) { 32 | for(let i = 0; i < chunk.length; i++) { 33 | if(this.skipNext) { 34 | this.skipNext = false; 35 | continue; 36 | } 37 | const byte = chunk[i]; 38 | const char = String.fromCharCode(byte); 39 | switch(char) { 40 | case '{': 41 | if(this.inString) continue; 42 | this.depth++; 43 | break; 44 | case '}': 45 | if(this.inString) continue; 46 | this.depth--; 47 | if(this.depth === 0) { 48 | const tail = new Uint8Array(chunk.buffer, chunk.byteOffset, i + 1); 49 | chunk = new Uint8Array(chunk.buffer, chunk.byteOffset + i + 1); 50 | this.chunks.push(tail); 51 | 52 | const jsonStr = this.chunks.reduce((str, chunk) => 53 | str + this.decoder.decode(chunk, {stream: true}), ''); 54 | controller.enqueue(jsonStr); 55 | 56 | this.chunks.length = 0; 57 | i = -1; 58 | } 59 | break; 60 | case '"': 61 | this.inString = !this.inString; 62 | break; 63 | case '\\': 64 | this.skipNext = true; 65 | break; 66 | } 67 | } 68 | this.chunks.push(chunk); 69 | } 70 | } 71 | 72 | const dial = document.querySelector('sc-dial'); 73 | fetch('./tweets.json') 74 | .then(async resp => { 75 | 76 | if (resp.status != 200) { 77 | //Don't try to parse non JSON responses, such as a 404 error... 78 | return; 79 | } 80 | 81 | const bytesTotal = parseInt(resp.headers.get('Content-Length'), 10); 82 | const jsonStream = resp.body.pipeThrough(new TransformStream(new JSONTransformer())); 83 | const reader = jsonStream.getReader(); 84 | 85 | let bytesCounted = 0; 86 | while(true) { 87 | const {value, done} = await reader.read(); 88 | if(done) { 89 | dial.percentage = 1; 90 | return; 91 | } 92 | 93 | bytesCounted += value.length; 94 | dial.percentage = bytesCounted / bytesTotal; 95 | } 96 | }); 97 | -------------------------------------------------------------------------------- /router-advanced/static/sc-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCView extends HTMLElement { 21 | 22 | constructor () { 23 | super(); 24 | this._view = null; 25 | this._isRemote = (this.getAttribute('remote') !== null); 26 | } 27 | 28 | get route () { 29 | return this.getAttribute('route') || null; 30 | } 31 | 32 | _hideSpinner () { 33 | this.classList.remove('pending'); 34 | } 35 | 36 | _showSpinner () { 37 | this.classList.add('pending'); 38 | } 39 | 40 | _loadView (data) { 41 | // Wait for half a second then show the spinner. 42 | const spinnerTimeout = setTimeout(_ => this._showSpinner(), 500); 43 | 44 | this._view = new DocumentFragment(); 45 | const xhr = new XMLHttpRequest(); 46 | 47 | xhr.onload = evt => { 48 | const newDoc = evt.target.response; 49 | const newView = newDoc.querySelector('sc-view.visible'); 50 | 51 | // Copy in the child nodes from the parent. 52 | while(newView.firstChild) { 53 | this._view.appendChild(newView.firstChild); 54 | } 55 | 56 | // Add the fragment to the page. 57 | this.appendChild(this._view); 58 | 59 | // Clear the timeout and remove the spinner if needed. 60 | clearTimeout(spinnerTimeout); 61 | this._hideSpinner(); 62 | }; 63 | xhr.responseType = 'document'; 64 | xhr.open('GET', `${data[0]}`); 65 | xhr.send(); 66 | } 67 | 68 | in (data) { 69 | if (this._isRemote && !this._view) { 70 | this._loadView(data); 71 | } 72 | 73 | return new Promise((resolve, reject) => { 74 | const onTransitionEnd = () => { 75 | this.removeEventListener('transitionend', onTransitionEnd); 76 | resolve(); 77 | }; 78 | 79 | this.classList.add('visible'); 80 | this.addEventListener('transitionend', onTransitionEnd); 81 | }); 82 | } 83 | 84 | out () { 85 | return new Promise((resolve, reject) => { 86 | const onTransitionEnd = () => { 87 | this.removeEventListener('transitionend', onTransitionEnd); 88 | resolve(); 89 | }; 90 | 91 | this.classList.remove('visible'); 92 | this.addEventListener('transitionend', onTransitionEnd); 93 | }); 94 | } 95 | 96 | update () { 97 | return Promise.resolve(); 98 | } 99 | } 100 | 101 | customElements.define('sc-view', SCView); 102 | -------------------------------------------------------------------------------- /code-splitting/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * 5 | * Copyright 2016 Google Inc. All rights reserved. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 'use strict'; 21 | 22 | const express = require('express'); 23 | const fs = require('mz/fs'); 24 | const handlebars = require('handlebars'); 25 | const crypto = require('crypto'); 26 | 27 | // Handlebars `if` only checks for truthy and falsy values, 28 | // so we have to write our own helper to check for equality (or inequality). 29 | handlebars.registerHelper('ifNotEq', function (a, b, opts) { 30 | if (a !== b) { 31 | return opts.fn(this); 32 | } 33 | }); 34 | 35 | handlebars.registerHelper('ifEq', function (a, b, opts) { 36 | if (a === b) { 37 | return opts.fn(this); 38 | } 39 | }); 40 | 41 | const app = express(); 42 | // Matches paths like `/`, `/index.html`, `/about/` or `/about/index.html`. 43 | const toplevelSection = /([^/]*)(\/|\/index.html)$/; 44 | app.get(toplevelSection, (req, res) => { 45 | // Extract the menu item name from the path and attach it to 46 | // the request to have it available for template rendering. 47 | req.item = req.params[0]; 48 | 49 | // If the request has `?partial`, don't render header and footer. 50 | let files; 51 | if ('partial' in req.query) { 52 | files = [fs.readFile(`app/${req.item}/index.html`)]; 53 | } else { 54 | files = [ 55 | fs.readFile('app/header.partial.html'), 56 | fs.readFile(`app/${req.item}/index.html`), 57 | fs.readFile('app/footer.partial.html') 58 | ]; 59 | } 60 | 61 | Promise.all(files) 62 | .then(files => files.map(f => f.toString('utf-8'))) 63 | .then(files => files.map(f => handlebars.compile(f)(req))) 64 | .then(files => { 65 | const content = files.join(''); 66 | // Let's use sha256 as a means to get an ETag 67 | const hash = crypto 68 | .createHash('sha256') 69 | .update(content) 70 | .digest('hex'); 71 | 72 | res.set({ 73 | 'ETag': hash, 74 | 'Cache-Control': 'public, no-cache' 75 | }); 76 | res.send(content); 77 | }) 78 | .catch(error => res.status(500).send(error.toString())); 79 | }); 80 | app.use(express.static('app')); 81 | 82 | // Self-signed certificate generated by `simplehttp2server` 83 | // @see https://github.com/GoogleChrome/simplehttp2server 84 | const options = { 85 | key: fs.readFileSync('key.pem'), 86 | cert: fs.readFileSync('cert.pem') 87 | }; 88 | // It says spdy, but it's actually HTTP/2 :) 89 | require('spdy').createServer(options, app).listen(8081); 90 | -------------------------------------------------------------------------------- /service-worker/app/static/sc-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCView extends HTMLElement { 21 | 22 | constructor () { 23 | super(); 24 | this._view = null; 25 | this._isRemote = (this.getAttribute('remote') !== null); 26 | } 27 | 28 | get route () { 29 | return this.getAttribute('route') || null; 30 | } 31 | 32 | _hideSpinner () { 33 | this.classList.remove('pending'); 34 | } 35 | 36 | _showSpinner () { 37 | this.classList.add('pending'); 38 | } 39 | 40 | _loadView (data) { 41 | // Wait for half a second then show the spinner. 42 | const spinnerTimeout = setTimeout(_ => this._showSpinner(), 500); 43 | 44 | this._view = new DocumentFragment(); 45 | const xhr = new XMLHttpRequest(); 46 | 47 | xhr.onload = evt => { 48 | const newDoc = evt.target.response; 49 | const newView = newDoc.querySelector('sc-view.visible'); 50 | 51 | // Copy in the child nodes from the parent. 52 | newView.childNodes.forEach(node => { 53 | this._view.appendChild(node); 54 | }); 55 | 56 | // Add the fragment to the page. 57 | this.appendChild(this._view); 58 | 59 | // Clear the timeout and remove the spinner if needed. 60 | clearTimeout(spinnerTimeout); 61 | this._hideSpinner(); 62 | }; 63 | xhr.responseType = 'document'; 64 | xhr.open('GET', `${data[0]}?partial=`); 65 | xhr.send(); 66 | } 67 | 68 | in (data) { 69 | if (this._isRemote && !this._view) { 70 | this._loadView(data); 71 | } 72 | 73 | return new Promise((resolve, reject) => { 74 | const onTransitionEnd = () => { 75 | this.removeEventListener('transitionend', onTransitionEnd); 76 | resolve(); 77 | }; 78 | 79 | this.classList.add('visible'); 80 | this.addEventListener('transitionend', onTransitionEnd); 81 | }); 82 | } 83 | 84 | out () { 85 | return new Promise((resolve, reject) => { 86 | const onTransitionEnd = () => { 87 | this.removeEventListener('transitionend', onTransitionEnd); 88 | resolve(); 89 | }; 90 | 91 | this.classList.remove('visible'); 92 | this.addEventListener('transitionend', onTransitionEnd); 93 | }); 94 | } 95 | 96 | update () { 97 | return Promise.resolve(); 98 | } 99 | } 100 | 101 | customElements.define('sc-view', SCView); 102 | -------------------------------------------------------------------------------- /server-side-rendering/app/static/sc-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCView extends HTMLElement { 21 | 22 | constructor () { 23 | super(); 24 | this._view = null; 25 | this._isRemote = (this.getAttribute('remote') !== null); 26 | } 27 | 28 | get route () { 29 | return this.getAttribute('route') || null; 30 | } 31 | 32 | _hideSpinner () { 33 | this.classList.remove('pending'); 34 | } 35 | 36 | _showSpinner () { 37 | this.classList.add('pending'); 38 | } 39 | 40 | _loadView (data) { 41 | // Wait for half a second then show the spinner. 42 | const spinnerTimeout = setTimeout(_ => this._showSpinner(), 500); 43 | 44 | this._view = new DocumentFragment(); 45 | const xhr = new XMLHttpRequest(); 46 | 47 | xhr.onload = evt => { 48 | const newDoc = evt.target.response; 49 | const newView = newDoc.querySelector('sc-view.visible'); 50 | 51 | // Copy in the child nodes from the parent. 52 | newView.childNodes.forEach(node => { 53 | this._view.appendChild(node); 54 | }); 55 | 56 | // Add the fragment to the page. 57 | this.appendChild(this._view); 58 | 59 | // Clear the timeout and remove the spinner if needed. 60 | clearTimeout(spinnerTimeout); 61 | this._hideSpinner(); 62 | }; 63 | xhr.responseType = 'document'; 64 | xhr.open('GET', `${data[0]}?partial`); 65 | xhr.send(); 66 | } 67 | 68 | in (data) { 69 | if (this._isRemote && !this._view) { 70 | this._loadView(data); 71 | } 72 | 73 | return new Promise((resolve, reject) => { 74 | const onTransitionEnd = () => { 75 | this.removeEventListener('transitionend', onTransitionEnd); 76 | resolve(); 77 | }; 78 | 79 | this.classList.add('visible'); 80 | this.addEventListener('transitionend', onTransitionEnd); 81 | }); 82 | } 83 | 84 | out () { 85 | return new Promise((resolve, reject) => { 86 | const onTransitionEnd = () => { 87 | this.removeEventListener('transitionend', onTransitionEnd); 88 | resolve(); 89 | }; 90 | 91 | this.classList.remove('visible'); 92 | this.addEventListener('transitionend', onTransitionEnd); 93 | }); 94 | } 95 | 96 | update () { 97 | return Promise.resolve(); 98 | } 99 | } 100 | 101 | customElements.define('sc-view', SCView); 102 | -------------------------------------------------------------------------------- /code-splitting/app/static/superstyles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | padding: 0; 24 | margin: 0; 25 | font-size: 24px; 26 | font-family: Arial, sans-serif; 27 | } 28 | 29 | sc-view { 30 | contain: strict; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: 100%; 35 | height: 100%; 36 | opacity: 0; 37 | pointer-events: none; 38 | transform: scale(0.95); 39 | transition: transform 0.3s cubic-bezier(0,0,0.3,1), 40 | opacity 0.3s cubic-bezier(0,0,0.3,1); 41 | font-size: 20vh; 42 | display: flex; 43 | flex-direction: row; 44 | justify-content: center; 45 | align-items: center; 46 | color: white; 47 | } 48 | 49 | sc-view.visible { 50 | opacity: 1; 51 | pointer-events: auto; 52 | transform: none; 53 | } 54 | 55 | sc-view[remote]::before { 56 | opacity: 0; 57 | pointer-events: none; 58 | content: ''; 59 | position: fixed; 60 | top: 0; 61 | left: 0; 62 | right: 0; 63 | bottom: 0; 64 | background: inherit; 65 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 66 | } 67 | 68 | sc-view[remote]::after { 69 | opacity: 0; 70 | pointer-events: none; 71 | content: ''; 72 | position: fixed; 73 | left: 50%; 74 | top: 50%; 75 | width: 40px; 76 | height: 40px; 77 | background: url(images/spinner.png) center center no-repeat; 78 | background-size: 40px 40px; 79 | animation-name: spin; 80 | animation-duration: 1s; 81 | animation-timing-function: linear; 82 | animation-iteration-count: infinite; 83 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 84 | } 85 | 86 | sc-view[remote].pending::before, 87 | sc-view[remote].pending::after { 88 | opacity: 1; 89 | } 90 | 91 | @keyframes spin { 92 | from { 93 | transform: translate(-50%, -50%) rotate(0deg); 94 | } 95 | 96 | to { 97 | transform: translate(-50%, -50%) rotate(360deg); 98 | } 99 | } 100 | 101 | .view-home { 102 | background: rgb(128,00,64); 103 | } 104 | 105 | .view-contact { 106 | background: rgb(00,128,64); 107 | } 108 | 109 | .view-about { 110 | background: rgb(00,64,128); 111 | } 112 | 113 | .view-misc { 114 | background: rgb(128,64,0); 115 | } 116 | 117 | nav { 118 | position: fixed; 119 | right: 10px; 120 | top: 10px; 121 | background: #FFF; 122 | box-shadow: 0 2px 4px rgba(0,0,0,0.3); 123 | padding: 10px 30px 10px 10px; 124 | border-radius: 3px; 125 | z-index: 1; 126 | } 127 | -------------------------------------------------------------------------------- /router-advanced/static/superstyles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | padding: 0; 24 | margin: 0; 25 | font-size: 24px; 26 | font-family: Arial, sans-serif; 27 | } 28 | 29 | sc-view { 30 | contain: strict; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: 100%; 35 | height: 100%; 36 | opacity: 0; 37 | pointer-events: none; 38 | transform: scale(0.95); 39 | transition: transform 0.3s cubic-bezier(0,0,0.3,1), 40 | opacity 0.3s cubic-bezier(0,0,0.3,1); 41 | font-size: 20vh; 42 | display: flex; 43 | flex-direction: row; 44 | justify-content: center; 45 | align-items: center; 46 | color: white; 47 | } 48 | 49 | sc-view.visible { 50 | opacity: 1; 51 | pointer-events: auto; 52 | transform: none; 53 | } 54 | 55 | sc-view[remote]::before { 56 | opacity: 0; 57 | pointer-events: none; 58 | content: ''; 59 | position: fixed; 60 | top: 0; 61 | left: 0; 62 | right: 0; 63 | bottom: 0; 64 | background: inherit; 65 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 66 | } 67 | 68 | sc-view[remote]::after { 69 | opacity: 0; 70 | pointer-events: none; 71 | content: ''; 72 | position: fixed; 73 | left: 50%; 74 | top: 50%; 75 | width: 40px; 76 | height: 40px; 77 | background: url(images/spinner.png) center center no-repeat; 78 | background-size: 40px 40px; 79 | animation-name: spin; 80 | animation-duration: 1s; 81 | animation-timing-function: linear; 82 | animation-iteration-count: infinite; 83 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 84 | } 85 | 86 | sc-view[remote].pending::before, 87 | sc-view[remote].pending::after { 88 | opacity: 1; 89 | } 90 | 91 | @keyframes spin { 92 | from { 93 | transform: translate(-50%, -50%) rotate(0deg); 94 | } 95 | 96 | to { 97 | transform: translate(-50%, -50%) rotate(360deg); 98 | } 99 | } 100 | 101 | .view-home { 102 | background: rgb(128,00,64); 103 | } 104 | 105 | .view-contact { 106 | background: rgb(00,128,64); 107 | } 108 | 109 | .view-about { 110 | background: rgb(00,64,128); 111 | } 112 | 113 | .view-misc { 114 | background: rgb(128,64,0); 115 | } 116 | 117 | nav { 118 | position: fixed; 119 | right: 10px; 120 | top: 10px; 121 | background: #FFF; 122 | box-shadow: 0 2px 4px rgba(0,0,0,0.3); 123 | padding: 10px 30px 10px 10px; 124 | border-radius: 3px; 125 | z-index: 1; 126 | } 127 | -------------------------------------------------------------------------------- /server-side-rendering/app/static/superstyles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | padding: 0; 24 | margin: 0; 25 | font-size: 24px; 26 | font-family: Arial, sans-serif; 27 | } 28 | 29 | sc-view { 30 | contain: strict; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: 100%; 35 | height: 100%; 36 | opacity: 0; 37 | pointer-events: none; 38 | transform: scale(0.95); 39 | transition: transform 0.3s cubic-bezier(0,0,0.3,1), 40 | opacity 0.3s cubic-bezier(0,0,0.3,1); 41 | font-size: 20vh; 42 | display: flex; 43 | flex-direction: row; 44 | justify-content: center; 45 | align-items: center; 46 | color: white; 47 | } 48 | 49 | sc-view.visible { 50 | opacity: 1; 51 | pointer-events: auto; 52 | transform: none; 53 | } 54 | 55 | sc-view[remote]::before { 56 | opacity: 0; 57 | pointer-events: none; 58 | content: ''; 59 | position: fixed; 60 | top: 0; 61 | left: 0; 62 | right: 0; 63 | bottom: 0; 64 | background: inherit; 65 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 66 | } 67 | 68 | sc-view[remote]::after { 69 | opacity: 0; 70 | pointer-events: none; 71 | content: ''; 72 | position: fixed; 73 | left: 50%; 74 | top: 50%; 75 | width: 40px; 76 | height: 40px; 77 | background: url(images/spinner.png) center center no-repeat; 78 | background-size: 40px 40px; 79 | animation-name: spin; 80 | animation-duration: 1s; 81 | animation-timing-function: linear; 82 | animation-iteration-count: infinite; 83 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 84 | } 85 | 86 | sc-view[remote].pending::before, 87 | sc-view[remote].pending::after { 88 | opacity: 1; 89 | } 90 | 91 | @keyframes spin { 92 | from { 93 | transform: translate(-50%, -50%) rotate(0deg); 94 | } 95 | 96 | to { 97 | transform: translate(-50%, -50%) rotate(360deg); 98 | } 99 | } 100 | 101 | .view-home { 102 | background: rgb(128,00,64); 103 | } 104 | 105 | .view-contact { 106 | background: rgb(00,128,64); 107 | } 108 | 109 | .view-about { 110 | background: rgb(00,64,128); 111 | } 112 | 113 | .view-misc { 114 | background: rgb(128,64,0); 115 | } 116 | 117 | nav { 118 | position: fixed; 119 | right: 10px; 120 | top: 10px; 121 | background: #FFF; 122 | box-shadow: 0 2px 4px rgba(0,0,0,0.3); 123 | padding: 10px 30px 10px 10px; 124 | border-radius: 3px; 125 | z-index: 1; 126 | } 127 | -------------------------------------------------------------------------------- /streaming-service-worker/server/rev.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const util = require('util'); 4 | const crypto = require('crypto'); 5 | 6 | const rename = util.promisify(fs.rename); 7 | const readFile = util.promisify(fs.readFile); 8 | const writeFile = util.promisify(fs.writeFile); 9 | 10 | const glob = util.promisify(require('glob')); 11 | const mkdirp = util.promisify(require('mkdirp')); 12 | const through2 = require('through2'); 13 | const escapeStringRegexp = require('escape-string-regexp'); 14 | 15 | const hashes = new Map(); 16 | 17 | function hashExtension(extension, hash) { 18 | return '.' + hash.digest('hex').slice(0, 10) + extension; 19 | } 20 | 21 | module.exports.copyAndRev = async function copyAndRev(cwd, from, to) { 22 | cwd = path.normalize(cwd); 23 | to = path.normalize(to); 24 | 25 | const paths = await glob(from, { 26 | cwd, 27 | nodir: true 28 | }); 29 | 30 | await Promise.all( 31 | paths.map(async p => { 32 | const parsedPath = path.parse(p); 33 | const parsedOutputPath = { 34 | dir: parsedPath.dir ? `${to}/${parsedPath.dir}` : to, 35 | name: parsedPath.name, 36 | ext: parsedPath.ext 37 | }; 38 | 39 | const hash = crypto.createHash('md5'); 40 | const input = fs.createReadStream(`${cwd}/${p}`); 41 | const initialOutputPath = path.format(parsedOutputPath); 42 | 43 | await mkdirp(parsedOutputPath.dir); 44 | 45 | await new Promise(resolve => { 46 | input.pipe(through2((chunk, enc, callback) => { 47 | hash.update(chunk); 48 | callback(null, chunk); 49 | })).pipe(fs.createWriteStream(initialOutputPath)).on('finish', resolve); 50 | }); 51 | 52 | parsedOutputPath.ext = hashExtension(parsedOutputPath.ext, hash); 53 | 54 | hashes.set(`/static/${p}`, `/static-rev/${parsedPath.dir ? parsedPath.dir + "/" : ""}${parsedOutputPath.name}${parsedOutputPath.ext}`); 55 | await rename(initialOutputPath, path.format(parsedOutputPath)); 56 | }) 57 | ); 58 | } 59 | 60 | module.exports.addAndRev = async function addAndRev(p, destination, content) { 61 | const parsedPath = path.parse(p); 62 | const newExtension = hashExtension(parsedPath.ext, 63 | crypto.createHash('md5').update(content) 64 | ); 65 | 66 | let outputPath = `${parsedPath.name}${newExtension}`; 67 | if (parsedPath.dir) outputPath = `${parsedPath.dir}/` + outputPath; 68 | 69 | hashes.set(`/static/${p}`, `/static-rev/${outputPath}`); 70 | await writeFile(`${destination}/${outputPath}`, content); 71 | }; 72 | 73 | module.exports.replaceInFiles = async function replaceInFiles(inGlob) { 74 | const paths = await glob(inGlob, { nodir: true }); 75 | 76 | await Promise.all( 77 | paths.map(async p => { 78 | const content = await readFile(p, 'utf8'); 79 | await writeFile(p, replace(content)); 80 | }) 81 | ); 82 | }; 83 | 84 | function replace(content) { 85 | const re = new RegExp( 86 | [...hashes.keys()].map(s => escapeStringRegexp(s)).join('|'), 87 | 'g' 88 | ); 89 | 90 | return content.replace(re, match => hashes.get(match)); 91 | }; 92 | 93 | module.exports.replace = replace; 94 | 95 | module.exports.get = function get(key) { 96 | return hashes.get(key); 97 | }; 98 | -------------------------------------------------------------------------------- /firebase-firestore-comments/src/server/index.html: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | Supercharged Comments 20 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 |
104 | 105 |
106 | 107 | 108 | 109 |

Comments

110 | 111 | 112 | 113 | 114 | 115 |
116 | 117 |
118 | 119 | 120 | -------------------------------------------------------------------------------- /code-splitting/app/static/sc-view.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCView extends HTMLElement { 21 | 22 | constructor () { 23 | super(); 24 | this._view = null; 25 | this._isRemote = (this.getAttribute('remote') !== null); 26 | } 27 | 28 | get route () { 29 | return this.getAttribute('route') || null; 30 | } 31 | 32 | _hideSpinner () { 33 | this.classList.remove('pending'); 34 | } 35 | 36 | _showSpinner () { 37 | this.classList.add('pending'); 38 | } 39 | 40 | _loadView (data) { 41 | // Wait for half a second then show the spinner. 42 | const spinnerTimeout = setTimeout(_ => this._showSpinner(), 500); 43 | 44 | this._view = new DocumentFragment(); 45 | const xhr = new XMLHttpRequest(); 46 | 47 | xhr.onload = evt => { 48 | const newDoc = evt.target.response; 49 | const newView = newDoc.querySelector('sc-view.visible'); 50 | 51 | // Copy in the child nodes from the parent. 52 | newView.childNodes.forEach(node => { 53 | this._view.appendChild(node); 54 | }); 55 | 56 | // Add the fragment to the page. 57 | this.appendChild(this._view); 58 | const s = document.createElement('script'); 59 | s.type = 'module'; 60 | s.src = newDoc.querySelector('body > script').src; 61 | this.appendChild(s); 62 | 63 | // Clear the timeout and remove the spinner if needed. 64 | clearTimeout(spinnerTimeout); 65 | this._hideSpinner(); 66 | }; 67 | xhr.responseType = 'document'; 68 | xhr.open('GET', `${data[0]}?partial`); 69 | xhr.send(); 70 | } 71 | 72 | in (data) { 73 | if (this._isRemote && !this._view) { 74 | this._loadView(data); 75 | } 76 | 77 | return new Promise((resolve, reject) => { 78 | const onTransitionEnd = () => { 79 | this.removeEventListener('transitionend', onTransitionEnd); 80 | resolve(); 81 | }; 82 | 83 | this.classList.add('visible'); 84 | this.addEventListener('transitionend', onTransitionEnd); 85 | }); 86 | } 87 | 88 | out () { 89 | return new Promise((resolve, reject) => { 90 | const onTransitionEnd = () => { 91 | this.removeEventListener('transitionend', onTransitionEnd); 92 | resolve(); 93 | }; 94 | 95 | this.classList.remove('visible'); 96 | this.addEventListener('transitionend', onTransitionEnd); 97 | }); 98 | } 99 | 100 | update () { 101 | return Promise.resolve(); 102 | } 103 | } 104 | 105 | customElements.define('sc-view', SCView); 106 | -------------------------------------------------------------------------------- /service-worker/app/static/superstyles.css: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | * { 19 | box-sizing: border-box; 20 | } 21 | 22 | html, body { 23 | padding: 0; 24 | margin: 0; 25 | font-size: 24px; 26 | font-family: Arial, sans-serif; 27 | } 28 | 29 | sc-view { 30 | contain: strict; 31 | position: fixed; 32 | top: 0; 33 | left: 0; 34 | width: 100%; 35 | height: 100%; 36 | opacity: 0; 37 | pointer-events: none; 38 | transform: scale(0.95); 39 | transition: transform 0.3s cubic-bezier(0,0,0.3,1), 40 | opacity 0.3s cubic-bezier(0,0,0.3,1); 41 | font-size: 20vh; 42 | display: flex; 43 | flex-direction: row; 44 | justify-content: center; 45 | align-items: center; 46 | color: white; 47 | } 48 | 49 | sc-view.visible { 50 | opacity: 1; 51 | pointer-events: auto; 52 | transform: none; 53 | } 54 | 55 | sc-view[remote]::before { 56 | opacity: 0; 57 | pointer-events: none; 58 | content: ''; 59 | position: fixed; 60 | top: 0; 61 | left: 0; 62 | right: 0; 63 | bottom: 0; 64 | background: inherit; 65 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 66 | } 67 | 68 | sc-view[remote]::after { 69 | opacity: 0; 70 | pointer-events: none; 71 | content: ''; 72 | position: fixed; 73 | left: 50%; 74 | top: 50%; 75 | width: 40px; 76 | height: 40px; 77 | background: url(images/spinner.png) center center no-repeat; 78 | background-size: 40px 40px; 79 | animation-name: spin; 80 | animation-duration: 1s; 81 | animation-timing-function: linear; 82 | animation-iteration-count: infinite; 83 | transition: opacity 0.3s cubic-bezier(0,0,0.3,1); 84 | } 85 | 86 | sc-view[remote].pending::before, 87 | sc-view[remote].pending::after { 88 | opacity: 1; 89 | } 90 | 91 | @keyframes spin { 92 | from { 93 | transform: translate(-50%, -50%) rotate(0deg); 94 | } 95 | 96 | to { 97 | transform: translate(-50%, -50%) rotate(360deg); 98 | } 99 | } 100 | 101 | .view-home { 102 | background: rgb(128,00,64); 103 | } 104 | 105 | .view-contact { 106 | background: rgb(00,128,64); 107 | } 108 | 109 | .view-about { 110 | background: rgb(00,64,128); 111 | } 112 | 113 | .view-misc { 114 | background: rgb(128,64,0); 115 | } 116 | 117 | nav { 118 | position: fixed; 119 | right: 10px; 120 | top: 10px; 121 | background: #FFF; 122 | box-shadow: 0 2px 4px rgba(0,0,0,0.3); 123 | padding: 10px 30px 10px 10px; 124 | border-radius: 3px; 125 | z-index: 1; 126 | } 127 | 128 | body.offline nav a { 129 | opacity: 0.3; 130 | pointer-events: none; 131 | } 132 | 133 | body.offline nav a.cached { 134 | opacity: 1; 135 | pointer-events: initial; 136 | } 137 | -------------------------------------------------------------------------------- /stream-progress/dial.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright 2016 Google Inc. All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | 'use strict'; 19 | 20 | class SCDial extends HTMLElement { 21 | static get SIZE () { 22 | return 256; 23 | } 24 | 25 | static get NINETY_DEGREES () { 26 | return Math.PI * 0.5; 27 | } 28 | 29 | static get TAU () { 30 | return Math.PI * 2; 31 | } 32 | 33 | constructor () { 34 | super(); 35 | 36 | this._canvas = document.createElement('canvas'); 37 | this._ctx = this._canvas.getContext('2d'); 38 | 39 | this._canvas.width = SCDial.SIZE; 40 | this._canvas.height = SCDial.SIZE; 41 | 42 | this._percentage = 0; 43 | } 44 | 45 | set percentage (_percentage) { 46 | if (Number.isNaN(_percentage) || _percentage < 0 || _percentage > 1) { 47 | throw new Error('Percentage must be a number between 0 and 1.'); 48 | } 49 | 50 | this._percentage = _percentage; 51 | this.draw(); 52 | } 53 | 54 | get percentage () { 55 | return this._percentage; 56 | } 57 | 58 | draw () { 59 | const mid = SCDial.SIZE * 0.5; 60 | 61 | // Since the coordinate system is about to get changed, 62 | // save the context (and restore it when we're done later). 63 | this._ctx.save(); 64 | 65 | // Clear everything. 66 | this._ctx.clearRect(0, 0, SCDial.SIZE, SCDial.SIZE); 67 | 68 | // Rotate the coordinate system. 69 | this._ctx.translate(mid, mid); 70 | this._ctx.rotate(-SCDial.NINETY_DEGREES); 71 | this._ctx.translate(-mid, -mid); 72 | 73 | // Outer arc. 74 | this._ctx.beginPath(); 75 | this._ctx.moveTo(mid, mid); 76 | this._ctx.arc(mid, mid, mid, 0, this._percentage * SCDial.TAU); 77 | this._ctx.closePath(); 78 | this._ctx.fillStyle = `rgb(${Math.round(this._percentage * 255)}, 0, 128)`; 79 | this._ctx.fill(); 80 | 81 | // Inner arc. 82 | this._ctx.beginPath(); 83 | this._ctx.moveTo(mid, mid); 84 | this._ctx.arc(mid, mid, mid * 0.8, 0, SCDial.TAU); 85 | this._ctx.closePath(); 86 | this._ctx.fillStyle = '#FFF'; 87 | this._ctx.fill(); 88 | 89 | this._ctx.restore(); 90 | 91 | // Number Label. 92 | this._ctx.fillStyle = '#333'; 93 | this._ctx.font = `${SCDial.SIZE * 0.25}px Arial`; 94 | this._ctx.textAlign = 'center'; 95 | this._ctx.textBaseline = 'middle'; 96 | this._ctx.fillText(Math.round(this._percentage * 100), mid, mid - 14); 97 | 98 | // Text label. 99 | this._ctx.fillStyle = '#777'; 100 | this._ctx.font = `${SCDial.SIZE * 0.06}px Arial`; 101 | this._ctx.fillText('PERCENT', mid, mid + 26); 102 | } 103 | 104 | connectedCallback () { 105 | this.appendChild(this._canvas); 106 | this.draw(); 107 | } 108 | } 109 | 110 | customElements.define('sc-dial', SCDial); 111 | --------------------------------------------------------------------------------