mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 00:37:19 +00:00
interim commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
/build
|
||||
/*.log
|
||||
15965
package-lock.json
generated
Normal file
15965
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
package.json
Normal file
40
package.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "squoosh",
|
||||
"version": "0.0.0",
|
||||
"license": "apache-2.0",
|
||||
"scripts": {
|
||||
"start": "if-env NODE_ENV=production && npm run -s serve || npm run -s dev",
|
||||
"build": "preact build",
|
||||
"serve": "preact build && preact serve",
|
||||
"dev": "preact watch",
|
||||
"lint": "eslint src"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "eslint-config-developit",
|
||||
"rules": {
|
||||
"react/prefer-stateless-function": 0
|
||||
}
|
||||
},
|
||||
"eslintIgnore": [
|
||||
"build/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"eslint": "^4.18.2",
|
||||
"eslint-config-developit": "^1.1.1",
|
||||
"if-env": "^1.0.4",
|
||||
"node-sass": "^4.7.2",
|
||||
"preact-cli": "^2.2.1",
|
||||
"sass-loader": "^6.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"material-components-web": "^0.31.0",
|
||||
"material-radial-progress": "git+https://gist.github.com/02134901c77c5309924bfcf8b4435ebe.git",
|
||||
"preact": "^8.2.7",
|
||||
"preact-compat": "^3.18.0",
|
||||
"preact-i18n": "^1.2.0",
|
||||
"preact-material-components": "^1.3.7",
|
||||
"preact-material-components-drawer": "git+https://gist.github.com/a78fceed440b98e62582e4440b86bfab.git",
|
||||
"preact-router": "^2.6.0"
|
||||
}
|
||||
}
|
||||
BIN
src/assets/favicon.ico
Normal file
BIN
src/assets/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
src/assets/icon.png
Normal file
BIN
src/assets/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 90 KiB |
36
src/components/app/index.js
Normal file
36
src/components/app/index.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Component } from 'preact';
|
||||
import { updater, toggle } from '../../lib/util';
|
||||
import Fab from '../fab';
|
||||
import Header from '../header';
|
||||
import Drawer from '../drawer';
|
||||
import Home from '../home';
|
||||
import style from './style';
|
||||
|
||||
export default class App extends Component {
|
||||
state = {
|
||||
showDrawer: false,
|
||||
showFab: true
|
||||
};
|
||||
|
||||
openDrawer = updater(this, 'showDrawer', true);
|
||||
closeDrawer = updater(this, 'showDrawer', false);
|
||||
toggleDrawer = updater(this, 'showDrawer', toggle);
|
||||
|
||||
openFab = updater(this, 'showFab', true);
|
||||
closeFab = updater(this, 'showFab', false);
|
||||
toggleFab = updater(this, 'showFab', toggle);
|
||||
|
||||
render({ url }, { showDrawer, showFab }) {
|
||||
return (
|
||||
<div id="app" class={style.app}>
|
||||
<Fab showing={showFab} />
|
||||
<Header toggleDrawer={this.toggleDrawer} />
|
||||
<Drawer showing={showDrawer} openDrawer={this.openDrawer} closeDrawer={this.closeDrawer} />
|
||||
<div class={style.content} paint-outside>
|
||||
<Home />
|
||||
</div>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
21
src/components/app/style.scss
Normal file
21
src/components/app/style.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
@import '~style/helpers.scss';
|
||||
|
||||
.app {
|
||||
position: absolute;
|
||||
top: $toolbar-height;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
contain: size layout style;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
> .content {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
38
src/components/drawer/index.js
Normal file
38
src/components/drawer/index.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Component } from 'preact';
|
||||
import MdlDrawer from 'preact-material-components-drawer';
|
||||
import 'preact-material-components/Drawer/style.css';
|
||||
import List from 'preact-material-components/List';
|
||||
// import 'preact-material-components/List/style.css';
|
||||
import { Text } from 'preact-i18n';
|
||||
import style from './style';
|
||||
|
||||
export default class Drawer extends Component {
|
||||
render({ showing, openDrawer, closeDrawer }) {
|
||||
return (
|
||||
<MdlDrawer open={showing} onOpen={openDrawer} onClose={closeDrawer}>
|
||||
<MdlDrawer.Header autosize class="mdc-theme--primary-bg">
|
||||
<img class={style.logo} alt="logo" src="/assets/icon.png" />
|
||||
</MdlDrawer.Header>
|
||||
<MdlDrawer.Content autosize class={style.list}>
|
||||
<List autosize>
|
||||
<List.LinkItem href="/">
|
||||
<List.ItemIcon>verified_user</List.ItemIcon>
|
||||
<Text id="SIGN_IN">Sign In</Text>
|
||||
</List.LinkItem>
|
||||
<List.LinkItem href="/register">
|
||||
<List.ItemIcon>account_circle</List.ItemIcon>
|
||||
<Text id="REGISTER">Register</Text>
|
||||
</List.LinkItem>
|
||||
</List>
|
||||
</MdlDrawer.Content>
|
||||
|
||||
<div class={style.bottom} autosize>
|
||||
<List.LinkItem href="/preferences">
|
||||
<List.ItemIcon>settings</List.ItemIcon>
|
||||
<Text id="PREFERENCES">Preferences</Text>
|
||||
</List.LinkItem>
|
||||
</div>
|
||||
</MdlDrawer>
|
||||
);
|
||||
}
|
||||
}
|
||||
29
src/components/drawer/style.scss
Normal file
29
src/components/drawer/style.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
@import '~style/helpers.scss';
|
||||
|
||||
:global {
|
||||
// @import '~preact-material-components/Drawer/style.css';
|
||||
@import '~preact-material-components/List/mdc-list.scss';
|
||||
}
|
||||
|
||||
.drawer {
|
||||
:global(.mdc-list-item__start-detail) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.category img {
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
bottom: constant(safe-area-inset-bottom);
|
||||
bottom: env(safe-area-inset-bottom);
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
28
src/components/fab/index.js
Normal file
28
src/components/fab/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Component } from 'preact';
|
||||
import Icon from 'preact-material-components/Icon';
|
||||
import 'preact-material-components/Icon/style.css';
|
||||
import Fab from 'preact-material-components/Fab';
|
||||
import RadialProgress from 'material-radial-progress';
|
||||
import style from './style';
|
||||
|
||||
export default class AppFab extends Component {
|
||||
handleClick = () => {
|
||||
console.log('TODO: Save the file to disk.');
|
||||
this.setState({ loading: true });
|
||||
setTimeout( () => {
|
||||
this.setState({ loading: false });
|
||||
}, 100000);
|
||||
};
|
||||
|
||||
render({}, { loading }) {
|
||||
return (
|
||||
<Fab ripple secondary class={style.fab} onClick={this.handleClick}>
|
||||
{ loading ? (
|
||||
<RadialProgress primary class={style.progress} />
|
||||
) : (
|
||||
<Icon autosize>file_download</Icon>
|
||||
) }
|
||||
</Fab>
|
||||
);
|
||||
}
|
||||
}
|
||||
18
src/components/fab/style.scss
Normal file
18
src/components/fab/style.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
@import '~style/helpers.scss';
|
||||
:global {
|
||||
@import '~preact-material-components/Fab/mdc-fab.scss';
|
||||
}
|
||||
|
||||
.fab {
|
||||
position: fixed;
|
||||
right: 14px;
|
||||
bottom: 14px;
|
||||
z-index: 4;
|
||||
|
||||
.progress {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: white;
|
||||
--mdc-theme-primary: #fff;
|
||||
}
|
||||
}
|
||||
35
src/components/header/index.js
Normal file
35
src/components/header/index.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Component } from 'preact';
|
||||
import Toolbar from 'preact-material-components/Toolbar';
|
||||
// import 'preact-material-components/Toolbar/mdc-toolbar.scss';
|
||||
// import Icon from 'preact-material-components/Icon';
|
||||
// import 'preact-material-components/Icon/style.css';
|
||||
// import Fab from 'preact-material-components/Fab';
|
||||
// import 'preact-material-components/Fab/mdc-fab.scss';
|
||||
import style from './style';
|
||||
|
||||
export default class Header extends Component {
|
||||
// fabClick = () => {
|
||||
// alert("Hello");
|
||||
// };
|
||||
|
||||
render({ toggleDrawer, showHeader, showFab }) {
|
||||
return (
|
||||
<Toolbar class={`${style.toolbar} ${showHeader === false ? style.minimal : ''} inert`} fixed>
|
||||
<Toolbar.Row>
|
||||
<Toolbar.Title autosize class={style.title}>
|
||||
<img class={style.logo} src="/assets/icon.png" />
|
||||
</Toolbar.Title>
|
||||
<Toolbar.Section autosize align-end>
|
||||
<Toolbar.Icon autosize menu onClick={toggleDrawer}>menu</Toolbar.Icon>
|
||||
</Toolbar.Section>
|
||||
</Toolbar.Row>
|
||||
|
||||
{/*
|
||||
<Fab class={style.fab} exited={showFab===false} ripple onClick={this.fabClick}>
|
||||
<Icon>create</Icon>
|
||||
</Fab>
|
||||
*/}
|
||||
</Toolbar>
|
||||
);
|
||||
}
|
||||
}
|
||||
45
src/components/header/style.scss
Normal file
45
src/components/header/style.scss
Normal file
@@ -0,0 +1,45 @@
|
||||
@import '~style/helpers.scss';
|
||||
:global {
|
||||
@import '~preact-material-components/Toolbar/mdc-toolbar.scss';
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
height: $toolbar-height;
|
||||
|
||||
&.minimal {
|
||||
height: $toolbar-height / 2;
|
||||
}
|
||||
|
||||
// > * {
|
||||
// min-height: 0;
|
||||
// }
|
||||
}
|
||||
|
||||
.fab {
|
||||
position: fixed;
|
||||
display: block;
|
||||
right: 14px;
|
||||
bottom: 14px;
|
||||
// z-index: 999;
|
||||
// transform: translateZ(0);
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.menu {
|
||||
position: absolute;
|
||||
top: $toolbar-height;
|
||||
right: 5px;
|
||||
|
||||
.menuItem {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 3px 0 0;
|
||||
font-weight: 300;
|
||||
font-size: 140%;
|
||||
}
|
||||
16
src/components/home/index.js
Normal file
16
src/components/home/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Component } from 'preact';
|
||||
// import Button from 'preact-material-components/Button';
|
||||
// import Switch from 'preact-material-components/Switch';
|
||||
// import 'preact-material-components/Switch/style.css';
|
||||
import style from './style';
|
||||
|
||||
|
||||
export default class Home extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div class={style.home}>
|
||||
<h1>Home</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
10
src/components/home/style.scss
Normal file
10
src/components/home/style.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
@import '~style/helpers.scss';
|
||||
|
||||
// :global {
|
||||
// @import '~preact-material-components/Button/mdc-button.scss';
|
||||
// // @import '~preact-material-components/Switch/mdc-switch.scss';
|
||||
// }
|
||||
|
||||
.home {
|
||||
padding: 20px;
|
||||
}
|
||||
18
src/index.js
Normal file
18
src/index.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import './style';
|
||||
import './lib/fix-pmc';
|
||||
import App from './components/app';
|
||||
|
||||
export default App;
|
||||
|
||||
if (typeof window!=='undefined') {
|
||||
addEventListener('click', e => {
|
||||
let { target } = e;
|
||||
do {
|
||||
if (target.nodeName === 'A') {
|
||||
history.pushState(null, null, target.pathname);
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
} while (target = target.parentNode);
|
||||
});
|
||||
}
|
||||
26
src/lib/fix-pmc.js
Normal file
26
src/lib/fix-pmc.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { options } from 'preact';
|
||||
|
||||
const classNameDescriptor = {
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
get() {
|
||||
return this.class;
|
||||
},
|
||||
set(value) {
|
||||
this.class = value;
|
||||
}
|
||||
};
|
||||
|
||||
let old = options.vnode;
|
||||
options.vnode = vnode => {
|
||||
let a = vnode.attributes;
|
||||
if (a!=null) {
|
||||
if ('className' in a) {
|
||||
a.class = a.className;
|
||||
}
|
||||
if ('class' in a) {
|
||||
Object.defineProperty(a, 'className', classNameDescriptor);
|
||||
}
|
||||
}
|
||||
if (old != null) old(vnode);
|
||||
};
|
||||
10
src/lib/util.js
Normal file
10
src/lib/util.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export function updater(obj, property, value) {
|
||||
return e => {
|
||||
let update = {};
|
||||
update[property] = typeof value === 'function' ? value(obj.state[property], e) : value;
|
||||
obj.setState(update);
|
||||
};
|
||||
}
|
||||
|
||||
export const toggle = value => !value;
|
||||
|
||||
16
src/manifest.json
Normal file
16
src/manifest.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Squoosh",
|
||||
"short_name": "Squoosh",
|
||||
"start_url": "/",
|
||||
"display": "standalone",
|
||||
"orientation": "portrait",
|
||||
"background_color": "#fff",
|
||||
"theme_color": "#673ab8",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/assets/icon.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
src/style/helpers.scss
Normal file
10
src/style/helpers.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
$toolbar-height: 56px;
|
||||
|
||||
$mdc-theme-primary: #263238;
|
||||
$mdc-theme-primary-light: #4f5b62;
|
||||
$mdc-theme-primary-dark: #000a12;
|
||||
$mdc-theme-secondary: #d81b60;
|
||||
$mdc-theme-secondary-light: #ff5c8d;
|
||||
$mdc-theme-secondary-dark: #a00037;
|
||||
$mdc-theme-secondary-dark: #a00037;
|
||||
$mdc-theme-background: #fff;
|
||||
26
src/style/index.scss
Normal file
26
src/style/index.scss
Normal file
@@ -0,0 +1,26 @@
|
||||
// @import './material-icons.scss';
|
||||
// @import 'material-components-web/material-components-web';
|
||||
@import './reset.scss';
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
html {
|
||||
background: #FAFAFA;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-weight: 400;
|
||||
color: #444;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.mdc-theme--dark {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
}
|
||||
28
src/style/material-icons.scss
Normal file
28
src/style/material-icons.scss
Normal file
@@ -0,0 +1,28 @@
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Material Icons'),
|
||||
local('MaterialIcons-Regular'),
|
||||
url(https://example.com/MaterialIcons-Regular.woff2) format('woff2'),
|
||||
url(https://example.com/MaterialIcons-Regular.woff) format('woff'),
|
||||
url(https://example.com/MaterialIcons-Regular.ttf) format('truetype');
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-rendering: optimizeLegibility;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
12
src/style/reset.scss
Normal file
12
src/style/reset.scss
Normal file
@@ -0,0 +1,12 @@
|
||||
button, a, img, input, select, textarea {
|
||||
-webkit-tap-highlight-color: rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
a, button, img, [inert], .inert {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-drag: none;
|
||||
-webkit-user-drag: none;
|
||||
touch-callout: none;
|
||||
-webkit-touch-callout: none;
|
||||
}
|
||||
Reference in New Issue
Block a user