├── .gitignore
├── README.md
├── demo
├── app.js
├── index.html
└── style.scss
├── package-lock.json
├── package.json
├── src
├── Note.js
├── NoteManager.js
└── NoteManager.scss
├── webpack.config.js
└── webpack.config.prod.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | /node_modules
3 | /dist
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Notes app using plain javascript
2 |
3 | ### Install in your project
4 | ```
5 | npm install @thecodeholic/plainjs-notes
6 | ```
7 |
8 | ### Usage
9 | ```javascript 1.8
10 | const noteManager = new NoteManager({
11 | el: document.getElementById('your_wrapper_element_id'),
12 | notes: [
13 | {
14 | title: 'sunt aut facere repellat',
15 | body: 'uia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto'
16 | },
17 | // ...
18 | ]
19 | });
20 | ```
21 |
22 | ### Methods
23 |
24 | ```javascript 1.8
25 | // Add the note at the bottom
26 | noteManager.addNote({
27 | title: '',
28 | body: ''
29 | });
30 |
31 | // Add the note at the top
32 | noteManager.prependNote({
33 | title: '',
34 | body: ''
35 | });
36 |
37 | // Remove the first note
38 | noteManager.removeNote(noteManager.notes[0]);
39 |
40 | // Update all notes and rerender
41 | noteManager.notes = [...];
42 | noteManager.renderNotes();
43 | ```
44 |
45 | ### Events
46 |
47 | ```javascript 1.8
48 | noteManager.onNoteAdd = (note) => {
49 | console.log("Note added ", note);
50 | };
51 | noteManager.onNoteChange = (note) => {
52 | console.log("Note changed ", note);
53 | };
54 | noteManager.onNoteRemove = (note) => {
55 | console.log("Note removed ", note);
56 | };
57 | ```
58 |
59 | -------------------------------------------------
60 |
61 |
62 | ### Installation and view demo
63 | 1. Clone the project
64 | 2. Go to the project root directory
65 | 3. Run `npm install`
66 |
67 | ### Running on development using [dev server](https://github.com/webpack/webpack-dev-server)
68 |
69 | Run `npm run start` to start to webpack dev server with HMR ready
70 |
71 | ### Build For production
72 |
73 | Run `npm run build` to build project's all assets in `dist` folder.
74 |
--------------------------------------------------------------------------------
/demo/app.js:
--------------------------------------------------------------------------------
1 | import './style.scss';
2 | import NoteManager from '../src/NoteManager';
3 |
4 | const noteManager = new NoteManager({
5 | el: document.getElementById('notesWrapper'),
6 | notes: [
7 | {
8 | title: 'sunt aut facere repellat',
9 | body: 'uia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto'
10 | },
11 | {
12 | title: 'qui est esse',
13 | body: 'est rerum tempore vitae
nsequi sint nihil reprehenderit dolor beatae ea dolores neque
fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis
qui aperiam non debitis possimus qui neque nisi nulla'
14 | },
15 | {
16 | title: 'nesciunt quas odio',
17 | body: 'repudiandae veniam quaerat sunt sed alias aut fugiat sit autem sed est'
18 | },
19 | {
20 | title: 'This is a demo note',
21 | body: 'Lorem ipsum dolor sit amet consectetur adipisicing elit. Modi corrupti officiis alias tenetur, tenetur iste maxime laudantium?'
22 | },
23 | {
24 | title: 'qui est esse',
25 | body: 'est rerum tempore vitae
nsequi sint nihil reprehenderit dolor beatae ea dolores neque
fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis
qui aperiam non debitis possimus qui neque nisi nulla'
26 | },
27 | ]
28 | });
29 |
30 | noteManager.onNoteAdd = (note) => {
31 | console.log("Note added ", note);
32 | };
33 | noteManager.onNoteChange = (note) => {
34 | console.log("Note changed ", note);
35 | };
36 | noteManager.onNoteRemove = (note) => {
37 | console.log("Note removed ", note);
38 | };
39 |
40 | const newNoteBtn = document.querySelector('.new-note-btn');
41 | newNoteBtn.onclick = () => {
42 | noteManager.prependNote({
43 | title: '',
44 | body: ''
45 | })
46 | };
47 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Webpack starter kit
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/style.scss:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | }
4 |
5 | body {
6 | padding: 0;
7 | margin: 0;
8 | background-color: #e4e4e4;
9 | }
10 |
11 | #notesWrapper {
12 | padding: 50px;
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@thecodeholic/plainjs-notes",
3 | "version": "1.0.0",
4 | "description": "Notes app using vanilla javascript",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "npx webpack --config webpack.config.prod.js --mode=production",
8 | "watch": "npx webpack --watch",
9 | "start": "webpack-dev-server"
10 | },
11 | "author": "Zura Sekhniashvili ",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "@babel/core": "^7.2.2",
15 | "@babel/preset-env": "^7.2.3",
16 | "babel-loader": "^8.0.5",
17 | "babel-minify-webpack-plugin": "^0.3.1",
18 | "clean-webpack-plugin": "^1.0.0",
19 | "css-loader": "^2.1.0",
20 | "html-loader": "^0.5.5",
21 | "html-webpack-plugin": "^4.0.0-beta.5",
22 | "mini-css-extract-plugin": "^0.5.0",
23 | "node-sass": "^4.11.0",
24 | "optimize-css-assets-webpack-plugin": "^5.0.1",
25 | "sass-loader": "^7.1.0",
26 | "style-loader": "^0.23.1",
27 | "webpack": "^4.28.3",
28 | "webpack-cli": "^3.2.0",
29 | "webpack-dev-server": "^3.1.14",
30 | "tar": ">=2.2.2"
31 | },
32 | "dependencies": {},
33 | "repository": {
34 | "type": "git",
35 | "url": "git+https://github.com/thecodeholic/VanillaJsNotes.git"
36 | },
37 | "bugs": {
38 | "url": "https://github.com/thecodeholic/VanillaJsNotes/issues"
39 | },
40 | "homepage": "https://github.com/thecodeholic/VanillaJsNotes#readme"
41 | }
42 |
--------------------------------------------------------------------------------
/src/Note.js:
--------------------------------------------------------------------------------
1 | export default class Note {
2 |
3 | constructor({title, body}, noteManager) {
4 | this.el = null;
5 | this.title = title;
6 | this.body = body;
7 | this.noteManager = noteManager;
8 | }
9 |
10 | static getNoteTpl() {
11 | return `
12 |
13 |
18 |
19 | {{title}}
20 |
21 |
22 | {{body}}
23 |
24 |
`;
25 | }
26 |
27 | createNoteEl() {
28 | let tpl = Note.getNoteTpl();
29 | tpl = tpl
30 | .replace('{{title}}', this.title)
31 | .replace('{{body}}', this.body)
32 | ;
33 | const div = document.createElement('div');
34 | div.innerHTML = tpl;
35 | this.el = div.children[0];
36 | this.attachEventListeners();
37 | return this.el;
38 | }
39 |
40 | attachEventListeners(){
41 | const btnClose = this.el.querySelector('.tc-note-close');
42 | btnClose.onclick = () => {
43 | this.noteManager.removeNote(this);
44 | };
45 | const title = this.el.querySelector('.tc-note-title');
46 | title.oninput = (ev) => {
47 | this.title = ev.target.innerText;
48 | this.noteManager.onNoteChange(this);
49 | };
50 | const body = this.el.querySelector('.tc-note-body');
51 | body.oninput = (ev) => {
52 | this.body = ev.target.innerText;
53 | this.noteManager.onNoteChange(this);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/NoteManager.js:
--------------------------------------------------------------------------------
1 | import './NoteManager.scss';
2 | import Note from './Note';
3 |
4 | export default class NoteManager {
5 | constructor({el, notes}) {
6 | this.el = el;
7 | this.el.className = 'tc-notes-wrapper';
8 | this.notesEl = null;
9 | this.notes = notes.map(note => new Note(note, this));
10 |
11 | this.onNoteChange = () => {
12 | };
13 | this.createNewNoteButton();
14 | this.createNotesWrapper();
15 | this.renderNotes();
16 | }
17 |
18 | addNote(note) {
19 | this.notes.push(new Note(note, this));
20 | this.renderNotes();
21 | }
22 |
23 | prependNote(note) {
24 | this.notes.unshift(new Note(note, this));
25 | this.renderNotes();
26 | }
27 |
28 | removeNote(note) {
29 | this.notes.splice(this.notes.indexOf(note), 1);
30 | this.renderNotes();
31 | }
32 |
33 | createNewNoteButton(){
34 |
35 | }
36 |
37 | createNotesWrapper() {
38 | this.notesEl = document.createElement('div');
39 | this.notesEl.className = 'tc-notes';
40 | this.el.appendChild(this.notesEl);
41 | }
42 |
43 | renderNotes() {
44 | this.notesEl.innerHTML = '';
45 | this.notes.forEach(note => this.renderNote(note));
46 | }
47 |
48 | renderNote(note) {
49 | this.notesEl.appendChild(note.createNoteEl())
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/NoteManager.scss:
--------------------------------------------------------------------------------
1 | .tc-notes-wrapper {
2 | .new-note-btn {
3 | width: 200px;
4 | display: block;
5 | margin: 0 auto 20px;
6 | background-color: #FFF;
7 | padding: 10px 32px;
8 | border: 1px solid #e0e0e0;
9 | font-size: 26px;
10 | outline: 0;
11 | transition: all 0.3s;
12 | cursor: pointer;
13 | font-family: 'Caveat', cursive;
14 |
15 | &:hover {
16 | box-shadow: 0 5px 7px rgba(0, 0, 0, 0.1);
17 | }
18 |
19 | &:active {
20 | position: relative;
21 | top: 1px;
22 | }
23 | }
24 |
25 | .tc-notes {
26 | display: flex;
27 | justify-content: center;
28 | flex-wrap: wrap;
29 | margin: 0 auto;
30 |
31 | .tc-note {
32 | background-color: #f0c806;
33 | border-radius: 8px;
34 | width: 280px;
35 | margin: 0 10px 20px;
36 | box-shadow: 1px 3px 5px rgba(0, 0, 0, 0.2);
37 | transition: all 0.5s;
38 | cursor: pointer;
39 | font-family: 'Caveat', cursive;
40 |
41 | .tc-note-header {
42 | padding: 10px 16px 0;
43 |
44 | .tc-note-close {
45 | display: inline-block;
46 | width: 24px;
47 | height: 24px;
48 | border-radius: 50%;
49 | line-height: 24px;
50 | text-align: center;
51 | transition: all 0.3s;
52 |
53 | &:hover {
54 | background-color: rgba(0, 0, 0, 0.2);
55 | }
56 |
57 | &:focus {
58 | box-shadow: inset 2px 3px 0px rgba(0, 0, 0, 0.8);
59 | }
60 | }
61 |
62 | .tc-note-close {
63 | float: right;
64 | }
65 | }
66 |
67 | .tc-note-title,
68 | .tc-note-body {
69 | outline: 0;
70 | }
71 |
72 | .tc-note-title {
73 | font-size: 24px;
74 | padding: 10px 16px;
75 | font-weight: bold;
76 | }
77 |
78 | .tc-note-body {
79 | font-size: 20px;
80 | padding: 10px 16px 16px;
81 | }
82 |
83 | &:hover {
84 | box-shadow: 2px 4px 10px rgba(0, 0, 0, 0.3);
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin');
2 | const webpack = require('webpack');
3 | const path = require('path');
4 |
5 | module.exports = function(){
6 | return {
7 | mode: 'development',
8 | entry: [
9 | './demo/app.js'
10 | ],
11 | watch: true,
12 | watchOptions: {
13 | aggregateTimeout: 300, // Process all changes which happened in this time into one rebuild
14 | poll: 1000, // Check for changes every second,
15 | ignored: /node_modules/,
16 | // ignored: [
17 | // '**/*.scss', '/node_modules/'
18 | // ]
19 | },
20 | devtool: 'source-maps',
21 | devServer: {
22 | contentBase: path.join(__dirname, 'src'),
23 | watchContentBase: true,
24 | hot: true,
25 | open: true,
26 | inline: true
27 | },
28 | plugins: [
29 | new HtmlWebpackPlugin({
30 | template: path.resolve('./demo/index.html')
31 | }),
32 | new webpack.HotModuleReplacementPlugin()
33 | ],
34 | module: {
35 | rules: [
36 | {
37 | test: /\.scss$/,
38 | use: [
39 | 'style-loader',
40 | "css-loader",
41 | "sass-loader"
42 | ]
43 | },
44 | {
45 | test: /\.m?js$/,
46 | exclude: /(node_modules|bower_components)/,
47 | use: {
48 | loader: 'babel-loader',
49 | options: {
50 | presets: ['@babel/preset-env']
51 | }
52 | }
53 | },
54 | {
55 | test: /\.(woff(2)?|ttf|otf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
56 | use: [
57 | {
58 | loader: 'file-loader',
59 | options: {
60 | name: '[name].[ext]',
61 | outputPath: 'fonts/'
62 | }
63 | }
64 | ]
65 | },
66 | {
67 | test: /\.html$/,
68 | use: {
69 | loader: 'html-loader',
70 | options: {
71 | attrs: [':src', ':href']
72 | }
73 | }
74 | },
75 | ]
76 | }
77 | };
78 | }
79 |
--------------------------------------------------------------------------------
/webpack.config.prod.js:
--------------------------------------------------------------------------------
1 | const CleanWebpackPlugin = require('clean-webpack-plugin');
2 | const HtmlWebpackPlugin = require('html-webpack-plugin');
3 | const MiniCssExtractPlugin = require("mini-css-extract-plugin");
4 | const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
5 | const MinifyPlugin = require("babel-minify-webpack-plugin");
6 | const path = require('path');
7 |
8 | module.exports = function (env, argv) {
9 | return {
10 | mode: 'production',
11 | entry: [
12 | './src/NoteManager.js'
13 | ],
14 | optimization: {
15 | minimizer: [
16 | new OptimizeCSSAssetsPlugin()
17 | ]
18 | }
19 | ,
20 | plugins: [
21 | new CleanWebpackPlugin(['dist']),
22 | new MiniCssExtractPlugin({
23 | filename: "[name].css",
24 | chunkFilename: "[id].css"
25 | }),
26 | new MinifyPlugin()
27 | ],
28 | module: {
29 | rules: [
30 | {
31 | test: /\.scss$/,
32 | use: [
33 | MiniCssExtractPlugin.loader,
34 | "css-loader",
35 | "sass-loader"
36 | ]
37 | },
38 | {
39 | test: /\.m?js$/,
40 | exclude: /(node_modules|bower_components)/,
41 | use: {
42 | loader: 'babel-loader',
43 | options: {
44 | presets: ['@babel/preset-env']
45 | }
46 | }
47 | }
48 | ]
49 | }
50 | };
51 | }
52 |
--------------------------------------------------------------------------------