Skip to content
This repository has been archived by the owner on Jul 12, 2021. It is now read-only.

Commit

Permalink
Add word count for current entry
Browse files Browse the repository at this point in the history
Closes #34
  • Loading branch information
samuelmeuli committed Feb 7, 2020
1 parent 524e934 commit 10a3aa0
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 126 deletions.
9 changes: 9 additions & 0 deletions src/renderer/assets/styles/components/_editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,18 @@

.editor-toolbar {
@include background-color("background-hover");
display: flex;
align-items: center;
justify-content: space-between;
height: $input-height;
}

.word-count {
@include color("text-faded");
margin-right: $spacing-abs-medium;
line-height: 1;
}

// stylelint-disable selector-class-pattern

// Fill editor height (and compensate for paragraph spacing between the title and text)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { EditorState } from "draft-js";
import React, { ReactElement } from "react";

import FormattingButtons from "../formatting-buttons/FormattingButtons";
import WordCountWrapper from "../word-count/WordCountWrapper";

export interface CustomProps {
onTextChange: (textEditorState: EditorState) => void;
textEditorState: EditorState;
}

type Props = CustomProps;

export default function EditorToolbar(props: Props): ReactElement {
const { onTextChange, textEditorState } = props;

return (
<div
className="editor-toolbar"
onMouseDown={(e): void => {
e.preventDefault(); // Keep focus on editor when a button is clicked
}}
role="none"
>
<FormattingButtons onTextChange={onTextChange} textEditorState={textEditorState} />
<WordCountWrapper />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { EditorState, RichUtils } from "draft-js";
import BoldIcon from "feather-icons/dist/icons/bold.svg";
import ItalicIcon from "feather-icons/dist/icons/italic.svg";
import UlIcon from "feather-icons/dist/icons/list.svg";
import React, { ReactElement } from "react";

import OlIcon from "../../../../../assets/icons/ordered-list.svg";
import { translations } from "../../../../../utils/i18n";
import { iconProps } from "../../../../../utils/icons";

const STROKE_WIDTH_DEFAULT = 2;
const STROKE_WIDTH_SELECTED = 3;

export interface CustomProps {
onTextChange: (textEditorState: EditorState) => void;
textEditorState: EditorState;
}

type Props = CustomProps;

/**
* Toolbar buttons for changing the formatting of the diary entry (bold, italic, lists)
*/
export default function FormattingButtons(props: Props): ReactElement {
const { onTextChange, textEditorState } = props;

const onBoldClick = (): void => {
onTextChange(RichUtils.toggleInlineStyle(textEditorState, "BOLD"));
};

const onItalicClick = (): void => {
onTextChange(RichUtils.toggleInlineStyle(textEditorState, "ITALIC"));
};

const onOlClick = (): void => {
onTextChange(RichUtils.toggleBlockType(textEditorState, "ordered-list-item"));
};

const onUlClick = (): void => {
onTextChange(RichUtils.toggleBlockType(textEditorState, "unordered-list-item"));
};

// Detect active inline/block styles
const inlineStyle = textEditorState.getCurrentInlineStyle();
const blockType = RichUtils.getCurrentBlockType(textEditorState);
const isBold = inlineStyle.has("BOLD");
const isItalic = inlineStyle.has("ITALIC");
const isOl = blockType === "ordered-list-item";
const isUl = blockType === "unordered-list-item";

return (
<div className="formatting-buttons">
<button
type="button"
className={`button button-invisible ${isBold ? "button-active" : ""}`}
onClick={onBoldClick}
>
<BoldIcon
{...iconProps}
strokeWidth={isBold ? STROKE_WIDTH_SELECTED : STROKE_WIDTH_DEFAULT}
title={translations.bold}
/>
</button>
<button
type="button"
className={`button button-invisible ${isItalic ? "button-active" : ""}`}
onClick={onItalicClick}
>
<ItalicIcon
{...iconProps}
strokeWidth={isItalic ? STROKE_WIDTH_SELECTED : STROKE_WIDTH_DEFAULT}
title={translations.italic}
/>
</button>
<button
type="button"
className={`button button-invisible ${isUl ? "button-active" : ""}`}
onClick={onUlClick}
>
<UlIcon
{...iconProps}
strokeWidth={isUl ? STROKE_WIDTH_SELECTED : STROKE_WIDTH_DEFAULT}
title={translations.bullets}
/>
</button>
<button
type="button"
className={`button button-invisible ${isOl ? "button-active" : ""}`}
onClick={onOlClick}
>
<OlIcon
{...iconProps}
strokeWidth={isOl ? STROKE_WIDTH_SELECTED : STROKE_WIDTH_DEFAULT}
title={translations.list}
/>
</button>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { ReactElement } from "react";
import countWords from "word-count";

import { toIndexDate } from "../../../../../utils/dateFormat";

export interface StateProps {
dateSelected: Date;
entries: Entries;
}

type Props = StateProps;

/**
* Text component which indicates the number of words/characters (varies per language) for the
* currently selected diary entry
*/
export default function WordCount(props: Props): ReactElement {
const { dateSelected, entries } = props;

let wordCount = 0;

const indexDate = toIndexDate(dateSelected);

if (indexDate in entries) {
const entry = entries[indexDate];
wordCount = countWords(`${entry.title ?? ""}\n${entry.text ?? ""}`);
}

return <p className="word-count">{wordCount}</p>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { connect } from "react-redux";

import { RootState } from "../../../../../store/store";
import WordCount, { StateProps } from "./WordCount";

const mapStateToProps = (state: RootState): StateProps => ({
dateSelected: state.diary.dateSelected,
entries: state.file.entries,
});

export default connect(mapStateToProps)(WordCount);
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React, { KeyboardEvent, PureComponent, ReactNode } from "react";

import { toIndexDate, toLocaleWeekday } from "../../../../utils/dateFormat";
import { translations } from "../../../../utils/i18n";
import EditorToolbar from "../editor-toolbar/EditorToolbar";
import EditorToolbar from "../editor-toolbar/editor-toolbar/EditorToolbar";

type DraftEditorCommandExtended = DraftEditorCommand | "enter";

Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/pages/diary/Diary.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";

import EditorContainer from "../../elements/diary-editor/editor/EditorContainer";
import EditorContainer from "../../elements/editor/editor/EditorContainer";
import SidebarContainer from "../../elements/sidebar/sidebar/SidebarContainer";

const Diary: FunctionComponent<{}> = (): JSX.Element => (
Expand Down

0 comments on commit 10a3aa0

Please sign in to comment.