diff --git a/app/components/CollectionIcon.js b/app/components/CollectionIcon.js
new file mode 100644
index 00000000..a5b1c348
--- /dev/null
+++ b/app/components/CollectionIcon.js
@@ -0,0 +1,45 @@
+// @flow
+import * as React from 'react';
+import { inject, observer } from 'mobx-react';
+import { getLuminance } from 'polished';
+import { PrivateCollectionIcon, CollectionIcon } from 'outline-icons';
+import Collection from 'models/Collection';
+import { icons } from 'components/IconPicker';
+import UiStore from 'stores/UiStore';
+
+type Props = {
+ collection: Collection,
+ expanded?: boolean,
+ size?: number,
+ ui: UiStore,
+};
+
+function ResolvedCollectionIcon({ collection, expanded, size, ui }: Props) {
+ // If the chosen icon color is very dark then we invert it in dark mode
+ // otherwise it will be impossible to see against the dark background.
+ const color =
+ ui.resolvedTheme === 'dark'
+ ? getLuminance(collection.color) > 0.12
+ ? collection.color
+ : 'currentColor'
+ : collection.color;
+
+ if (collection.icon && collection.icon !== 'collection') {
+ try {
+ const Component = icons[collection.icon].component;
+ return ;
+ } catch (error) {
+ console.warn('Failed to render custom icon ' + collection.icon);
+ }
+ }
+
+ if (collection.private) {
+ return (
+
+ );
+ }
+
+ return ;
+}
+
+export default inject('ui')(observer(ResolvedCollectionIcon));
diff --git a/app/components/ColorPicker.js b/app/components/ColorPicker.js
deleted file mode 100644
index 5037dcb9..00000000
--- a/app/components/ColorPicker.js
+++ /dev/null
@@ -1,106 +0,0 @@
-// @flow
-import * as React from 'react';
-import { observable } from 'mobx';
-import { observer } from 'mobx-react';
-import { TwitterPicker } from 'react-color';
-import styled from 'styled-components';
-import Fade from 'components/Fade';
-import { LabelText } from 'components/Input';
-
-const colors = [
- '#4E5C6E',
- '#19B7FF',
- '#7F6BFF',
- '#FC7419',
- '#FC2D2D',
- '#FFE100',
- '#14CF9F',
- '#00D084',
- '#EE84F0',
- '#2F362F',
-];
-
-type Props = {
- onChange: (color: string) => void,
- value?: string,
-};
-
-@observer
-class ColorPicker extends React.Component {
- @observable isOpen: boolean = false;
- node: ?HTMLElement;
-
- componentDidMount() {
- window.addEventListener('click', this.handleClickOutside);
- }
-
- componentWillUnmount() {
- window.removeEventListener('click', this.handleClickOutside);
- }
-
- handleClose = () => {
- this.isOpen = false;
- };
-
- handleOpen = () => {
- this.isOpen = true;
- };
-
- handleClickOutside = (ev: SyntheticMouseEvent<>) => {
- // $FlowFixMe
- if (ev.target && this.node && this.node.contains(ev.target)) {
- return;
- }
-
- this.handleClose();
- };
-
- render() {
- return (
- (this.node = ref)}>
-
-
-
- {this.isOpen && (
-
- this.props.onChange(color.hex)}
- triangle="top-right"
- />
-
- )}
-
-
- );
- }
-}
-
-const Wrapper = styled('div')`
- display: inline-block;
- position: relative;
-`;
-const Floating = styled('div')`
- position: absolute;
- top: 60px;
- right: 0;
- z-index: 1;
-`;
-
-const Swatch = styled('div')`
- display: inline-block;
- width: 48px;
- height: 32px;
- border: 1px solid ${({ active, color }) => (active ? 'white' : 'transparent')};
- border-radius: 4px;
- background: ${({ color }) => color};
-`;
-
-export default ColorPicker;
diff --git a/app/components/DropdownMenu/DropdownMenu.js b/app/components/DropdownMenu/DropdownMenu.js
index abf02a3c..d4bab28b 100644
--- a/app/components/DropdownMenu/DropdownMenu.js
+++ b/app/components/DropdownMenu/DropdownMenu.js
@@ -253,6 +253,10 @@ const Menu = styled.div`
animation: ${fadeAndScaleIn} 200ms ease;
transform-origin: ${props => (props.left !== undefined ? '25%' : '75%')} 0;
background: ${props => props.theme.menuBackground};
+ ${props =>
+ props.theme.menuBorder
+ ? `border: 1px solid ${props.theme.menuBorder}`
+ : ''};
border-radius: 2px;
padding: 0.5em 0;
min-width: 180px;
@@ -261,6 +265,10 @@ const Menu = styled.div`
box-shadow: ${props => props.theme.menuShadow};
pointer-events: all;
+ hr {
+ margin: 0.5em 12px;
+ }
+
@media print {
display: none;
}
diff --git a/app/components/IconPicker.js b/app/components/IconPicker.js
new file mode 100644
index 00000000..5d60b17d
--- /dev/null
+++ b/app/components/IconPicker.js
@@ -0,0 +1,238 @@
+// @flow
+import * as React from 'react';
+import { observable } from 'mobx';
+import { observer } from 'mobx-react';
+import { TwitterPicker } from 'react-color';
+import {
+ CollectionIcon,
+ CoinsIcon,
+ AcademicCapIcon,
+ BeakerIcon,
+ BuildingBlocksIcon,
+ CloudIcon,
+ CodeIcon,
+ EditIcon,
+ EyeIcon,
+ LeafIcon,
+ LightBulbIcon,
+ MoonIcon,
+ NotepadIcon,
+ PadlockIcon,
+ PaletteIcon,
+ QuestionMarkIcon,
+ SunIcon,
+ VehicleIcon,
+} from 'outline-icons';
+import styled from 'styled-components';
+import { LabelText } from 'components/Input';
+import { DropdownMenu } from 'components/DropdownMenu';
+import NudeButton from 'components/NudeButton';
+import Flex from 'shared/components/Flex';
+
+export const icons = {
+ collection: {
+ component: CollectionIcon,
+ keywords: 'collection',
+ },
+ coins: {
+ component: CoinsIcon,
+ keywords: 'coins money finance sales income revenue cash',
+ },
+ academicCap: {
+ component: AcademicCapIcon,
+ keywords: 'learn teach lesson guide tutorial onboarding training',
+ },
+ beaker: {
+ component: BeakerIcon,
+ keywords: 'lab research experiment test',
+ },
+ buildingBlocks: {
+ component: BuildingBlocksIcon,
+ keywords: 'app blocks product prototype',
+ },
+ cloud: {
+ component: CloudIcon,
+ keywords: 'cloud service aws infrastructure',
+ },
+ code: {
+ component: CodeIcon,
+ keywords: 'developer api code development engineering programming',
+ },
+ eye: {
+ component: EyeIcon,
+ keywords: 'eye view',
+ },
+ leaf: {
+ component: LeafIcon,
+ keywords: 'leaf plant outdoors nature ecosystem climate',
+ },
+ lightbulb: {
+ component: LightBulbIcon,
+ keywords: 'lightbulb idea',
+ },
+ moon: {
+ component: MoonIcon,
+ keywords: 'night moon dark',
+ },
+ notepad: {
+ component: NotepadIcon,
+ keywords: 'journal notepad write notes',
+ },
+ padlock: {
+ component: PadlockIcon,
+ keywords: 'padlock private security authentication authorization auth',
+ },
+ palette: {
+ component: PaletteIcon,
+ keywords: 'design palette art brand',
+ },
+ pencil: {
+ component: EditIcon,
+ keywords: 'copy writing post blog',
+ },
+ question: {
+ component: QuestionMarkIcon,
+ keywords: 'question help support faq',
+ },
+ sun: {
+ component: SunIcon,
+ keywords: 'day sun weather',
+ },
+ vehicle: {
+ component: VehicleIcon,
+ keywords: 'truck car travel transport',
+ },
+};
+
+const colors = [
+ '#4E5C6E',
+ '#0366d6',
+ '#7F6BFF',
+ '#E76F51',
+ '#FC2D2D',
+ '#FFBE0B',
+ '#2A9D8F',
+ '#00D084',
+ '#EE84F0',
+ '#2F362F',
+];
+
+type Props = {
+ onOpen?: () => void,
+ onChange: (color: string, icon: string) => void,
+ icon: string,
+ color: string,
+};
+
+function preventEventBubble(event) {
+ event.stopPropagation();
+}
+
+@observer
+class IconPicker extends React.Component {
+ @observable isOpen: boolean = false;
+ node: ?HTMLElement;
+
+ componentDidMount() {
+ window.addEventListener('click', this.handleClickOutside);
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('click', this.handleClickOutside);
+ }
+
+ handleClose = () => {
+ this.isOpen = false;
+ };
+
+ handleOpen = () => {
+ this.isOpen = true;
+
+ if (this.props.onOpen) {
+ this.props.onOpen();
+ }
+ };
+
+ handleClickOutside = (ev: SyntheticMouseEvent<>) => {
+ // $FlowFixMe
+ if (ev.target && this.node && this.node.contains(ev.target)) {
+ return;
+ }
+
+ this.handleClose();
+ };
+
+ render() {
+ const Component = icons[this.props.icon || 'collection'].component;
+
+ return (
+ (this.node = ref)}>
+
+
+
+
+ }
+ >
+
+ {Object.keys(icons).map(name => {
+ const Component = icons[name].component;
+ return (
+ this.props.onChange(this.props.color, name)}
+ style={{ width: 30, height: 30 }}
+ >
+
+
+ );
+ })}
+
+
+
+ this.props.onChange(color.hex, this.props.icon)
+ }
+ colors={colors}
+ triangle="hide"
+ />
+
+
+
+ );
+ }
+}
+
+const Icons = styled.div`
+ padding: 15px 9px 9px 15px;
+ width: 276px;
+`;
+
+const LabelButton = styled(NudeButton)`
+ border: 1px solid ${props => props.theme.inputBorder};
+ width: 32px;
+ height: 32px;
+`;
+
+const IconButton = styled(NudeButton)`
+ border-radius: 4px;
+ margin: 0px 6px 6px 0px;
+ width: 30px;
+ height: 30px;
+`;
+
+const ColorPicker = styled(TwitterPicker)`
+ box-shadow: none !important;
+ background: transparent !important;
+`;
+
+const Wrapper = styled('div')`
+ display: inline-block;
+ position: relative;
+`;
+
+export default IconPicker;
diff --git a/app/components/PathToDocument.js b/app/components/PathToDocument.js
index e839638a..942b4b4e 100644
--- a/app/components/PathToDocument.js
+++ b/app/components/PathToDocument.js
@@ -2,12 +2,13 @@
import * as React from 'react';
import { observer } from 'mobx-react';
import styled from 'styled-components';
-import { GoToIcon, CollectionIcon, PrivateCollectionIcon } from 'outline-icons';
+import { GoToIcon } from 'outline-icons';
import Flex from 'shared/components/Flex';
import Document from 'models/Document';
import Collection from 'models/Collection';
import type { DocumentPath } from 'stores/CollectionsStore';
+import CollectionIcon from 'components/CollectionIcon';
type Props = {
result: DocumentPath,
@@ -41,12 +42,7 @@ class PathToDocument extends React.Component {
return (
- {collection &&
- (collection.private ? (
-
- ) : (
-
- ))}
+ {collection && }
{result.path
.map(doc => {doc.title})
.reduce((prev, curr) => [prev, , curr])}
diff --git a/app/components/Sidebar/Main.js b/app/components/Sidebar/Main.js
index c6919ee4..8c79c8b6 100644
--- a/app/components/Sidebar/Main.js
+++ b/app/components/Sidebar/Main.js
@@ -84,7 +84,7 @@ class MainSidebar extends React.Component {
}
+ icon={}
exact={false}
label="Home"
/>
@@ -93,19 +93,19 @@ class MainSidebar extends React.Component {
pathname: '/search',
state: { fromMenu: true },
}}
- icon={}
+ icon={}
label="Search"
exact={false}
/>
}
+ icon={}
exact={false}
label="Starred"
/>
}
+ icon={}
label={
Drafts{draftDocumentsCount > 0 && (
@@ -127,7 +127,7 @@ class MainSidebar extends React.Component {
}
+ icon={}
exact={false}
label="Archive"
active={
@@ -138,7 +138,7 @@ class MainSidebar extends React.Component {
/>
}
+ icon={}
exact={false}
label="Trash"
active={
@@ -149,7 +149,7 @@ class MainSidebar extends React.Component {
}
+ icon={}
label="Invite people…"
/>
)}
diff --git a/app/components/Sidebar/components/CollectionLink.js b/app/components/Sidebar/components/CollectionLink.js
index ce76b78d..107c8683 100644
--- a/app/components/Sidebar/components/CollectionLink.js
+++ b/app/components/Sidebar/components/CollectionLink.js
@@ -2,7 +2,6 @@
import * as React from 'react';
import { observer } from 'mobx-react';
import { observable } from 'mobx';
-import { CollectionIcon, PrivateCollectionIcon } from 'outline-icons';
import Collection from 'models/Collection';
import Document from 'models/Document';
import CollectionMenu from 'menus/CollectionMenu';
@@ -10,6 +9,7 @@ import UiStore from 'stores/UiStore';
import DocumentsStore from 'stores/DocumentsStore';
import SidebarLink from './SidebarLink';
import DocumentLink from './DocumentLink';
+import CollectionIcon from 'components/CollectionIcon';
import DropToImport from 'components/DropToImport';
import Flex from 'shared/components/Flex';
@@ -44,16 +44,7 @@ class CollectionLink extends React.Component {
- ) : (
-
- )
- }
+ icon={}
iconColor={collection.color}
expanded={expanded}
hideDisclosure
diff --git a/app/components/Sidebar/components/Collections.js b/app/components/Sidebar/components/Collections.js
index 3eb03cbb..10c9834e 100644
--- a/app/components/Sidebar/components/Collections.js
+++ b/app/components/Sidebar/components/Collections.js
@@ -70,7 +70,7 @@ class Collections extends React.Component {
}
+ icon={}
label="New collection…"
exact
/>
diff --git a/app/menus/NewDocumentMenu.js b/app/menus/NewDocumentMenu.js
index abc15366..33c709ee 100644
--- a/app/menus/NewDocumentMenu.js
+++ b/app/menus/NewDocumentMenu.js
@@ -3,13 +3,14 @@ import * as React from 'react';
import { observable } from 'mobx';
import { inject, observer } from 'mobx-react';
import { Redirect } from 'react-router-dom';
-import { PlusIcon, CollectionIcon, PrivateCollectionIcon } from 'outline-icons';
+import { PlusIcon } from 'outline-icons';
import { newDocumentUrl } from 'utils/routeHelpers';
import CollectionsStore from 'stores/CollectionsStore';
import PoliciesStore from 'stores/PoliciesStore';
import { DropdownMenu, DropdownMenuItem } from 'components/DropdownMenu';
import Button from 'components/Button';
+import CollectionIcon from 'components/CollectionIcon';
type Props = {
label?: React.Node,
@@ -64,12 +65,7 @@ class NewDocumentMenu extends React.Component {
onClick={() => this.handleNewDocument(collection.id)}
disabled={!can.update}
>
- {collection.private ? (
-
- ) : (
-
- )}{' '}
- {collection.name}
+ {collection.name}
);
})}
diff --git a/app/models/Collection.js b/app/models/Collection.js
index c69d7f12..4639226d 100644
--- a/app/models/Collection.js
+++ b/app/models/Collection.js
@@ -13,6 +13,7 @@ export default class Collection extends BaseModel {
id: string;
name: string;
description: string;
+ icon: string;
color: string;
private: boolean;
type: 'atlas' | 'journal';
@@ -101,7 +102,14 @@ export default class Collection extends BaseModel {
}
toJS = () => {
- return pick(this, ['id', 'name', 'color', 'description', 'private']);
+ return pick(this, [
+ 'id',
+ 'name',
+ 'color',
+ 'description',
+ 'icon',
+ 'private',
+ ]);
};
export = () => {
diff --git a/app/scenes/Collection.js b/app/scenes/Collection.js
index d7a025e4..1704e6b7 100644
--- a/app/scenes/Collection.js
+++ b/app/scenes/Collection.js
@@ -5,13 +5,7 @@ import { observer, inject } from 'mobx-react';
import { Redirect, Link, Switch, Route } from 'react-router-dom';
import styled, { withTheme } from 'styled-components';
-import {
- CollectionIcon,
- PrivateCollectionIcon,
- NewDocumentIcon,
- PlusIcon,
- PinIcon,
-} from 'outline-icons';
+import { NewDocumentIcon, PlusIcon, PinIcon } from 'outline-icons';
import RichMarkdownEditor from 'rich-markdown-editor';
import { newDocumentUrl, collectionUrl } from 'utils/routeHelpers';
@@ -42,6 +36,7 @@ import CollectionMembers from 'scenes/CollectionMembers';
import Tabs from 'components/Tabs';
import Tab from 'components/Tab';
import PaginatedDocumentList from 'components/PaginatedDocumentList';
+import CollectionIcon from 'components/CollectionIcon';
type Props = {
ui: UiStore,
@@ -210,19 +205,7 @@ class CollectionScene extends React.Component {
) : (
- {collection.private ? (
-
- ) : (
-
- )}{' '}
+ {' '}
{collection.name}
diff --git a/app/scenes/CollectionEdit.js b/app/scenes/CollectionEdit.js
index 71eecca5..881da8f5 100644
--- a/app/scenes/CollectionEdit.js
+++ b/app/scenes/CollectionEdit.js
@@ -8,7 +8,7 @@ import Button from 'components/Button';
import Switch from 'components/Switch';
import Flex from 'shared/components/Flex';
import HelpText from 'components/HelpText';
-import ColorPicker from 'components/ColorPicker';
+import IconPicker from 'components/IconPicker';
import Collection from 'models/Collection';
import UiStore from 'stores/UiStore';
@@ -22,6 +22,7 @@ type Props = {
class CollectionEdit extends React.Component {
@observable name: string;
@observable description: string = '';
+ @observable icon: string = '';
@observable color: string = '#4E5C6E';
@observable isSaving: boolean;
@observable private: boolean = false;
@@ -29,6 +30,7 @@ class CollectionEdit extends React.Component {
componentDidMount() {
this.name = this.props.collection.name;
this.description = this.props.collection.description;
+ this.icon = this.props.collection.icon;
this.color = this.props.collection.color;
this.private = this.props.collection.private;
}
@@ -41,6 +43,7 @@ class CollectionEdit extends React.Component {
await this.props.collection.save({
name: this.name,
description: this.description,
+ icon: this.icon,
color: this.color,
private: this.private,
});
@@ -61,8 +64,9 @@ class CollectionEdit extends React.Component {
this.name = ev.target.value;
};
- handleColor = (color: string) => {
+ handleChange = (color: string, icon: string) => {
this.color = color;
+ this.icon = icon;
};
handlePrivateChange = (ev: SyntheticInputEvent<*>) => {
@@ -87,7 +91,12 @@ class CollectionEdit extends React.Component {
autoFocus
flex
/>
-
+
+
{
@observable name: string = '';
@observable description: string = '';
+ @observable icon: string = '';
@observable color: string = '#4E5C6E';
@observable private: boolean = false;
@observable isSaving: boolean;
+ hasOpenedIconPicker: boolean = false;
handleSubmit = async (ev: SyntheticEvent<>) => {
ev.preventDefault();
@@ -37,6 +40,7 @@ class CollectionNew extends React.Component {
{
name: this.name,
description: this.description,
+ icon: this.icon,
color: this.color,
private: this.private,
},
@@ -56,6 +60,29 @@ class CollectionNew extends React.Component {
handleNameChange = (ev: SyntheticInputEvent<*>) => {
this.name = ev.target.value;
+
+ // If the user hasn't picked an icon yet, go ahead and suggest one based on
+ // the name of the collection. It's the little things sometimes.
+ if (!this.hasOpenedIconPicker) {
+ const keys = Object.keys(icons);
+ for (const key of keys) {
+ const icon = icons[key];
+ const keywords = icon.keywords.split(' ');
+ const namewords = this.name.toLowerCase().split(' ');
+ const matches = intersection(namewords, keywords);
+
+ if (matches.length > 0) {
+ this.icon = key;
+ return;
+ }
+ }
+
+ this.icon = 'collection';
+ }
+ };
+
+ handleIconPickerOpen = () => {
+ this.hasOpenedIconPicker = true;
};
handleDescriptionChange = getValue => {
@@ -66,8 +93,9 @@ class CollectionNew extends React.Component {
this.private = ev.target.checked;
};
- handleColor = (color: string) => {
+ handleChange = (color: string, icon: string) => {
this.color = color;
+ this.icon = icon;
};
render() {
@@ -88,7 +116,13 @@ class CollectionNew extends React.Component {
autoFocus
flex
/>
-
+
+
{
- const { name, color, description, type } = ctx.body;
+ const { name, color, description, icon, type } = ctx.body;
const isPrivate = ctx.body.private;
ctx.assertPresent(name, 'name is required');
@@ -44,6 +44,7 @@ router.post('collections.create', auth(), async ctx => {
let collection = await Collection.create({
name,
description,
+ icon,
color,
type: type || 'atlas',
teamId: user.teamId,
@@ -445,7 +446,7 @@ router.post('collections.export_all', auth(), async ctx => {
});
router.post('collections.update', auth(), async ctx => {
- const { id, name, description, color } = ctx.body;
+ const { id, name, description, icon, color } = ctx.body;
const isPrivate = ctx.body.private;
ctx.assertPresent(name, 'name is required');
@@ -480,6 +481,7 @@ router.post('collections.update', auth(), async ctx => {
collection.name = name;
collection.description = description;
+ collection.icon = icon;
collection.color = color;
collection.private = isPrivate;
diff --git a/server/migrations/20200522054958-collection-icon.js b/server/migrations/20200522054958-collection-icon.js
new file mode 100644
index 00000000..b1579f45
--- /dev/null
+++ b/server/migrations/20200522054958-collection-icon.js
@@ -0,0 +1,14 @@
+'use strict';
+
+module.exports = {
+ up: async (queryInterface, Sequelize) => {
+ await queryInterface.addColumn('collections', 'icon', {
+ type: Sequelize.TEXT,
+ allowNull: true,
+ });
+ },
+
+ down: async (queryInterface, Sequelize) => {
+ await queryInterface.removeColumn('collections', 'icon');
+ }
+};
\ No newline at end of file
diff --git a/server/models/Collection.js b/server/models/Collection.js
index 56cb055b..2b25b1de 100644
--- a/server/models/Collection.js
+++ b/server/models/Collection.js
@@ -19,6 +19,7 @@ const Collection = sequelize.define(
urlId: { type: DataTypes.STRING, unique: true },
name: DataTypes.STRING,
description: DataTypes.STRING,
+ icon: DataTypes.STRING,
color: DataTypes.STRING,
private: DataTypes.BOOLEAN,
maintainerApprovalRequired: DataTypes.BOOLEAN,
@@ -46,6 +47,12 @@ const Collection = sequelize.define(
}
);
+Collection.addHook('beforeSave', async model => {
+ if (model.icon === 'collection') {
+ model.icon = null;
+ }
+});
+
// Class methods
Collection.associate = models => {
diff --git a/server/presenters/collection.js b/server/presenters/collection.js
index b2bd8cbe..2f88ee8c 100644
--- a/server/presenters/collection.js
+++ b/server/presenters/collection.js
@@ -24,6 +24,7 @@ export default function present(collection: Collection) {
url: collection.url,
name: collection.name,
description: collection.description,
+ icon: collection.icon,
color: collection.color || '#4E5C6E',
type: collection.type,
private: collection.private,
diff --git a/shared/components/Breadcrumb.js b/shared/components/Breadcrumb.js
index 9acb622c..5696a184 100644
--- a/shared/components/Breadcrumb.js
+++ b/shared/components/Breadcrumb.js
@@ -4,19 +4,14 @@ import { observer, inject } from 'mobx-react';
import breakpoint from 'styled-components-breakpoint';
import styled from 'styled-components';
import { Link } from 'react-router-dom';
-import {
- CollectionIcon,
- PrivateCollectionIcon,
- PadlockIcon,
- GoToIcon,
- MoreIcon,
-} from 'outline-icons';
+import { PadlockIcon, GoToIcon, MoreIcon } from 'outline-icons';
import Document from 'models/Document';
import CollectionsStore from 'stores/CollectionsStore';
import { collectionUrl } from 'utils/routeHelpers';
import Flex from 'shared/components/Flex';
import BreadcrumbMenu from './BreadcrumbMenu';
+import CollectionIcon from 'components/CollectionIcon';
type Props = {
document: Document,
@@ -56,11 +51,7 @@ const Breadcrumb = observer(({ document, collections, onlyText }: Props) => {
return (
- {collection.private ? (
-
- ) : (
-
- )}{' '}
+ {' '}
{collection.name}
{isNestedDocument && (
diff --git a/shared/styles/theme.js b/shared/styles/theme.js
index 8f726c7d..09b2abd6 100644
--- a/shared/styles/theme.js
+++ b/shared/styles/theme.js
@@ -155,6 +155,7 @@ export const dark = {
sidebarText: colors.slate,
shadow: 'rgba(0, 0, 0, 0.6)',
+ menuBorder: lighten(0.1, colors.almostBlack),
menuBackground: lighten(0.015, colors.almostBlack),
menuShadow:
'0 0 0 1px rgba(0, 0, 0, 0.1), 0 8px 16px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.08), inset 0 0 1px rgba(255,255,255,.2)',
diff --git a/yarn.lock b/yarn.lock
index 2b9946b7..fdd629a6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -122,6 +122,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.9.2":
+ version "7.10.1"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.1.tgz#b6eb75cac279588d3100baecd1b9894ea2840822"
+ integrity sha512-nQbbCbQc9u/rpg1XCxoMYQTbSMVZjCDxErQ1ClCn9Pvcmv1lGads19ep0a2VsEiIJeHqjZley6EQGEC3Yo1xMA==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/template@^7.8.3":
version "7.8.6"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
@@ -7159,10 +7166,10 @@ osenv@^0.1.4:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
-outline-icons@^1.15.0, outline-icons@^1.16.0:
- version "1.16.0"
- resolved "https://registry.yarnpkg.com/outline-icons/-/outline-icons-1.16.0.tgz#0a71d2fe32170f0e00b8775681f0339f4fc8777a"
- integrity sha512-6bAk5rBGVtYiFP6AONx7NdmpFP+daKUJEev7PAjdfTVmE3bPXeSzzaGY51Y1XM8UdP5XqJICWncktRHeSfn1Pw==
+outline-icons@^1.15.0, outline-icons@^1.18.0:
+ version "1.18.0"
+ resolved "https://registry.yarnpkg.com/outline-icons/-/outline-icons-1.18.0.tgz#2f128d668b0874725b5c0656a04fd73a7f8fe418"
+ integrity sha512-odEYBLN+zFcTDhfs4af2RHUGneQBYbVgaBuI/I30BLaJQsKT2jBw2Shjie/HR8MYpZtgMwixP51XPPlGBSIqgw==
oy-vey@^0.10.0:
version "0.10.0"
@@ -7549,10 +7556,12 @@ pn@^1.1.0:
resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
-polished@1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/polished/-/polished-1.2.1.tgz#83c18a85bf9d7023477cfc7049763b657d50f0f7"
- integrity sha1-g8GKhb+dcCNHfPxwSXY7ZX1Q8Pc=
+polished@3.6.4:
+ version "3.6.4"
+ resolved "https://registry.yarnpkg.com/polished/-/polished-3.6.4.tgz#cec6bc0fbffc5d6ce5799c85bcc1bca5e63f1dee"
+ integrity sha512-21moJXCm/7EvjeKQz5w89QDDKNPCoimc83CqwZZGJluFdMXsFlMQl9lPA/OMRkoceZ19kU0anKlMgZmY7LJSJw==
+ dependencies:
+ "@babel/runtime" "^7.9.2"
popper.js@^1.14.7:
version "1.16.1"