Skip to content

Commit

Permalink
WIP annotations sidebar refactor - structure shaping up
Browse files Browse the repository at this point in the history
  • Loading branch information
cdharris committed Jun 24, 2020
1 parent 89baf6c commit 1f4c1b2
Show file tree
Hide file tree
Showing 41 changed files with 1,005 additions and 1,048 deletions.
3 changes: 2 additions & 1 deletion docs/in-page-ui-arch.puml
Expand Up @@ -85,9 +85,10 @@ Class to hold state of what component is shown and loaded
global -> InPageUI #green

InPageUI .. CS #white
note left of CS: Can we clearly name and organise \n this part into something like \n 'script loading' as n1
note left of CS: Can we clearly name and organise \n this part into something like \n 'script loading'
package "src/content-scripts/content_script/" as CS {


component RibbonMain [
<i><u>ribbon.ts

Expand Down
241 changes: 126 additions & 115 deletions src/annotations/components/AnnotationCreate.tsx
@@ -1,157 +1,168 @@
import * as React from 'react'
import { Tooltip } from 'src/common-ui/components'
import TextInputControlled from 'src/common-ui/components/TextInputControlled'
import styled from 'styled-components'
import { browser } from 'webextension-polyfill-ts'
import { Anchor } from 'src/highlighting/types'
import { Tooltip } from 'src/common-ui/components'
import TagPicker from 'src/tags/ui/TagPicker'
import TextInputControlled from 'src/common-ui/components/TextInputControlled'
import { GenericPickerDependenciesMinusSave } from 'src/common-ui/GenericPicker/logic'
import TextHighlighted from 'src/annotations/components/parts/TextHighlighted'
import { NewAnnotationOptions } from 'src/annotations/types'
import { PickerUpdateHandler } from 'src/common-ui/GenericPicker/types'
import styled from 'styled-components'
import { ClickHandler } from 'src/in-page-ui/sidebar/react/types'
import { Anchor } from 'src/highlighting/types'
import TextHighlighted from 'src/annotations/components/TextHighlighted'

const tagEmpty = browser.extension.getURL('/img/tag_empty.svg')
const tagFull = browser.extension.getURL('/img/tag_full.svg')
const heartEmpty = browser.extension.getURL('/img/star_empty.svg')
const heartFull = browser.extension.getURL('/img/star_full.svg')

interface OwnProps {
env?: 'inpage' | 'overview'
tags: string[]
commentText: string
isCommentBookmarked: boolean
handleCommentTextChange: (comment: string) => void
saveComment: React.EventHandler<React.SyntheticEvent>
cancelComment: ClickHandler<HTMLDivElement>
toggleBookmark: ClickHandler<HTMLDivElement>
toggleTagPicker: () => void
queryTagSuggestions: (query: string) => Promise<string[]>
fetchInitialTagSuggestions: () => Promise<string[]>
updateTags: PickerUpdateHandler
anchor?: Anchor
form: Omit<CommentBoxFormProps, 'saveComment'>
interface AnnotationCreateState {
isTagPickerShown: boolean
isBookmarked: boolean
text: string
tags?: string[]
}

interface CommentBoxFormStateProps {
isTagInputActive: boolean
showTagsPicker: boolean
export interface AnnotationCreateProps {
tagPickerDependencies: GenericPickerDependenciesMinusSave
onCancel: () => void
onSave: (newAnnotation: NewAnnotationOptions) => void
anchor?: Anchor
}

export type CommentBoxFormProps = OwnProps & CommentBoxFormStateProps

class AnnotationCreate extends React.Component<CommentBoxFormProps> {
private handleTagBtnClick = (e) => {
e.preventDefault()
e.stopPropagation()
this.props.toggleTagPicker()
}

private handleCancelBtnClick = (e) => {
e.preventDefault()
e.stopPropagation()
this.props.cancelComment(e)
}

private handleBookmarkBtnClick = (e) => {
e.preventDefault()
e.stopPropagation()
this.props.toggleBookmark(e)
}

private saveComment = (e) => {
this.props.saveComment(e)
}

setTagInputActive = (isTagInputActive: boolean) => {
this.setState({ isTagInputActive })
class AnnotationCreate extends React.Component<
AnnotationCreateProps,
AnnotationCreateState
> {
state = {
isBookmarked: false,
isTagInputActive: false,
isTagPickerShown: false,
text: '',
tags: [],
}

onEnterSaveHandler = {
test: (e) => (e.ctrlKey || e.metaKey) && e.key === 'Enter',
handle: (e) => this.saveComment(e),
setTagInputActive = (isTagPickerShown: boolean) => {
this.setState({ isTagPickerShown })
}

handleClickOutside(e) {
this.props.cancelComment(e)
this.props.onCancel()
}

save = async (e) => {
e.preventDefault()
e.stopPropagation()

const { anchor, form, saveComment } = this.props
handleSave = async () => {
this.props.onSave({
anchor: this.props.anchor,
isBookmarked: this.state.isBookmarked,
tags: this.state.tags,
text: this.state.text,
})
}

return saveComment(
anchor,
form.commentText.trim(),
form.tags,
form.isCommentBookmarked,
render() {
return (
<TextBoxContainerStyled>
{this.renderHighlight()}
{this.renderInput()}
{this.renderActionButtons()}
{this.renderTagPicker()}
</TextBoxContainerStyled>
)
}

render() {
const { anchor, isCommentBookmarked } = this.props
renderHighlight() {
const { anchor } = this.props
return (
<CommentBoxContainerStyled>
<>
{!!anchor && (
<TextHighlighted
anchor={anchor}
truncateHighlight={false}
setTruncateHighlight={() => {}}
/>
)}
</>
)
}

renderInput() {
const { text } = this.state
const { hideTagPicker, handleTextChange } = this

const onEnterSaveHandler = {
test: (e) => (e.ctrlKey || e.metaKey) && e.key === 'Enter',
handle: (e) => this.props.onSave(e),
}

return (
<TextInputControlledStyled
defaultValue={text}
onClick={hideTagPicker}
placeholder="Add a private note... (save with cmd/ctrl+enter)"
onChange={handleTextChange}
specialHandlers={[onEnterSaveHandler]}
/>
)
}

handleTextChange = (text) => {
this.setState({ text })
}

renderTagPicker() {
const { tagPickerDependencies } = this.props
const { isTagPickerShown } = this.state

<TextInputControlledStyled
defaultValue={this.props.commentText}
onClick={() => {
this.setTagInputActive(false)
this.setState((state) => ({ showTagsPicker: false }))
}}
placeholder="Add a private note... (save with cmd/ctrl+enter)"
onChange={this.props.handleCommentTextChange}
specialHandlers={[this.onEnterSaveHandler]}
/>

<FooterStyled>
<Flex>
<InteractionsImgContainerStyled>
<ImgButtonStyled src={tagEmpty} />
</InteractionsImgContainerStyled>
<InteractionsImgContainerStyled>
<ImgButtonStyled
src={
isCommentBookmarked ? heartFull : heartEmpty
}
/>
</InteractionsImgContainerStyled>
</Flex>
<Flex>
<CancelBtnStyled>Cancel</CancelBtnStyled>
<SaveBtnStyled>Save</SaveBtnStyled>
</Flex>
</FooterStyled>

<TagDropdownStyled>
{this.props.showTagsPicker && (
<Tooltip position="bottomLeft">
<TagPicker
queryEntries={this.props.queryTagSuggestions}
onUpdateEntrySelection={this.props.updateTags}
loadDefaultSuggestions={
this.props.fetchInitialTagSuggestions
}
onEscapeKeyDown={this.props.toggleTagPicker}
/>
</Tooltip>
)}
</TagDropdownStyled>
</CommentBoxContainerStyled>
return (
<TagDropdownStyled>
{isTagPickerShown && (
<Tooltip position="bottomLeft">
<TagPicker
onEscapeKeyDown={this.hideTagPicker}
{...tagPickerDependencies}
onUpdateEntrySelection={this.updateTags}
/>
</Tooltip>
)}
</TagDropdownStyled>
)
}

updateTags: PickerUpdateHandler = async (args) => {
this.setState({ tags: args.selected })
}

hideTagPicker = () => {
this.setState({ isTagPickerShown: false })
}

renderActionButtons() {
const { onCancel } = this.props
const { isBookmarked } = this.state
const { handleSave } = this

return (
<FooterStyled>
<Flex>
<InteractionsImgContainerStyled>
<ImgButtonStyled src={tagEmpty} />
</InteractionsImgContainerStyled>
<InteractionsImgContainerStyled>
<ImgButtonStyled
src={isBookmarked ? heartFull : heartEmpty}
/>
</InteractionsImgContainerStyled>
</Flex>
<Flex>
<CancelBtnStyled onClick={onCancel}>Cancel</CancelBtnStyled>
<SaveBtnStyled onClick={handleSave}>Save</SaveBtnStyled>
</Flex>
</FooterStyled>
)
}
}

export default AnnotationCreate

const CommentBoxContainerStyled = styled.div`
const TextBoxContainerStyled = styled.div`
box-shadow: none;
margin-top: 1px;
cursor: default;
Expand Down
Expand Up @@ -27,7 +27,7 @@ interface State {
tags: string[]
}

class AnnotationEditForm extends React.Component<Props, State> {
class AnnotationEdit extends React.Component<Props, State> {
state: State = {
isTagInputActive: false,
commentEditText: this.props.comment ?? '',
Expand Down Expand Up @@ -130,4 +130,4 @@ class AnnotationEditForm extends React.Component<Props, State> {
}
}

export default AnnotationEditForm
export default AnnotationEdit
Expand Up @@ -4,11 +4,11 @@ import cx from 'classnames'
import niceTime from 'src/util/nice-time'
import { CrowdfundingBox } from 'src/common-ui/crowdfunding'
import { HighlightInteractionInterface } from 'src/highlighting/types'
import AnnotationEditForm, {
TagsEventProps,
} from 'src/annotations/components/old/edit/AnnotationEditForm'
import TextTruncated from 'src/annotations/components/TextTruncated'
import AnnotationView from 'src/annotations/components/AnnotationView'
import AnnotationEdit, {
TagsEventProps,
} from 'src/annotations/components/AnnotationEdit'
import TextTruncated from 'src/annotations/components/parts/TextTruncated'

const styles = require('./annotation-editable.css')
const footerStyles = require('./default-footer.css')
Expand Down Expand Up @@ -53,7 +53,7 @@ export type AnnotationViewEditableProps = AnnotationEditableGeneralProps &
AnnotationEditableEventProps &
TagsEventProps

export default class AnnotationViewEditable extends React.Component<
export default class AnnotationEditable extends React.Component<
AnnotationViewEditableProps
> {
private _boxRef: HTMLDivElement = null
Expand Down Expand Up @@ -263,7 +263,7 @@ export default class AnnotationViewEditable extends React.Component<
handleBookmarkToggle={this.handleBookmarkToggle}
/>
) : (
<AnnotationEditForm
<AnnotationEdit
rows={2}
tags={this.props.tags}
comment={this.props.comment}
Expand Down
5 changes: 2 additions & 3 deletions src/annotations/components/AnnotationView.tsx
@@ -1,7 +1,6 @@
import * as React from 'react'

import CommentTags from './comment-tags'
import AllModesFooter from './all-modes-footer'
import CommentTags from 'src/annotations/components/old/edit/comment-tags'
import AllModesFooter from './old/edit/all-modes-footer'

interface Props {
env: 'inpage' | 'overview'
Expand Down

0 comments on commit 1f4c1b2

Please sign in to comment.