mirror of
https://github.com/bendtherules/piktochart-create-editor.git
synced 2026-08-18 13:52:56 +00:00
Merge with exercise project
This commit is contained in:
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
# Custom from test
|
||||||
|
js/
|
||||||
|
index.html
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
## Instructions
|
||||||
|
|
||||||
|
You are required to implement a single page application that allows user to add text and image into canvas.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
Below are the basic features for the application:
|
||||||
|
|
||||||
|
- user can see the existing images from folder `images` to the images list
|
||||||
|
- user can *upload image* to folder `images` and directly added to images list
|
||||||
|
- user can *add image / text* from the menu to the canvas
|
||||||
|
- user can *move and delete the image / text* inside the canvas
|
||||||
|
- the created objects on canvas can be saved and repopulated on refresh browser
|
||||||
|
|
||||||
|
You may refer to Piktochart Editor page of how this test should look like.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
You will be given a HTML and CSS file with simple structure, and a server that allows you to upload and retrieve image. Instruction on how to run the server is included below.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Here are the expected requirements:
|
||||||
|
|
||||||
|
- App should have the features listed [above](#features)
|
||||||
|
|
||||||
|
- App should work on modern browsers (Chrome / Firefox)
|
||||||
|
|
||||||
|
- App logic and data flow are written in a functional and reactive programming concept
|
||||||
|
|
||||||
|
Separate the logic between application data state and template view / user interactions (unidirectional data flow).
|
||||||
|
|
||||||
|
- Use libraries as less as possible,
|
||||||
|
|
||||||
|
If you need to use libraries, we recommend vueJS (or any virtual DOM library), RxJS (or any streams library), Ramda (or any FP library).
|
||||||
|
Other than that, feel free to use other libraries that you're confident of.
|
||||||
|
For moving item inside the canvas, try your best to do it natively.
|
||||||
|
|
||||||
|
_note: use native HTML element `<div>` for editor canvas, not `<canvas>`_
|
||||||
|
|
||||||
|
- Code and flow should be properly documented
|
||||||
|
|
||||||
|
Help us understand your flow easier by code comments or a readme file.
|
||||||
|
|
||||||
|
- Build automated test for the app
|
||||||
|
|
||||||
|
|
||||||
|
## How to Submit
|
||||||
|
|
||||||
|
- Zip your working folder with the name `<your name>-piktojstest`
|
||||||
|
|
||||||
|
- Exclude `node_modules` folder from the zip
|
||||||
|
|
||||||
|
- If you're using github or any code management tools, you can pass us the link
|
||||||
|
|
||||||
|
- You have **one day** to complete the test. If you are not able to finish, do send us whatever you have done, we will evaluate accordingly. If you need more time to fulfill all the features and requirements, we can give you **an extra day**
|
||||||
|
|
||||||
|
Have fun programming 😊
|
||||||
|
|
||||||
|
## How To Install
|
||||||
|
|
||||||
|
To set up the environment dependencies ( node version 5++ )
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the node server
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm run start
|
||||||
|
```
|
||||||
|
|
||||||
|
Server is listening to port `8000`
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
#### get uploaded images
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /images
|
||||||
|
```
|
||||||
|
|
||||||
|
#### upload image to server
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /uploads
|
||||||
|
```
|
||||||
|
|
||||||
|
### Note
|
||||||
|
|
||||||
|
_- The name of the file input has to be `upload` as this is what the server will be reading from_
|
||||||
|
_- The server only accepts `png` and `jpeg` file format_
|
||||||
|
_- You are allowed to edit the server.js file_
|
||||||
@@ -2,12 +2,21 @@
|
|||||||
"name": "piktochart-create-editor",
|
"name": "piktochart-create-editor",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"description": "package for js candidate test",
|
||||||
|
"author": "jun",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"express": "^4.13.4",
|
||||||
|
"jquery": "^2.2.3",
|
||||||
|
"junk": "^1.0.2",
|
||||||
|
"multer": "^1.1.0",
|
||||||
|
"nodemon": "^1.9.1",
|
||||||
"react": "^16.3.1",
|
"react": "^16.3.1",
|
||||||
"react-dom": "^16.3.1",
|
"react-dom": "^16.3.1",
|
||||||
"react-scripts-ts": "2.14.0"
|
"react-scripts-ts": "2.14.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"start-server": "nodemon ./server/server.js",
|
||||||
"start": "react-scripts-ts start",
|
"start": "react-scripts-ts start",
|
||||||
"build": "react-scripts-ts build",
|
"build": "react-scripts-ts build",
|
||||||
"test": "react-scripts-ts test --env=jsdom",
|
"test": "react-scripts-ts test --env=jsdom",
|
||||||
|
|||||||
Vendored
+6760
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,41 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Canvas</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="bootstrap.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="main.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- side pane -->
|
||||||
|
<div class="sidepane col-sm-2 col-md-2 col-lg-2">
|
||||||
|
<div class="form">
|
||||||
|
<h3>Form</h3>
|
||||||
|
<input type="file" class="form-control" placeholder="Upload Your Images" name="upload">
|
||||||
|
<button id="submit" class="btn btn-default">upload</button>
|
||||||
|
<!-- Upload Form here -->
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="assets">
|
||||||
|
<h3>Assets</h3>
|
||||||
|
<div class="text">
|
||||||
|
<h4>Text</h4>
|
||||||
|
<button id="addText" class="btn btn-default">Add Text</button>
|
||||||
|
</div>
|
||||||
|
<div class="image">
|
||||||
|
<h4>Images</h4>
|
||||||
|
<ul class="list-unstyled">
|
||||||
|
<!-- List of images here -->
|
||||||
|
<!-- <li><img src="images/sample.jpeg" class="img-rounded" /></li> -->
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- canvas -->
|
||||||
|
<div class="canvas col-sm-8 col-md-8 col-lg-8">
|
||||||
|
<div class="block">
|
||||||
|
<!-- Add images and texts to here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidepane {
|
||||||
|
height: 100%;
|
||||||
|
background: #E8E8EA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidepane .form {
|
||||||
|
height: 80px;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidepane .assets {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#assetText {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.assets .text, .assets .image {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
.assets .image ul li {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
margin-right: 5px;
|
||||||
|
float: left;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.assets .image ul li img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas .block {
|
||||||
|
position: relative;
|
||||||
|
width: 600px; height: 600px;
|
||||||
|
margin: 10px;
|
||||||
|
border: 1px solid;
|
||||||
|
box-shadow: 0px 0px 5px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item.selected {
|
||||||
|
border-color: blue;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const express = require( 'express' );
|
||||||
|
const multer = require( 'multer' );
|
||||||
|
const fs = require( 'fs' );
|
||||||
|
const junk = require( 'junk' );
|
||||||
|
let app = express();
|
||||||
|
|
||||||
|
app.use( express.static('./') );
|
||||||
|
|
||||||
|
// define file name and destination to save
|
||||||
|
let storage = multer.diskStorage({
|
||||||
|
destination: (req, file, cb) => {
|
||||||
|
cb(null, __dirname + '/images')
|
||||||
|
},
|
||||||
|
filename: (req, file, cb) => {
|
||||||
|
let ext = file.originalname.split( '.' );
|
||||||
|
ext = ext[ext.length - 1];
|
||||||
|
cb(null, 'uploads-' + Date.now() + '.' + ext);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// define what file type to accept
|
||||||
|
let filter = ( req, file, cb ) => {
|
||||||
|
if ( file.mimetype == 'image/jpeg' || file.mimetype == 'image/png' ) {
|
||||||
|
cb( null, true );
|
||||||
|
} else {
|
||||||
|
cb( 'Failed: format not supported' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// set multer config
|
||||||
|
let upload = multer( {
|
||||||
|
storage: storage,
|
||||||
|
fileFilter: filter
|
||||||
|
}).single( 'upload' );
|
||||||
|
|
||||||
|
/* ===============================
|
||||||
|
ROUTE
|
||||||
|
============================== */
|
||||||
|
|
||||||
|
// route for file upload
|
||||||
|
app.post( '/uploads', ( req, res ) => {
|
||||||
|
upload( req, res, err => {
|
||||||
|
if ( err ) {
|
||||||
|
console.log( err )
|
||||||
|
res.status(400).json( {message: err} );
|
||||||
|
} else {
|
||||||
|
res.status(200).json( {
|
||||||
|
file: req.protocol + '://' + req.get('host') + '/images/' + req.file.filename
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get( '/images', ( req, res ) => {
|
||||||
|
let file_path = req.protocol + '://' + req.get('host') + '/images/';
|
||||||
|
let files = fs.readdirSync( './images/' );
|
||||||
|
files = files
|
||||||
|
.filter( junk.not ) // remove .DS_STORE etc
|
||||||
|
.map( f => file_path + f ); // map with url path
|
||||||
|
res.json( files );
|
||||||
|
});
|
||||||
|
|
||||||
|
// general route
|
||||||
|
app.get( '/', ( req, res ) => {
|
||||||
|
res.sendFile( __dirname + '/index.html' );
|
||||||
|
})
|
||||||
|
|
||||||
|
var server = app.listen( 8000, _ => {
|
||||||
|
console.log( 'server started. listening to 8000' );
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user