diff --git a/docs/stack.md b/docs/stack.md
index ea44681..5243833 100644
--- a/docs/stack.md
+++ b/docs/stack.md
@@ -27,11 +27,50 @@ Some automation so I stop checking in crap-looking code.
Can't imagine doing web differently to be honest. I'm sure we will soon, but for mid-2017, this is dominating.
-> **vanilla react**
+I like `preact` as well. I feel like the switching over will be pretty simple and I probably will.
-There are lot of great libraries out there for UI. This intentionally uses none of them. Don't hestitate to bring one in and use it if that's how you roll.
-I'm keep it straight-up react here because some types of apps I'd will be using webgl, pixi, or are pure svg interfaces.
+## Component Styling ##
+
+> **glamor**
+
+The winner is:
+
+* ~vanilla css~
+* ~sass~
+* ~css modules~
+* ~diy~
+* ~radium~
+* ~aphrodite~
+* ~styletron~
+* ~styled-components~
+* ~typestyle~
+* ~emotion~
+* ~glam~
+* ~glamorous~
+* `glamor`!
+
+I've flip-flopped on this quite a bit. We're spoiled by awesome options.
+
+`glamor` nails what I'm looking for:
+
+* ✅ objects are first class
+* ✅ strong on composibility
+* ✅ performant out of the box (without configuration)
+* ✅ works well with global styles and things like keyframes
+* ✅ friendly devs
+* ✅ a DSL that is true to CSS (especially with child selectors)
+* ✅ built-in escape hatches
+* ✅ clear docs with examples, patterns, and advice
+* ✅ stable-ish API
+* ✅ TypeScript-friendly
+* ✅ testability without flushing caches or buffers
+
+My advice? **Don't listen to my advice**. Explore & pick your own. Much, if not most, of your app is UI.
+
+Start your app only when your gut says, "You'll fuck this up long before your styling lib gives out."
+
+`glamor` gives me that vibe. 💃
## State Management
diff --git a/package-lock.json b/package-lock.json
index fc40ed6..d61244b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1160,6 +1160,11 @@
"hoek": "2.16.3"
}
},
+ "bowser": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.7.1.tgz",
+ "integrity": "sha1-pN6PGKGg3JUx6yqSoVIftqm6lqU="
+ },
"boxen": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/boxen/-/boxen-1.2.0.tgz",
@@ -1762,6 +1767,14 @@
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
"dev": true
},
+ "css-in-js-utils": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz",
+ "integrity": "sha1-msfgL3Y8+F2UAXZmVl7WiltfMhU=",
+ "requires": {
+ "hyphenate-style-name": "1.0.2"
+ }
+ },
"cuint": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz",
@@ -4771,6 +4784,18 @@
}
}
},
+ "glamor": {
+ "version": "2.20.39",
+ "resolved": "https://registry.npmjs.org/glamor/-/glamor-2.20.39.tgz",
+ "integrity": "sha512-tQ25Rmuad18jybnQgnsBzjhayPaK5Izy7SApBAaRnYQ50uA96SQEAoyymA8QNan51QyK1mB7dFUCX0OyaKa0yg==",
+ "requires": {
+ "fbjs": "0.8.12",
+ "inline-style-prefixer": "3.0.7",
+ "object-assign": "4.1.1",
+ "prop-types": "15.5.10",
+ "through": "2.3.8"
+ }
+ },
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
@@ -5031,6 +5056,11 @@
}
}
},
+ "hyphenate-style-name": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",
+ "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="
+ },
"iconv-lite": {
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
@@ -5104,6 +5134,15 @@
"integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=",
"dev": true
},
+ "inline-style-prefixer": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-3.0.7.tgz",
+ "integrity": "sha1-DMyS5ZAv5uDSjZdcQlhEP4gGFfg=",
+ "requires": {
+ "bowser": "1.7.1",
+ "css-in-js-utils": "1.0.3"
+ }
+ },
"inquirer": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.0.tgz",
@@ -8709,8 +8748,7 @@
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
},
"through2": {
"version": "2.0.3",
diff --git a/package.json b/package.json
index cc4d8ee..5622639 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"electron-log": "2.2.7",
"electron-store": "1.2.0",
"electron-updater": "2.8.2",
+ "glamor": "2.20.39",
"mobx": "3.2.2",
"mobx-react": "4.2.2",
"mobx-state-tree": "0.9.5",
diff --git a/src/renderer/features/app/app.css b/src/renderer/features/app/app.css
deleted file mode 100644
index bc3dc35..0000000
--- a/src/renderer/features/app/app.css
+++ /dev/null
@@ -1,8 +0,0 @@
-@keyframes spin360 {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
diff --git a/src/renderer/features/app/app.tsx b/src/renderer/features/app/app.tsx
index 1895106..4413a9c 100644
--- a/src/renderer/features/app/app.tsx
+++ b/src/renderer/features/app/app.tsx
@@ -1,16 +1,19 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
import { WelcomeScreen } from '..'
-import './reset.css'
-import './app.css'
+import { styles, cssProps, colors } from '../../platform'
+import { css, compose } from 'glamor'
-// this is in place to claim 100% of the viewport and not scroll.
-const rootStyle: CSSProperties = { overflow: 'hidden', height: '100vh', display: 'flex' }
+const ROOT = compose(
+ styles.fullScreen,
+ cssProps({
+ backgroundColor: colors.background,
+ }),
+)
export class App extends React.Component<{}, {}> {
render() {
return (
-
+
)
diff --git a/src/renderer/features/app/reset.css b/src/renderer/features/app/reset.css
deleted file mode 100644
index 7bc4e53..0000000
--- a/src/renderer/features/app/reset.css
+++ /dev/null
@@ -1,76 +0,0 @@
-/* A CSS Reset. */
-
-*:focus {
- outline: 0;
-}
-html,
-body {
- user-select: none;
- cursor: default;
- -webkit-font-smoothing: subpixel-antialiased;
- text-rendering: optimizeLegibility;
- font: caption;
-}
-
-body,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-hr,
-p,
-blockquote,
-dl,
-dt,
-dd,
-ul,
-ol,
-li,
-pre,
-form,
-fieldset,
-legend,
-button,
-input,
-textarea,
-th,
-td {
- margin: 0;
- padding: 0;
- vertical-align: baseline;
-}
-
-img {
- border: 0 none;
- vertical-align: top;
-}
-
-i,
-em {
- font-style: normal;
-}
-
-ol,
-ul {
- list-style: none;
-}
-
-input,
-select,
-button,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- font-size: 100%;
- font-family: inherit;
-}
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
diff --git a/src/renderer/features/example-using-tabs/dog-tab/dog-tab.tsx b/src/renderer/features/example-using-tabs/dog-tab/dog-tab.tsx
index a681ee1..2c7e842 100644
--- a/src/renderer/features/example-using-tabs/dog-tab/dog-tab.tsx
+++ b/src/renderer/features/example-using-tabs/dog-tab/dog-tab.tsx
@@ -1,15 +1,14 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
-import { Text, CenteredContent, spacing } from '../../../platform'
-import { FunDog } from '../fun-dog/fun-dog'
-import { Logo } from '../logo/logo'
+import { Text, CenteredContent, spacing, cssProps } from '../../../platform'
+import { FunDog } from '../fun-dog'
+import { Logo } from '../logo'
-const TEXT_STYLE: CSSProperties = {
+const TEXT_STYLE = cssProps({
paddingTop: spacing.medium,
paddingBottom: spacing.medium,
-}
+})
-export class DogTab extends React.Component<{}, {}> {
+export class DogTab extends React.PureComponent<{}, {}> {
render() {
return (
diff --git a/src/renderer/features/example-using-tabs/dog-tab/index.ts b/src/renderer/features/example-using-tabs/dog-tab/index.ts
new file mode 100644
index 0000000..f684315
--- /dev/null
+++ b/src/renderer/features/example-using-tabs/dog-tab/index.ts
@@ -0,0 +1 @@
+export * from './dog-tab'
diff --git a/src/renderer/features/example-using-tabs/fun-dog/fun-dog.tsx b/src/renderer/features/example-using-tabs/fun-dog/fun-dog.tsx
index 5c0e1aa..8f85d89 100644
--- a/src/renderer/features/example-using-tabs/fun-dog/fun-dog.tsx
+++ b/src/renderer/features/example-using-tabs/fun-dog/fun-dog.tsx
@@ -1,8 +1,14 @@
import * as React from 'react'
import dogImage from './fun-dog.jpg'
+import { cssProps } from '../../../platform'
+import { css } from 'glamor'
-const style = { width: 300, borderStyle: 'solid', borderWidth: 1 }
+const ROOT = cssProps({
+ width: 300,
+ borderStyle: 'solid',
+ borderWidth: 1,
+})
export function FunDog() {
- return
+ return
}
diff --git a/src/renderer/features/example-using-tabs/fun-dog/index.ts b/src/renderer/features/example-using-tabs/fun-dog/index.ts
new file mode 100644
index 0000000..53b38e9
--- /dev/null
+++ b/src/renderer/features/example-using-tabs/fun-dog/index.ts
@@ -0,0 +1 @@
+export * from './fun-dog'
diff --git a/src/renderer/features/example-using-tabs/header/header.tsx b/src/renderer/features/example-using-tabs/header/header.tsx
index d1d6951..d3c6217 100644
--- a/src/renderer/features/example-using-tabs/header/header.tsx
+++ b/src/renderer/features/example-using-tabs/header/header.tsx
@@ -1,23 +1,25 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
-import { Text, spacing, colors, fontSizes } from '../../../platform'
+import { Text, spacing, colors, fontSizes, styles, cssProps } from '../../../platform'
import { isMac } from '../../../../shared'
import { remote } from 'electron'
+import { compose } from 'glamor'
-const ROOT_STYLE: CSSProperties = {
- WebkitAppRegion: 'drag',
- textAlign: 'center',
- paddingTop: spacing.verySmall,
- backgroundColor: colors.headerBg,
- fontSize: fontSizes.small,
-}
+const ROOT = compose(
+ styles.windowDrag,
+ cssProps({
+ textAlign: 'center',
+ paddingTop: spacing.verySmall,
+ backgroundColor: colors.headerBg,
+ fontSize: fontSizes.small,
+ }),
+)
const title = remote.require('../package.json').name
export function Header() {
if (isMac()) {
return (
-
+
{title}
)
diff --git a/src/renderer/features/example-using-tabs/header/index.ts b/src/renderer/features/example-using-tabs/header/index.ts
new file mode 100644
index 0000000..c73f6da
--- /dev/null
+++ b/src/renderer/features/example-using-tabs/header/index.ts
@@ -0,0 +1 @@
+export * from './header'
diff --git a/src/renderer/features/example-using-tabs/index.ts b/src/renderer/features/example-using-tabs/index.ts
index 4cd576c..3f283f6 100644
--- a/src/renderer/features/example-using-tabs/index.ts
+++ b/src/renderer/features/example-using-tabs/index.ts
@@ -1 +1 @@
-export * from './welcome-screen/welcome-screen'
+export * from './welcome-screen'
diff --git a/src/renderer/features/example-using-tabs/logo/index.ts b/src/renderer/features/example-using-tabs/logo/index.ts
new file mode 100644
index 0000000..e371294
--- /dev/null
+++ b/src/renderer/features/example-using-tabs/logo/index.ts
@@ -0,0 +1 @@
+export * from './logo'
diff --git a/src/renderer/features/example-using-tabs/logo/logo.tsx b/src/renderer/features/example-using-tabs/logo/logo.tsx
index adad771..2ab36bb 100644
--- a/src/renderer/features/example-using-tabs/logo/logo.tsx
+++ b/src/renderer/features/example-using-tabs/logo/logo.tsx
@@ -1,9 +1,14 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
+import { cssProps, animations } from '../../../platform'
import icon from './electron-icon.svg'
+import { css } from 'glamor'
-const style: CSSProperties = { width: 80, height: 80, animation: 'spin360 infinite 5s linear' }
+const ROOT = cssProps({
+ width: 80,
+ height: 80,
+ animation: `${animations.spin360} infinite 5s linear`,
+})
export function Logo() {
- return
+ return
}
diff --git a/src/renderer/features/example-using-tabs/long-tab/index.ts b/src/renderer/features/example-using-tabs/long-tab/index.ts
new file mode 100644
index 0000000..0af75e0
--- /dev/null
+++ b/src/renderer/features/example-using-tabs/long-tab/index.ts
@@ -0,0 +1 @@
+export * from './long-tab'
diff --git a/src/renderer/features/example-using-tabs/long-tab/long-tab.tsx b/src/renderer/features/example-using-tabs/long-tab/long-tab.tsx
index 00630b0..3665284 100644
--- a/src/renderer/features/example-using-tabs/long-tab/long-tab.tsx
+++ b/src/renderer/features/example-using-tabs/long-tab/long-tab.tsx
@@ -1,16 +1,16 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
-import { Text, ScrollableContent, spacing } from '../../../platform'
+import { Text, ScrollableContent, spacing, cssProps } from '../../../platform'
+import { css } from 'glamor'
-const PADDED_STYLE: CSSProperties = {
+const PADDED = cssProps({
paddingBottom: spacing.medium,
-}
+})
-export class LongTab extends React.Component<{}, {}> {
+export class LongTab extends React.PureComponent<{}, {}> {
render() {
return (
-
+
Lomo kombucha irony, keffiyeh man bun pitchfork helvetica organic godard brunch XOXO
subway tile. Vexillologist gluten-free prism air plant godard raw denim tacos forage
neutra kogi lyft beard. Direct trade retro ramps, pour-over slow-carb 8-bit hell of
@@ -22,7 +22,7 @@ export class LongTab extends React.Component<{}, {}> {
bicycle rights. Post-ironic selfies gochujang franzen master cleanse chicharrones ethical
coloring book keytar 8-bit poutine fixie.
-
+
Shaman glossier listicle, tousled knausgaard vegan microdosing mumblecore meditation
freegan taiyaki. Dreamcatcher occupy enamel pin edison bulb PBR&B +1 food truck try-hard
forage pug iceland sartorial scenester. Yr brooklyn pinterest +1 sustainable. Narwhal
@@ -33,7 +33,7 @@ export class LongTab extends React.Component<{}, {}> {
VHS, brooklyn salvia lyft activated charcoal direct trade mlkshk unicorn williamsburg
post-ironic banjo. Sriracha cray coloring book activated charcoal irony meditation.
-
+
Drinking vinegar 8-bit roof party leggings, master cleanse deep v slow-carb locavore
hoodie. La croix thundercats trust fund synth, truffaut woke bitters twee craft beer next
level mustache ramps yr hashtag. Portland 8-bit gentrify 3 wolf moon hexagon, 90's
@@ -49,7 +49,7 @@ export class LongTab extends React.Component<{}, {}> {
Listicle letterpress waistcoat actually, hell of typewriter normcore thundercats kale
chips post-ironic helvetica pabst.
-
+
Chambray ethical vice williamsburg. Four loko chambray glossier seitan, stumptown fanny
pack PBR&B normcore quinoa echo park. Direct trade taxidermy pok pok, unicorn you probably
haven't heard of them letterpress leggings. Flannel kinfolk four loko taxidermy fanny pack
@@ -63,7 +63,7 @@ export class LongTab extends React.Component<{}, {}> {
master cleanse wayfarers. Mlkshk sriracha microdosing, chia post-ironic paleo chillwave
PBR&B.
-
+
Ugh +1 narwhal, truffaut polaroid live-edge artisan tousled wayfarers taxidermy chia raw
denim flannel. Vinyl polaroid franzen portland tilde edison bulb, you probably haven't
heard of them hot chicken mlkshk. Prism blue bottle mustache, tattooed selvage franzen
@@ -76,9 +76,7 @@ export class LongTab extends React.Component<{}, {}> {
synth affogato pickled. Truffaut typewriter quinoa copper mug fanny pack glossier 8-bit,
meditation vape jean shorts. Ennui church-key cliche af intelligentsia, fam fingerstache.
-
- Oh. You need a little dummy text for your mockup? How quaint.
-
+ Oh. You need a little dummy text for your mockup? How quaint.
I bet you’re still using Bootstrap too…
)
diff --git a/src/renderer/features/example-using-tabs/welcome-screen/index.ts b/src/renderer/features/example-using-tabs/welcome-screen/index.ts
new file mode 100644
index 0000000..3f283f6
--- /dev/null
+++ b/src/renderer/features/example-using-tabs/welcome-screen/index.ts
@@ -0,0 +1 @@
+export * from './welcome-screen'
diff --git a/src/renderer/features/example-using-tabs/welcome-screen/sample-tabs.tsx b/src/renderer/features/example-using-tabs/welcome-screen/sample-tabs.tsx
index a275348..77eab07 100644
--- a/src/renderer/features/example-using-tabs/welcome-screen/sample-tabs.tsx
+++ b/src/renderer/features/example-using-tabs/welcome-screen/sample-tabs.tsx
@@ -1,7 +1,15 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
-import { Tab, bindKey, unbindKey, spacing, colors } from '../../../platform'
-import { isMac } from '../../../../shared'
+import {
+ Tab,
+ bindKey,
+ unbindKey,
+ spacing,
+ colors,
+ styles,
+ cssProps,
+ commandOrControlKey,
+} from '../../../platform'
+import { css, compose } from 'glamor'
export type SampleTabType = 'one' | 'two' | 'three'
@@ -10,19 +18,18 @@ export interface SampleTabsProps {
onChangeTab: (tab: SampleTabType) => void
}
-const commandOrControl = isMac() ? 'command' : 'ctrl'
-const KEY_1 = `${commandOrControl}+1`
-const KEY_2 = `${commandOrControl}+2`
-const KEY_3 = `${commandOrControl}+3`
-
-const ROOT_STYLE: CSSProperties = {
- display: 'flex',
- flexDirection: 'row',
- WebkitAppRegion: 'drag',
- paddingLeft: spacing.medium,
- paddingRight: spacing.medium,
- backgroundColor: colors.headerBg,
-}
+const KEY_1 = `${commandOrControlKey}+1`
+const KEY_2 = `${commandOrControlKey}+2`
+const KEY_3 = `${commandOrControlKey}+3`
+
+const ROOT_STYLE = compose(
+ styles.row,
+ cssProps({
+ paddingLeft: spacing.medium,
+ paddingRight: spacing.medium,
+ backgroundColor: colors.headerBg,
+ }),
+)
export class SampleTabs extends React.PureComponent {
changeTab1 = () => this.props.onChangeTab('one')
@@ -44,8 +51,8 @@ export class SampleTabs extends React.PureComponent {
render() {
const { tab } = this.props
return (
-
-
+
+
diff --git a/src/renderer/features/example-using-tabs/welcome-screen/welcome-screen.tsx b/src/renderer/features/example-using-tabs/welcome-screen/welcome-screen.tsx
index db9eafb..9bc3266 100644
--- a/src/renderer/features/example-using-tabs/welcome-screen/welcome-screen.tsx
+++ b/src/renderer/features/example-using-tabs/welcome-screen/welcome-screen.tsx
@@ -1,10 +1,11 @@
import * as React from 'react'
-import { CSSProperties } from 'react'
import { SampleTabs, SampleTabType } from './sample-tabs'
-import { LongTab } from '../long-tab/long-tab'
-import { DogTab } from '../dog-tab/dog-tab'
-import { Header } from '../header/header'
+import { LongTab } from '../long-tab'
+import { DogTab } from '../dog-tab'
+import { Header } from '../header'
+import { styles } from '../../../platform'
import Store = require('electron-store')
+import { css } from 'glamor'
// a sample store
const store = new Store()
@@ -13,12 +14,6 @@ interface WelcomeScreenState {
tab: SampleTabType
}
-const style: CSSProperties = {
- display: 'flex',
- flex: 1,
- flexDirection: 'column',
-}
-
export class WelcomeScreen extends React.Component<{}, WelcomeScreenState> {
state: WelcomeScreenState = {
tab: 'one',
@@ -40,7 +35,7 @@ export class WelcomeScreen extends React.Component<{}, WelcomeScreenState> {
render() {
return (
-
+
{this.state.tab === 'one' &&
}
diff --git a/src/renderer/platform/components/centered-content/centered-content.tsx b/src/renderer/platform/components/centered-content/centered-content.tsx
index bf0156d..9117af9 100644
--- a/src/renderer/platform/components/centered-content/centered-content.tsx
+++ b/src/renderer/platform/components/centered-content/centered-content.tsx
@@ -1,22 +1,26 @@
import * as React from 'react'
import { CSSProperties } from 'react'
+import { cssProps, styles } from '../..'
+import { compose, css } from 'glamor'
export interface CenteredContentProps {
children: React.ReactNode
+ style?: CSSProperties | CSSProperties[]
}
-const style: CSSProperties = {
- overflow: 'hidden',
- flex: 1,
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- alignItems: 'center',
-}
+const BASE = compose(
+ styles.flex1,
+ styles.column,
+ cssProps({
+ overflow: 'hidden',
+ justifyContent: 'center',
+ alignItems: 'center',
+ }),
+)
export function CenteredContent(props: CenteredContentProps) {
return (
-
+
{props.children}
)
diff --git a/src/renderer/platform/components/scrollable-content/scrollable-content.tsx b/src/renderer/platform/components/scrollable-content/scrollable-content.tsx
index db3a2b4..fd09bec 100644
--- a/src/renderer/platform/components/scrollable-content/scrollable-content.tsx
+++ b/src/renderer/platform/components/scrollable-content/scrollable-content.tsx
@@ -1,22 +1,22 @@
import * as React from 'react'
import { CSSProperties } from 'react'
-import { spacing } from '../..'
+import { spacing, styles, cssProps } from '../..'
+import { css, compose } from 'glamor'
export interface ScrollableContentProps {
- children: React.ReactNode
+ children?: React.ReactNode
+ style?: CSSProperties | CSSProperties[]
}
-const style: CSSProperties = {
- display: 'flex',
- flex: 1,
- flexDirection: 'column',
- padding: spacing.medium,
- overflowY: 'scroll',
-}
+const ROOT = compose(
+ styles.column,
+ styles.flex1,
+ cssProps({ padding: spacing.medium, overflowY: 'scroll' }),
+)
export function ScrollableContent(props: ScrollableContentProps) {
return (
-
+
{props.children}
)
diff --git a/src/renderer/platform/components/tab/tab.tsx b/src/renderer/platform/components/tab/tab.tsx
index f200c8c..e76e015 100644
--- a/src/renderer/platform/components/tab/tab.tsx
+++ b/src/renderer/platform/components/tab/tab.tsx
@@ -1,44 +1,40 @@
import * as React from 'react'
import { CSSProperties } from 'react'
-import { colors, spacing, fontSizes, Text } from '../..'
+import { colors, spacing, fontSizes, Text, styles, cssProps } from '../..'
+import { css, compose } from 'glamor'
export interface TabProps {
text: string
active?: boolean
- style?: CSSProperties
+ style?: CSSProperties | CSSProperties[]
onClick: () => void
- first?: boolean
}
-const ROOT_STYLE: CSSProperties = {
- display: 'flex',
- paddingTop: spacing.small,
- paddingBottom: spacing.small,
- marginLeft: spacing.small,
- marginRight: spacing.small,
- cursor: 'pointer',
- WebkitAppRegion: 'no-drag',
- fontSize: fontSizes.default,
-}
+const BASE = compose(
+ styles.noWindowDrag,
+ cssProps({
+ cursor: 'pointer',
+ padding: spacing.small,
+ fontSize: fontSizes.default,
+ }),
+)
-const ACTIVE_STYLE: CSSProperties = {
+const ACTIVE = cssProps({
color: colors.primary,
borderBottom: colors.primary,
borderBottomWidth: 2,
borderBottomStyle: 'solid',
-}
-
-const FIRST_STYLE: CSSProperties = { marginLeft: 0 }
+})
+/**
+ * A tab component that you click on. Not the tab panel.
+ */
export function Tab(props: TabProps) {
- const style: CSSProperties = {
- ...ROOT_STYLE,
- ...props.active ? ACTIVE_STYLE : null,
- ...props.first ? FIRST_STYLE : null,
- ...props.style,
- }
+ // work out the styles
+ const styleProps = css(BASE, props.active && ACTIVE, props.style)
+
return (
-
+
)
diff --git a/src/renderer/platform/components/text/text.test.js.md b/src/renderer/platform/components/text/text.test.js.md
index e28d00f..e24746f 100644
--- a/src/renderer/platform/components/text/text.test.js.md
+++ b/src/renderer/platform/components/text/text.test.js.md
@@ -9,14 +9,7 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
## children have priority over text
@@ -24,14 +17,7 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
one
@@ -41,14 +27,7 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
hi
@@ -58,14 +37,7 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
hello
@@ -75,15 +47,7 @@ Generated by [AVA](https://ava.li).
> Snapshot 1
one
diff --git a/src/renderer/platform/components/text/text.test.js.snap b/src/renderer/platform/components/text/text.test.js.snap
index 464c7bd..fd13f89 100644
Binary files a/src/renderer/platform/components/text/text.test.js.snap and b/src/renderer/platform/components/text/text.test.js.snap differ
diff --git a/src/renderer/platform/components/text/text.tsx b/src/renderer/platform/components/text/text.tsx
index a64fbe6..553f2eb 100644
--- a/src/renderer/platform/components/text/text.tsx
+++ b/src/renderer/platform/components/text/text.tsx
@@ -1,27 +1,25 @@
import * as React from 'react'
import { CSSProperties } from 'react'
-import { fonts, fontSizes } from '../..'
+import { fonts, fontSizes, cssProps } from '../..'
+import { css } from 'glamor'
export interface TextProps {
text?: string
children?: React.ReactNode
- style?: any
+ style?: CSSProperties | CSSProperties[]
}
-const ROOT_STYLE: CSSProperties = {
+const STYLE = cssProps({
fontSize: fontSizes.default,
fontFamily: fonts.default,
padding: 0,
margin: 0,
-}
+})
export function Text(props: TextProps) {
- const style: CSSProperties = {
- ...ROOT_STYLE,
- ...props.style,
- }
+ const styleProps = css(STYLE, props.style)
return (
-
+
{props.children || props.text}
)
diff --git a/src/renderer/platform/theme/animations.ts b/src/renderer/platform/theme/animations.ts
new file mode 100644
index 0000000..1f5b36f
--- /dev/null
+++ b/src/renderer/platform/theme/animations.ts
@@ -0,0 +1,14 @@
+import { keyframes } from 'glamor'
+
+/**
+ * Keyframe animations.
+ */
+export const animations = {
+ /**
+ * Rotate 360 degrees clockwise.
+ */
+ spin360: keyframes('spin360', {
+ '0%': { transform: 'rotate(0deg)' },
+ '100%': { transform: 'rotate(360deg)' },
+ }),
+}
diff --git a/src/renderer/platform/theme/colors.ts b/src/renderer/platform/theme/colors.ts
index ffe080c..fc74258 100644
--- a/src/renderer/platform/theme/colors.ts
+++ b/src/renderer/platform/theme/colors.ts
@@ -1,5 +1,43 @@
+/**
+ * Named colours.
+ */
+const palette = {
+ blue: '#66d',
+ cherry: '#d44',
+ white: '#fff',
+ offWhite: '#f0f0f0',
+ neutral: '#999',
+ offBlack: '#222',
+ black: '#000',
+}
+
+/**
+ * These are the various roles that colour plays in the system.
+ */
export const colors = {
- bg: '#fff',
- headerBg: '#fff',
- primary: '#66f',
+ /**
+ * The color palette if you need it, but prefer to use the other
+ * roles since it is easier to make sweeping chanegs.
+ */
+ palette,
+
+ /**
+ * The default dackground color.
+ */
+ background: palette.white,
+
+ /**
+ * The header background color.
+ */
+ headerBg: palette.white,
+
+ /**
+ * The predominant colour.
+ */
+ primary: palette.blue,
+
+ /**
+ * When something goes wrong.
+ */
+ error: palette.cherry,
}
diff --git a/src/renderer/platform/theme/index.ts b/src/renderer/platform/theme/index.ts
index 2255757..0e14c45 100644
--- a/src/renderer/platform/theme/index.ts
+++ b/src/renderer/platform/theme/index.ts
@@ -2,3 +2,5 @@ export * from './colors'
export * from './spacing'
export * from './fontSizes'
export * from './fonts'
+export * from './styles'
+export * from './animations'
diff --git a/src/renderer/platform/theme/styles.ts b/src/renderer/platform/theme/styles.ts
new file mode 100644
index 0000000..eeed62e
--- /dev/null
+++ b/src/renderer/platform/theme/styles.ts
@@ -0,0 +1,41 @@
+import { CSSProperties } from 'react'
+
+/**
+ * Typecast objects as CSSProperties. ¯\\_(ツ)_/¯
+ */
+export function cssProps(props?: CSSProperties): CSSProperties {
+ return props as CSSProperties
+}
+
+const flexbox = {
+ /** Flex the children vertically. */
+ column: cssProps({ display: 'flex', flexDirection: 'column' }),
+
+ /** Flex the children horizontally. */
+ row: cssProps({ display: 'flex', flexDirection: 'row' }),
+
+ /** Grow to the size of our parent. */
+ flex1: cssProps({ flex: 1 }),
+}
+
+const electron = {
+ /** Enable window dragging. */
+ windowDrag: cssProps({ WebkitAppRegion: 'drag' }),
+
+ /** Disable window dragging. */
+ noWindowDrag: cssProps({ WebkitAppRegion: 'no-drag' }),
+}
+
+/**
+ * Full screen and disable the scrolling.
+ */
+const fullScreen = cssProps({ overflow: 'hidden', height: '100vh', ...flexbox.column })
+
+/**
+ * Style presets.
+ */
+export const styles = {
+ ...flexbox,
+ ...electron,
+ fullScreen,
+}
diff --git a/src/renderer/platform/utils/css-reset/css-reset.ts b/src/renderer/platform/utils/css-reset/css-reset.ts
new file mode 100644
index 0000000..5745750
--- /dev/null
+++ b/src/renderer/platform/utils/css-reset/css-reset.ts
@@ -0,0 +1,16 @@
+/**
+ * Sane browser defaults.
+ */
+import 'glamor/reset'
+import { css } from 'glamor'
+
+/**
+ * Sane electron defaults.
+ */
+css.global('html, body', {
+ userSelect: 'none',
+ cursor: 'default',
+ WebkitFontSmoothing: 'subpixel-antialiased',
+ textRendering: 'optimizeLegibility',
+ font: 'caption',
+})
diff --git a/src/renderer/platform/utils/css-reset/index.ts b/src/renderer/platform/utils/css-reset/index.ts
new file mode 100644
index 0000000..20f79bc
--- /dev/null
+++ b/src/renderer/platform/utils/css-reset/index.ts
@@ -0,0 +1 @@
+export * from './css-reset'
diff --git a/src/renderer/platform/utils/index.ts b/src/renderer/platform/utils/index.ts
index ddbe779..cf450ec 100644
--- a/src/renderer/platform/utils/index.ts
+++ b/src/renderer/platform/utils/index.ts
@@ -1 +1,2 @@
+export * from './css-reset'
export * from './keyboard'
diff --git a/src/renderer/platform/utils/keyboard/keyboard.ts b/src/renderer/platform/utils/keyboard/keyboard.ts
index fa28ceb..6b3fb92 100644
--- a/src/renderer/platform/utils/keyboard/keyboard.ts
+++ b/src/renderer/platform/utils/keyboard/keyboard.ts
@@ -1,6 +1,7 @@
// A straight thru wrapper with the intention to add contexts
// which will swap out groups of keybinds at a time.
import * as Mousetrap from 'mousetrap'
+import { isMac } from '../../../../shared'
export type KeyboardCallback = (e: ExtendedKeyboardEvent, combo: string) => any
export type KeyboardAction = 'keypress' | 'keydown' | 'keyup'
@@ -10,6 +11,8 @@ if (Mousetrap.prototype) {
Mousetrap.prototype.stopCallback = () => false
}
+export const commandOrControlKey = isMac() ? 'command' : 'ctrl'
+
/**
* Binds a keystroke to a function.
*
diff --git a/src/shared/utils/index.ts b/src/shared/utils/index.ts
index a8cfc64..86119db 100644
--- a/src/shared/utils/index.ts
+++ b/src/shared/utils/index.ts
@@ -1 +1 @@
-export * from './platform/platform'
+export * from './platform'
diff --git a/src/shared/utils/platform/index.ts b/src/shared/utils/platform/index.ts
new file mode 100644
index 0000000..86119db
--- /dev/null
+++ b/src/shared/utils/platform/index.ts
@@ -0,0 +1 @@
+export * from './platform'