feat: nicer smart filters & folders theme (#795)
* fix: color add button and drop * fix: color scrollbars * fix: remove infinite scroll and fix scrollbars * fix: plus icon center * fix: navigation padding, structure simplif and naming * fix: simplify scrollbars * fix: scroll bar simplif + scheme in macos * fix: magic variables to const * refactor: extract panel ref state * refactor: remove dead code, simple macos theme
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.5999 8.00002C13.5999 8.44185 13.2417 8.80002 12.7999 8.80002H8.7999V12.8C8.7999 13.2419 8.44173 13.6 7.9999 13.6C7.55807 13.6 7.1999 13.2419 7.1999 12.8V8.80002H3.1999C2.75807 8.80002 2.3999 8.44185 2.3999 8.00002C2.3999 7.5582 2.75807 7.20002 3.1999 7.20002H7.1999V3.20002C7.1999 2.7582 7.55807 2.40002 7.9999 2.40002C8.44173 2.40002 8.7999 2.7582 8.7999 3.20002V7.20002H12.7999C13.2417 7.20002 13.5999 7.5582 13.5999 8.00002Z" />
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 548 B After Width: | Height: | Size: 525 B |
@@ -58,7 +58,6 @@ import {
|
||||
delayHide,
|
||||
elemReady,
|
||||
fileChange,
|
||||
infiniteScroll,
|
||||
lowercase,
|
||||
selectOnFocus,
|
||||
snEnter,
|
||||
@@ -150,7 +149,6 @@ const startApplication: StartApplication = async function startApplication(
|
||||
.directive('delayHide', delayHide)
|
||||
.directive('elemReady', elemReady)
|
||||
.directive('fileChange', fileChange)
|
||||
.directive('infiniteScroll', [infiniteScroll])
|
||||
.directive('lowercase', lowercase)
|
||||
.directive('selectOnFocus', ['$window', selectOnFocus])
|
||||
.directive('snEnter', snEnter);
|
||||
|
||||
@@ -12,27 +12,35 @@ import { PANEL_NAME_NAVIGATION } from '@/views/constants';
|
||||
import { PrefKey } from '@standardnotes/snjs';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { FunctionComponent } from 'preact';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'preact/hooks';
|
||||
import { useCallback, useMemo, useState } from 'preact/hooks';
|
||||
import { PremiumModalProvider } from './Premium';
|
||||
|
||||
type Props = {
|
||||
application: WebApplication;
|
||||
};
|
||||
|
||||
const NAVIGATION_SELECTOR = 'navigation';
|
||||
|
||||
const useNavigationPanelRef = (): [HTMLDivElement | null, () => void] => {
|
||||
const [panelRef, setPanelRefInternal] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const setPanelRefPublic = useCallback(() => {
|
||||
const elem = document.querySelector(
|
||||
NAVIGATION_SELECTOR
|
||||
) as HTMLDivElement | null;
|
||||
setPanelRefInternal(elem);
|
||||
}, [setPanelRefInternal]);
|
||||
|
||||
return [panelRef, setPanelRefPublic];
|
||||
};
|
||||
|
||||
export const Navigation: FunctionComponent<Props> = observer(
|
||||
({ application }) => {
|
||||
const appState = useMemo(() => application.getAppState(), [application]);
|
||||
const componentViewer = appState.foldersComponentViewer;
|
||||
const enableNativeSmartTagsFeature =
|
||||
appState.features.enableNativeSmartTagsFeature;
|
||||
const [panelRef, setPanelRef] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const elem = document.querySelector(
|
||||
'navigation'
|
||||
) as HTMLDivElement | null;
|
||||
setPanelRef(elem);
|
||||
}, [setPanelRef]);
|
||||
const [panelRef, setPanelRef] = useNavigationPanelRef();
|
||||
|
||||
const onCreateNewTag = useCallback(() => {
|
||||
appState.tags.createNewTemplate();
|
||||
@@ -53,10 +61,10 @@ export const Navigation: FunctionComponent<Props> = observer(
|
||||
return (
|
||||
<PremiumModalProvider state={appState.features}>
|
||||
<div
|
||||
id="tags-column"
|
||||
id="navigation"
|
||||
className="sn-component section"
|
||||
data-aria-label="Navigation"
|
||||
ref={setPanelRef}
|
||||
className="sn-component section tags"
|
||||
data-aria-label="Tags"
|
||||
>
|
||||
{componentViewer ? (
|
||||
<div className="component-view-container">
|
||||
@@ -69,8 +77,8 @@ export const Navigation: FunctionComponent<Props> = observer(
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div id="tags-content" className="content">
|
||||
<div className="tags-title-section section-title-bar">
|
||||
<div id="navigation-content" className="content">
|
||||
<div className="section-title-bar">
|
||||
<div className="section-title-bar-header">
|
||||
<div className="sk-h3 title">
|
||||
<span className="sk-bold">Views</span>
|
||||
@@ -89,10 +97,8 @@ export const Navigation: FunctionComponent<Props> = observer(
|
||||
</div>
|
||||
</div>
|
||||
<div className="scrollable">
|
||||
<div className="infinite-scroll">
|
||||
<SmartTagsSection appState={appState} />
|
||||
<TagsSection appState={appState} />
|
||||
</div>
|
||||
<SmartTagsSection appState={appState} />
|
||||
<TagsSection appState={appState} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -50,7 +50,7 @@ export const RootTagDropZone: React.FC<Props> = observer(
|
||||
<div
|
||||
ref={dropRef}
|
||||
className={`root-drop ${canDrop ? 'active' : ''} ${
|
||||
isOver ? 'is-over' : ''
|
||||
isOver ? 'is-drag-over' : ''
|
||||
}`}
|
||||
>
|
||||
<Icon className="color-neutral" type="link-off" />
|
||||
|
||||
@@ -13,6 +13,9 @@ type Props = {
|
||||
features: FeaturesState;
|
||||
};
|
||||
|
||||
const PADDING_BASE_PX = 14;
|
||||
const PADDING_PER_LEVEL_PX = 21;
|
||||
|
||||
const smartTagIconType = (tag: SNSmartTag): IconType => {
|
||||
if (tag.isAllTag) {
|
||||
return 'notes';
|
||||
@@ -95,7 +98,9 @@ export const SmartTagsListItem: FunctionComponent<Props> = observer(
|
||||
isFaded ? 'faded' : ''
|
||||
}`}
|
||||
onClick={selectCurrentTag}
|
||||
style={{ paddingLeft: `${level + 0.5}rem` }}
|
||||
style={{
|
||||
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
|
||||
}}
|
||||
>
|
||||
{!tag.errorDecrypting ? (
|
||||
<div className="tag-info">
|
||||
|
||||
@@ -21,6 +21,9 @@ type Props = {
|
||||
level: number;
|
||||
};
|
||||
|
||||
const PADDING_BASE_PX = 14;
|
||||
const PADDING_PER_LEVEL_PX = 21;
|
||||
|
||||
export const TagsListItem: FunctionComponent<Props> = observer(
|
||||
({ tag, features, tagsState, level }) => {
|
||||
const [title, setTitle] = useState(tag.title || '');
|
||||
@@ -151,7 +154,9 @@ export const TagsListItem: FunctionComponent<Props> = observer(
|
||||
}`}
|
||||
onClick={selectCurrentTag}
|
||||
ref={dragRef}
|
||||
style={{ paddingLeft: `${level * 21 + 10}px` }}
|
||||
style={{
|
||||
paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`,
|
||||
}}
|
||||
>
|
||||
{!tag.errorDecrypting ? (
|
||||
<div className="tag-info" title={title} ref={dropRef}>
|
||||
|
||||
@@ -13,7 +13,7 @@ export const TagsSection: FunctionComponent<Props> = observer(
|
||||
({ appState }) => {
|
||||
return (
|
||||
<section>
|
||||
<div className="tags-title-section section-title-bar">
|
||||
<div className="section-title-bar">
|
||||
<div className="section-title-bar-header">
|
||||
<TagsSectionTitle features={appState.features} />
|
||||
<TagsSectionAddButton
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { IconButton } from '@/components/IconButton';
|
||||
import { AppState } from '@/ui_models/app_state';
|
||||
import { FeaturesState } from '@/ui_models/app_state/features_state';
|
||||
import { TagsState } from '@/ui_models/app_state/tags_state';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
@@ -23,6 +22,7 @@ export const TagsSectionAddButton: FunctionComponent<Props> = observer(
|
||||
focusable={true}
|
||||
icon="add"
|
||||
title="Create a new tag"
|
||||
className="color-neutral"
|
||||
onClick={() => tags.createNewTemplate()}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@ export { clickOutside } from './click-outside';
|
||||
export { delayHide } from './delay-hide';
|
||||
export { elemReady } from './elemReady';
|
||||
export { fileChange } from './file-change';
|
||||
export { infiniteScroll } from './infiniteScroll';
|
||||
export { lowercase } from './lowercase';
|
||||
export { selectOnFocus } from './selectOnFocus';
|
||||
export { snEnter } from './snEnter';
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import { debounce } from '@/utils';
|
||||
/* @ngInject */
|
||||
export function infiniteScroll() {
|
||||
return {
|
||||
link: function (scope: ng.IScope, elem: JQLite, attrs: any) {
|
||||
const scopeAny = scope as any;
|
||||
const offset = parseInt(attrs.threshold) || 0;
|
||||
const element = elem[0];
|
||||
scopeAny.paginate = debounce(() => {
|
||||
scope.$apply(attrs.infiniteScroll);
|
||||
}, 10);
|
||||
scopeAny.onScroll = () => {
|
||||
if (
|
||||
scope.$eval(attrs.canLoad) &&
|
||||
element.scrollTop + element.offsetHeight >= element.scrollHeight - offset
|
||||
) {
|
||||
scopeAny.paginate();
|
||||
}
|
||||
};
|
||||
elem.on('scroll', scopeAny.onScroll);
|
||||
scope.$on('$destroy', () => {
|
||||
elem.off('scroll', scopeAny.onScroll);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -203,11 +203,6 @@ $footer-height: 2rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
.scrollable {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
> .content {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#tags-column {
|
||||
width: 100%;
|
||||
@import './scrollbar';
|
||||
|
||||
#navigation .scrollable {
|
||||
@include minimal_scrollbar();
|
||||
height: 100%;
|
||||
background-color: var(--sn-stylekit-background-color);
|
||||
}
|
||||
|
||||
.tags {
|
||||
width: 180px;
|
||||
#navigation {
|
||||
width: 100%;
|
||||
flex-grow: 0;
|
||||
|
||||
user-select: none;
|
||||
@@ -12,42 +16,21 @@
|
||||
-webkit-user-select: none;
|
||||
|
||||
&,
|
||||
#tags-content {
|
||||
background-color: var(--sn-stylekit-secondary-background-color);
|
||||
#navigation-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--sn-stylekit-secondary-background-color);
|
||||
}
|
||||
|
||||
.tags-title-section {
|
||||
.section-title-bar {
|
||||
color: var(--sn-stylekit-secondary-foreground-color);
|
||||
padding-top: 15px;
|
||||
padding-bottom: 8px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.infinite-scroll {
|
||||
overflow-x: hidden;
|
||||
height: inherit;
|
||||
|
||||
// Autohide scrollbar on Windows.
|
||||
@at-root {
|
||||
.windows-web &,
|
||||
.windows-desktop & {
|
||||
overflow-y: hidden;
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
overflow-y: overlay; // overlay is not supported on ff, so keep previous statement up
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no-tags-placeholder {
|
||||
padding: 0px 12px;
|
||||
font-size: 12px;
|
||||
@@ -80,12 +63,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tag {
|
||||
.tag,
|
||||
.root-drop {
|
||||
font-size: 14px;
|
||||
line-height: 18px;
|
||||
|
||||
min-height: 30px;
|
||||
padding: 5px 12px;
|
||||
padding: 5px 14px;
|
||||
cursor: pointer;
|
||||
transition: height 0.1s ease-in-out;
|
||||
position: relative;
|
||||
@@ -1,3 +1,5 @@
|
||||
@import './scrollbar';
|
||||
|
||||
notes-view {
|
||||
width: 350px;
|
||||
}
|
||||
@@ -101,25 +103,10 @@ notes-view {
|
||||
}
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.infinite-scroll {
|
||||
overflow-x: hidden;
|
||||
@include minimal_scrollbar();
|
||||
height: inherit;
|
||||
|
||||
// Autohide scrollbar on Windows.
|
||||
@at-root {
|
||||
.windows-web &,
|
||||
.windows-desktop & {
|
||||
overflow-y: hidden;
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
overflow-y: overlay; // overlay is not supported on ff, so keep previous statement up
|
||||
}
|
||||
}
|
||||
}
|
||||
background-color: var(--sn-stylekit-background-color);
|
||||
}
|
||||
|
||||
.note {
|
||||
|
||||
9
app/assets/stylesheets/_scrollbar.scss
Normal file
9
app/assets/stylesheets/_scrollbar.scss
Normal file
@@ -0,0 +1,9 @@
|
||||
@mixin minimal_scrollbar() {
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
|
||||
&:hover {
|
||||
overflow-y: auto;
|
||||
overflow-y: overlay;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
@import 'main';
|
||||
@import 'ui';
|
||||
@import 'footer';
|
||||
@import 'tags';
|
||||
@import 'navigation';
|
||||
@import 'notes';
|
||||
@import 'editor';
|
||||
@import 'menus';
|
||||
|
||||
Reference in New Issue
Block a user