Compare commits
2 Commits
5f41c5c5f4
...
5f10bce64f
Author | SHA1 | Date |
---|---|---|
Adam Veldhousen | 5f10bce64f | 4 years ago |
Adam Veldhousen | b83580fa05 | 4 years ago |
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { noop } from "../state";
|
||||
import "./EditableNoteArea.css";
|
||||
|
||||
export default function EditableNoteArea({ content = null, onSave = noop }) {
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [newContent, setNewContent] = useState(content);
|
||||
|
||||
const toggleEditMode = () => {
|
||||
setEditMode(!editMode);
|
||||
|
||||
if (editMode && newContent) {
|
||||
onSave(newContent, content);
|
||||
}
|
||||
};
|
||||
|
||||
const updateContent = ({ target }) =>
|
||||
setNewContent(target.value || newContent);
|
||||
|
||||
return (
|
||||
<section
|
||||
className="EditableNoteArea"
|
||||
onClick={toggleEditMode}
|
||||
// onDoubleClick={toggleEditMode}
|
||||
>
|
||||
{editMode ? (
|
||||
<textarea
|
||||
defaultValue={content}
|
||||
onChange={updateContent}
|
||||
></textarea>
|
||||
) : (
|
||||
<ReactMarkdown source={content} />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
import React, { useState } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { noop } from "../../state";
|
||||
|
||||
import "./EditableNoteArea.css";
|
||||
|
||||
export default function EditableNoteArea({
|
||||
content = null,
|
||||
onSave = noop,
|
||||
preview = false
|
||||
}) {
|
||||
const [newContent, setNewContent] = useState(content);
|
||||
|
||||
const updateContent = ({ target }) =>
|
||||
setNewContent(target.value || newContent);
|
||||
|
||||
return (
|
||||
<section className="EditableNoteArea">
|
||||
{!preview ? (
|
||||
<textarea defaultValue={content} onChange={updateContent} />
|
||||
) : (
|
||||
<ReactMarkdown source={content} />
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
@ -1,17 +1,42 @@
|
||||
import React from "react";
|
||||
import EditableNoteArea from "./EditableNoteArea";
|
||||
import "./NoteContent.css";
|
||||
import React, { useState } from "react";
|
||||
import { noop } from "../state";
|
||||
import EditableNoteArea from "./EditableNoteArea/EditableNoteArea";
|
||||
|
||||
import "./NoteContent.css";
|
||||
|
||||
export default function NoteContent({ note = null, onSave = noop }) {
|
||||
const [renderMarkdown, setRenderMarkdown] = useState(false);
|
||||
const { content, title } = note || {};
|
||||
|
||||
return (
|
||||
<div className="NoteContent">
|
||||
<header>
|
||||
<h2>{title}</h2>
|
||||
<header className="controls">
|
||||
<Checkbox
|
||||
label="Preview Markdown"
|
||||
onChange={checked => setRenderMarkdown(checked)}
|
||||
/>
|
||||
</header>
|
||||
<EditableNoteArea content={content} onSave={onSave} />
|
||||
<EditableNoteArea
|
||||
content={content}
|
||||
onSave={onSave}
|
||||
preview={renderMarkdown}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const Checkbox = ({
|
||||
className = "",
|
||||
onChange = noop,
|
||||
label = "checkbox",
|
||||
defaultChecked = false
|
||||
}) => (
|
||||
<div className={className}>
|
||||
<label>{label}:</label>
|
||||
<input
|
||||
type="checkbox"
|
||||
defaultChecked={defaultChecked}
|
||||
onChange={({ target }) => onChange(target.checked)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,59 +0,0 @@
|
||||
.NoteList {
|
||||
height: 25%;
|
||||
list-style-type: none;
|
||||
border-color: black;
|
||||
border-width: 2px;
|
||||
border-style: groove;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
overflow-y: scroll;
|
||||
min-height: 75px;
|
||||
}
|
||||
|
||||
.NoteList li:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.NoteList li:nth-child(even) {
|
||||
background-color: #222222;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem h2 {
|
||||
font-size: 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem .TagList {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem .TagList input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem .TagList span {
|
||||
font-size: 10pt;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem .TagList ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
font-size: 8pt;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem .TagList li {
|
||||
background-color: #333;
|
||||
padding: 2px 7px;
|
||||
border-radius: 10px;
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { noop } from "../state.js";
|
||||
import "./NoteList.css";
|
||||
|
||||
export default function NoteList({
|
||||
notes = [],
|
||||
onSelect = noop,
|
||||
onTagUpdate = noop
|
||||
}) {
|
||||
return (
|
||||
<ul className="NoteList">
|
||||
{notes.map(n => (
|
||||
<li key={n.title}>
|
||||
<a onClick={() => onSelect(n.title)}>
|
||||
<NoteListItem
|
||||
title={n.title}
|
||||
tags={n.tags}
|
||||
content={n.content}
|
||||
onTagUpdate={onTagUpdate}
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
|
||||
{notes.length === 0 && (
|
||||
<li>Click the text box above to create a note.</li>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
const NoteListItem = ({
|
||||
title = "empty note",
|
||||
tags = [],
|
||||
content = "",
|
||||
onTagUpdate = noop
|
||||
}) => (
|
||||
<div className="NoteListItem">
|
||||
<h2>{title}</h2>
|
||||
<TagList tags={tags} onTagUpdate={onTagUpdate} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const TagList = ({ tags = [], onTagUpdate = noop }) => {
|
||||
const getTags = () => tags.join(",");
|
||||
|
||||
const [state, setState] = useState({
|
||||
editMode: false,
|
||||
editTags: getTags()
|
||||
});
|
||||
|
||||
const { editMode, editTags } = state;
|
||||
|
||||
const toggleEditMode = () => {
|
||||
setState({ editMode: !editMode });
|
||||
if (editMode) {
|
||||
onTagUpdate(editTags.split(","));
|
||||
}
|
||||
};
|
||||
|
||||
const updateTags = ({ target }) =>
|
||||
setState({ editMode: editMode, editTags: target.value });
|
||||
|
||||
return (
|
||||
<span className="TagList" onDoubleClick={toggleEditMode}>
|
||||
{editMode ? (
|
||||
<input
|
||||
type="text"
|
||||
defaultValue={getTags()}
|
||||
onChange={updateTags}
|
||||
/>
|
||||
) : (
|
||||
<Fragment>
|
||||
<span>tags</span>
|
||||
<ul>
|
||||
{tags.map(t => (
|
||||
<li key={t}> {t} </li>
|
||||
))}
|
||||
</ul>
|
||||
</Fragment>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
};
|
@ -0,0 +1,57 @@
|
||||
.NoteList {
|
||||
height: 25%;
|
||||
list-style-type: none;
|
||||
border-color: black;
|
||||
border-width: 2px;
|
||||
border-style: groove;
|
||||
border-top-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
overflow-y: scroll;
|
||||
min-height: 75px;
|
||||
}
|
||||
|
||||
.NoteList li:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.NoteList li:nth-child(even) {
|
||||
background-color: #222222;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem {
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.NoteListItem .attributes {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
align-items: center;
|
||||
flex-basis: min-content;
|
||||
max-width: 35%;
|
||||
}
|
||||
|
||||
.NoteListItem .attributes .lastModified {
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.NoteList .NoteListItem h2 {
|
||||
flex: 0 1 min-content;
|
||||
white-space: pre;
|
||||
font-size: 1rem;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.NoteListItem .preview {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
color: #777;
|
||||
padding: 0 5px 0 10px;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1 2 min-content;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
import { formatRelative } from "date-fns";
|
||||
import { noop } from "../../state.js";
|
||||
import TagList from "../TagList/TagList";
|
||||
|
||||
import "./NoteList.css";
|
||||
|
||||
export default function NoteList({
|
||||
notes = [],
|
||||
onSelect = noop,
|
||||
onTagUpdate = noop
|
||||
}) {
|
||||
return (
|
||||
<ul className="NoteList">
|
||||
{notes.map(n => (
|
||||
<li key={n.title}>
|
||||
<NoteListItem
|
||||
{...n}
|
||||
onSelect={onSelect}
|
||||
onTagUpdate={onTagUpdate}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
|
||||
{notes.length === 0 && (
|
||||
<li>Click the text box above to create a note.</li>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
const NoteListItem = ({
|
||||
content,
|
||||
title,
|
||||
tags,
|
||||
lastModified,
|
||||
onSelect,
|
||||
onTagUpdate
|
||||
}) => {
|
||||
return (
|
||||
<div className="NoteListItem" onClick={() => onSelect(title)}>
|
||||
<h2>{title}</h2>
|
||||
<p className="preview">-- {content}</p>
|
||||
<span className="attributes">
|
||||
<TagList tags={tags} onTagUpdate={onTagUpdate} />
|
||||
<span className="lastModified">
|
||||
{formatRelative(new Date(lastModified), new Date())}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,32 @@
|
||||
.TagList {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.TagList input {
|
||||
max-width: 100%;
|
||||
min-width: 75px;
|
||||
}
|
||||
|
||||
.TagList span {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.TagList ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
font-size: 8pt;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.TagList li {
|
||||
margin: 0 2px;
|
||||
padding: 2px 7px;
|
||||
border-radius: 10px;
|
||||
background-color: #ccc !important;
|
||||
color: #333 !important;
|
||||
white-space: nowrap;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
import React, { Fragment, useState } from "react";
|
||||
import { noop, enterKeyPressed } from "../../state.js";
|
||||
import "./TagList.css";
|
||||
|
||||
export default function TagList({ tags = [], onTagUpdate = noop }) {
|
||||
const getTags = () => tags.join(",");
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const [editTags, setEditTags] = useState(getTags());
|
||||
|
||||
const toggleEditMode = () => {
|
||||
setEditMode(!editMode);
|
||||
if (editMode) {
|
||||
onTagUpdate(editTags.split(",").map(x => x.trim()));
|
||||
}
|
||||
};
|
||||
|
||||
const updateTags = ({ target }) => setEditTags(target.value);
|
||||
|
||||
return (
|
||||
<span className="TagList" onDoubleClick={toggleEditMode}>
|
||||
{editMode ? (
|
||||
<input
|
||||
type="text"
|
||||
style={{ width: `${editTags.length - 2}ch` }}
|
||||
defaultValue={getTags()}
|
||||
onChange={updateTags}
|
||||
onKeyPress={enterKeyPressed(toggleEditMode)}
|
||||
onBlur={() => editMode && toggleEditMode()}
|
||||
/>
|
||||
) : (
|
||||
<Fragment>
|
||||
{tags.length <= 0 && <span>tags</span>}
|
||||
<ul>
|
||||
{tags.map(t => (
|
||||
<li key={t}>{t}</li>
|
||||
))}
|
||||
</ul>
|
||||
</Fragment>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
Before Width: | Height: | Size: 2.6 KiB |
Loading…
Reference in new issue