Offline GraphQL Demo
- Markdown Live Preview
- Download Markdown File
- Highlight Code Syntax
- Works Offline (localStorage)
- Responsive Web
- No Redux (GraphQL Local State)
Live Demo
![Netlify Status](https://camo.githubusercontent.com/dd11927a64c5033b20f3e2385aabfb04dcfca660153dc8aa8ade885795d4e3f7/68747470733a2f2f6170692e6e65746c6966792e636f6d2f6170692f76312f6261646765732f66363830326466392d366630642d343836662d383261632d3233313663366539626433322f6465706c6f792d737461747573)
Screenshots
![](https://github.com/img/Main.png)
![](https://github.com/img/Editor.png)
Install
- apollo-cache-inmemory
- apollo-client
- graphql
- graphql-tag
- react-fontawesome
- react-router-dom
- react-markdown
- react-textarea-autosize
- A textarea component that automatically resizes textarea as content changes
- styled-components
- styled-reset
- Reset CSS for styled-components
- github-markdown-css
- prismjs
TIL
GraphQL Fragment
- Share fields across queries
fragment NameParts on Person {
firstName
lastName
}
query GetPerson {
people(id: 7) {
...NameParts
avatar(size: LARGE)
}
}
Apollo Local State Management
- Configure
apollo-link-state
is deprecated
apollo-client@2.5
can handle local state now
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { resolvers, typeDefs, defaults } from './clientState';
const cache = new InMemoryCache();
const client = new ApolloClient({
cache,
resolvers,
typeDefs
});
cache.writeData({
data: defaults // default data
});
export default client;
cache
cache.readFragment({ fragment, id })
cache.readQuery({ query })
cache.writeDate({ data: {} })
- Maniuplate or read the cache
getCacheKey({ __typename, id })
- Get a key from the cache using
__typename
and id
Query: {
note: (_, { id }, { cache, getCacheKey }) => {
const noteId = getCacheKey({ __typename: 'Note', id });
const note = cache.readFragment({ fragment: NOTE_FRAGMENT, id: noteId });
return note;
}
}
Mutation: {
createNote: (_, { title, content }, { cache }) => {
const { notes } = cache.readQuery({ query: GET_NOTES });
const newNote = { id: uuid(), title, content, __typename: 'Note' };
cache.writeData({ data: { notes: [...notes, newNote] } });
return newNote;
}
}
{
notes @client {
...
}
}
export const ADD_NOTE = gql`
mutation createNote($title: String!, $content: String) {
createNote(title: $title, content: $content) @client {...}
}
`;
import { Mutation } from 'react-apollo';
...
<Mutation mutation={ADD_NOTE}>
{createNote => <EditorContainer submit={createNote} />}
</Mutation>
submit({ variables: { id, title, content } });
react-markdown + github-markdown-css
- Renders markdown strings to HTML
- escapes HTML tags by default for security issues
import ReactMarkdown from 'react-markdown';
import MarkdownStyle from '../styles/markdown';
...
<MarkdownStyle>
<ReactMarkdown className="markdown-body" source={content} />
</MarkdownStyle>
import styled from 'styled-components';
import markdownStyles from 'github-markdown-css';
export default styled.div`${markdownStyles}`;
Create & Download File
const element = document.createElement('a');
const file = new Blob([note.content], { type: 'text/plain' });
element.href = URL.createObjectURL(file);
element.download = `${note.title}.md`;
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
react-fontawesome
npm install --save @fontawesome/fontawesome-svg-core @fontawesome/free-solid-svg-icons @fontawesome/react-fontawesome
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faChevronLeft} from '@fortawesome/free-solid-svg-icons';
...
<FontAwesomeIcon icon={faChevronLeft} size="sm" />