Flare-k

[Add] videoDetail, css

1 -import "../scss/style.scss"; 1 +import "../scss/styles.scss";
2 - 2 +import "./videoPlayer";
3 -const something = async () => {
4 - console.log("something");
5 -};
......
File mode changed
1 +.u-avatar {
2 + height: 80px;
3 + background-color: $red;
4 + border-radius: 50%;
5 +}
1 +.user-profile {
2 + width: 100%;
3 + display: flex;
4 + align-items: center;
5 + flex-direction: column;
6 + .user-profile__header {
7 + display: flex;
8 + flex-direction: column;
9 + align-items: center;
10 + margin-bottom: 18px;
11 + .profile__username {
12 + font-size: 18px;
13 + margin-top: 15px;
14 + }
15 + }
16 + .user-profile__btns {
17 + display: flex;
18 + flex-direction: column;
19 + align-items: center;
20 + a:not(:last-child) {
21 + margin-bottom: 20px;
22 + }
23 + }
24 +}
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
10 width: 100px; 10 width: 100px;
11 margin-bottom: 25px; 11 margin-bottom: 25px;
12 } 12 }
13 + .video__author {
14 + a {
15 + color: #3498db;
16 + }
17 + }
13 .video__title, 18 .video__title,
14 .video__views, 19 .video__views,
15 .video__description { 20 .video__description {
......
1 +.videoPlayer {
2 + position: relative;
3 + &:hover {
4 + .videoPlayer__controls {
5 + opacity: 1;
6 + }
7 + }
8 + video {
9 + max-width: 100%;
10 + }
11 + .videoPlayer__controls {
12 + opacity: 0;
13 + transition: opacity 0.4s linear;
14 + color: white;
15 + position: absolute;
16 + z-index: 9;
17 + bottom: 5px;
18 + width: 100%;
19 + background-color: rgba(0, 0, 0, 0.5);
20 + padding: 10px;
21 + display: grid;
22 + grid-template-columns: repeat(3, 1fr);
23 + font-size: 16px;
24 + .videoPlayer__column:first-child {
25 + display: flex;
26 + align-items: center;
27 + span:first-child {
28 + margin-right: 10px;
29 + }
30 + }
31 + .videoPlayer__column:last-child {
32 + justify-self: end;
33 + }
34 + .videoPlayer__column:nth-child(2) {
35 + justify-self: center;
36 + }
37 + i {
38 + font-size: 25px;
39 + cursor: pointer;
40 + }
41 + }
42 +}
1 @import "config/_variables.scss"; 1 @import "config/_variables.scss";
2 @import "config/reset.scss"; 2 @import "config/reset.scss";
3 +@import "config/utils.scss";
3 @import "main.scss"; 4 @import "main.scss";
4 5
5 @import "partials/header.scss"; 6 @import "partials/header.scss";
...@@ -7,6 +8,8 @@ ...@@ -7,6 +8,8 @@
7 @import "partials/form.scss"; 8 @import "partials/form.scss";
8 @import "partials/socialLogin.scss"; 9 @import "partials/socialLogin.scss";
9 @import "partials/videoBlock.scss"; 10 @import "partials/videoBlock.scss";
11 +@import "partials/videoPlayer.scss";
10 12
11 @import "pages/home.scss"; 13 @import "pages/home.scss";
12 @import "pages/videoDetail.scss"; 14 @import "pages/videoDetail.scss";
15 +@import "pages/userProfile.scss";
......
...@@ -120,7 +120,7 @@ export const logout = (req, res) => { ...@@ -120,7 +120,7 @@ export const logout = (req, res) => {
120 120
121 export const getMe = (req, res) => 121 export const getMe = (req, res) =>
122 res.render("userDetail", { pageTitle: "User Detail", user: req.user }); 122 res.render("userDetail", { pageTitle: "User Detail", user: req.user });
123 - 123 +// req.user -> 로그인된 유저
124 // export const users = (req, res) => res.render("users", { pageTitle: "Users" }); 124 // export const users = (req, res) => res.render("users", { pageTitle: "Users" });
125 125
126 export const userDetail = async (req, res) => { 126 export const userDetail = async (req, res) => {
...@@ -128,13 +128,50 @@ export const userDetail = async (req, res) => { ...@@ -128,13 +128,50 @@ export const userDetail = async (req, res) => {
128 params: { id }, 128 params: { id },
129 } = req; // req로 부터 params의 id가져오기 129 } = req; // req로 부터 params의 id가져오기
130 try { 130 try {
131 - const user = await User.findById(id); 131 + const user = await User.findById(id).populate("videos");
132 res.render("userDetail", { pageTitle: "User Detail", user }); 132 res.render("userDetail", { pageTitle: "User Detail", user });
133 } catch (error) { 133 } catch (error) {
134 res.redirect(routes.home); 134 res.redirect(routes.home);
135 } 135 }
136 }; 136 };
137 -export const editProfile = (req, res) => 137 +export const getEditProfile = (req, res) =>
138 res.render("editProfile", { pageTitle: "Edit Profile" }); 138 res.render("editProfile", { pageTitle: "Edit Profile" });
139 -export const changePassword = (req, res) => 139 +
140 +export const postEditProfile = async (req, res) => {
141 + const {
142 + body: { name, email },
143 + file,
144 + } = req;
145 + try {
146 + // 로그인된 user의 id 가져오면 됨
147 + await User.findByIdAndUpdate(req.user.id, {
148 + name,
149 + email,
150 + avatarUrl: file ? file.path : req.user.avatarUrl,
151 + });
152 + res.redirect(routes.me);
153 + } catch (error) {
154 + res.redirect(`/users${routes.editProfile}`);
155 + }
156 +};
157 +
158 +export const getChangePassword = (req, res) =>
140 res.render("changePassword", { pageTitle: "Change Password" }); 159 res.render("changePassword", { pageTitle: "Change Password" });
160 +
161 +export const postChangePassword = async (req, res) => {
162 + const {
163 + body: { oldPassword, newPassword, newPassword1 },
164 + } = req;
165 + try {
166 + if (newPassword !== newPassword1) {
167 + res.status(400);
168 + res.redirect(`/users${routes.changePassword}`);
169 + return;
170 + }
171 + await req.user.changePassword(oldPassword, newPassword);
172 + res.redirect(routes.me);
173 + } catch (error) {
174 + res.status(400);
175 + res.redirect(`/users${routes.changePassword}`);
176 + }
177 +};
......
...@@ -46,9 +46,12 @@ export const postUpload = async (req, res) => { ...@@ -46,9 +46,12 @@ export const postUpload = async (req, res) => {
46 fileUrl: path, 46 fileUrl: path,
47 title, 47 title,
48 description, 48 description,
49 + creator: req.user.id,
49 // 여기있는 fileUrl, title, description은 videoDB의 속성이다. 50 // 여기있는 fileUrl, title, description은 videoDB의 속성이다.
50 }); 51 });
51 - console.log(newVideo); 52 + // console.log(newVideo);
53 + req.user.videos.push(newVideo.id); // user DB의 video atribute에 추가
54 + req.user.save();
52 res.redirect(routes.videoDetail(newVideo.id)); // id는 DB의 id 55 res.redirect(routes.videoDetail(newVideo.id)); // id는 DB의 id
53 // id는 mongoDB가 랜덤하게 만들어준다. 56 // id는 mongoDB가 랜덤하게 만들어준다.
54 }; 57 };
...@@ -59,7 +62,7 @@ export const videoDetail = async (req, res) => { ...@@ -59,7 +62,7 @@ export const videoDetail = async (req, res) => {
59 params: { id }, 62 params: { id },
60 } = req; 63 } = req;
61 try { 64 try {
62 - const video = await Video.findById(id); 65 + const video = await Video.findById(id).populate("creator");
63 res.render("videoDetail", { pageTitle: video.title, video }); 66 res.render("videoDetail", { pageTitle: video.title, video });
64 } catch (error) { 67 } catch (error) {
65 res.redirect(routes.home); 68 res.redirect(routes.home);
...@@ -72,7 +75,11 @@ export const getEditVideo = async (req, res) => { ...@@ -72,7 +75,11 @@ export const getEditVideo = async (req, res) => {
72 try { 75 try {
73 const video = await Video.findById(id); 76 const video = await Video.findById(id);
74 // video를 받아서 render로 통해 템플릿으로 던져준다, 77 // video를 받아서 render로 통해 템플릿으로 던져준다,
78 + if (String(video.creator) !== req.user.id) {
79 + throw Error();
80 + } else {
75 res.render("editVideo", { pageTitle: `Edit ${video.title}`, video }); 81 res.render("editVideo", { pageTitle: `Edit ${video.title}`, video });
82 + }
76 // rendering하는 순간 템플릿에선 video의 title과 description을 던져준다. 83 // rendering하는 순간 템플릿에선 video의 title과 description을 던져준다.
77 } catch (error) { 84 } catch (error) {
78 res.redirect(routes.home); 85 res.redirect(routes.home);
...@@ -99,7 +106,13 @@ export const deleteVideo = async (req, res) => { ...@@ -99,7 +106,13 @@ export const deleteVideo = async (req, res) => {
99 params: { id }, 106 params: { id },
100 } = req; 107 } = req;
101 try { 108 try {
109 + const video = await Video.findById(id);
110 + // video를 받아서 render로 통해 템플릿으로 던져준다,
111 + if (String(video.creator) !== req.user.id) {
112 + throw Error();
113 + } else {
102 await Video.findOneAndRemove({ _id: id }); 114 await Video.findOneAndRemove({ _id: id });
115 + }
103 } catch (error) { 116 } catch (error) {
104 console.log(error); 117 console.log(error);
105 } 118 }
......
...@@ -2,6 +2,7 @@ import multer from "multer"; ...@@ -2,6 +2,7 @@ import multer from "multer";
2 import routes from "./routes"; 2 import routes from "./routes";
3 3
4 const multerVideo = multer({ dest: "uploads/videos/" }); 4 const multerVideo = multer({ dest: "uploads/videos/" });
5 +const multerAvatar = multer({ dest: "uploads/avatars/" });
5 6
6 export const localsMiddleware = (req, res, next) => { 7 export const localsMiddleware = (req, res, next) => {
7 res.locals.siteName = "my Youtube"; 8 res.locals.siteName = "my Youtube";
...@@ -26,3 +27,4 @@ export const onlyPrivate = (req, res, next) => { ...@@ -26,3 +27,4 @@ export const onlyPrivate = (req, res, next) => {
26 }; 27 };
27 export const uploadVideo = multerVideo.single("videoFile"); 28 export const uploadVideo = multerVideo.single("videoFile");
28 // single에 들어간 videoFile은 upload.pug의 file 부분 input name 29 // single에 들어간 videoFile은 upload.pug의 file 부분 input name
30 +export const uploadAvatar = multerAvatar.single("avatar");
......
...@@ -10,6 +10,10 @@ const CommentSchema = new mongoose.Schema({ ...@@ -10,6 +10,10 @@ const CommentSchema = new mongoose.Schema({
10 type: Date, 10 type: Date,
11 default: Date.now, 11 default: Date.now,
12 }, 12 },
13 + creator: {
14 + type: mongoose.Schema.Types.ObjectId,
15 + ref: "User",
16 + },
13 /* 17 /*
14 18
15 video: { //video와 comment를 연결하는 방법 #2 19 video: { //video와 comment를 연결하는 방법 #2
......
...@@ -7,6 +7,18 @@ const UserSchema = new mongoose.Schema({ ...@@ -7,6 +7,18 @@ const UserSchema = new mongoose.Schema({
7 avatarUrl: String, 7 avatarUrl: String,
8 facebookId: Number, 8 facebookId: Number,
9 githubId: Number, 9 githubId: Number,
10 + comments: [
11 + {
12 + type: mongoose.Schema.Types.ObjectId, // 그 다음 어느 model에서 온 id인지 알려줘야 한다.
13 + ref: "Comment",
14 + },
15 + ],
16 + videos: [
17 + {
18 + type: mongoose.Schema.Types.ObjectId, // 그 다음 어느 model에서 온 id인지 알려줘야 한다.
19 + ref: "Video",
20 + },
21 + ],
10 }); 22 });
11 // 이 상태에서 새로운 스키마를 추가한다. 23 // 이 상태에서 새로운 스키마를 추가한다.
12 // passportLocalMongoose는 configuration object가 필요하다. 24 // passportLocalMongoose는 configuration object가 필요하다.
......
...@@ -27,6 +27,10 @@ const VideoSchema = new mongoose.Schema({ ...@@ -27,6 +27,10 @@ const VideoSchema = new mongoose.Schema({
27 ref: "Comment", 27 ref: "Comment",
28 }, 28 },
29 ], 29 ],
30 + creator: {
31 + type: mongoose.Schema.Types.ObjectId,
32 + ref: "User",
33 + },
30 }); 34 });
31 // 이제 이 스키마를 이용하여 model을 만들어준다. 35 // 이제 이 스키마를 이용하여 model을 만들어준다.
32 // 모델의 이름은 "Video" 36 // 모델의 이름은 "Video"
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
4 "description": "make Youtube Website", 4 "description": "make Youtube Website",
5 "main": "app.js", 5 "main": "app.js",
6 "scripts": { 6 "scripts": {
7 - "dev:server": "nodemon --exec babel-node init.js --delay 2 --ignore 'scss'", 7 + "dev:server": "nodemon --exec babel-node init.js --delay 2 --ignore '.scss' --ignore 'static'",
8 "dev:assets": "WEBPACK_ENV=development webpack -w", 8 "dev:assets": "WEBPACK_ENV=development webpack -w",
9 "build:assets": "WEBPACK_ENV=production webpack", 9 "build:assets": "WEBPACK_ENV=production webpack",
10 "tunnel": "ngrok http 80" 10 "tunnel": "ngrok http 80"
......
...@@ -2,15 +2,20 @@ import express from "express"; ...@@ -2,15 +2,20 @@ import express from "express";
2 import routes from "../routes"; 2 import routes from "../routes";
3 import { 3 import {
4 userDetail, 4 userDetail,
5 - editProfile, 5 + getEditProfile,
6 - changePassword, 6 + postEditProfile,
7 + getChangePassword,
8 + postChangePassword,
7 } from "../controllers/userController"; 9 } from "../controllers/userController";
8 -import { onlyPrivate } from "../middlewares"; 10 +import { onlyPrivate, uploadAvatar } from "../middlewares";
9 11
10 const userRouter = express.Router(); 12 const userRouter = express.Router();
11 13
12 -userRouter.get(routes.editProfile, onlyPrivate, editProfile); 14 +userRouter.get(routes.editProfile, onlyPrivate, getEditProfile);
13 -userRouter.get(routes.changePassword, onlyPrivate, changePassword); 15 +userRouter.post(routes.editProfile, onlyPrivate, uploadAvatar, postEditProfile);
16 +
17 +userRouter.get(routes.changePassword, onlyPrivate, getChangePassword);
18 +userRouter.post(routes.changePassword, onlyPrivate, postChangePassword);
14 userRouter.get(routes.userDetail(), userDetail); 19 userRouter.get(routes.userDetail(), userDetail);
15 20
16 export default userRouter; 21 export default userRouter;
......
...@@ -4,9 +4,9 @@ import { ...@@ -4,9 +4,9 @@ import {
4 getUpload, 4 getUpload,
5 postUpload, 5 postUpload,
6 videoDetail, 6 videoDetail,
7 + deleteVideo,
7 getEditVideo, 8 getEditVideo,
8 postEditVideo, 9 postEditVideo,
9 - deleteVideo,
10 } from "../controllers/videoController"; 10 } from "../controllers/videoController";
11 import { uploadVideo, onlyPrivate } from "../middlewares"; 11 import { uploadVideo, onlyPrivate } from "../middlewares";
12 // export const videoRouter = express.Router(); 이렇게하면 이 변수만 export하게 된다. 12 // export const videoRouter = express.Router(); 이렇게하면 이 변수만 export하게 된다.
......
...@@ -94,18 +94,29 @@ ...@@ -94,18 +94,29 @@
94 /***/ (function(module, __webpack_exports__, __webpack_require__) { 94 /***/ (function(module, __webpack_exports__, __webpack_require__) {
95 95
96 "use strict"; 96 "use strict";
97 -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _scss_style_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../scss/style.scss */ \"./assets/scss/style.scss\");\n/* harmony import */ var _scss_style_scss__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_scss_style_scss__WEBPACK_IMPORTED_MODULE_0__);\n\n\nconst something = async () => {\n console.log(\"something\");\n};\n\n\n//# sourceURL=webpack:///./assets/js/main.js?"); 97 +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _scss_styles_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../scss/styles.scss */ \"./assets/scss/styles.scss\");\n/* harmony import */ var _scss_styles_scss__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_scss_styles_scss__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _videoPlayer__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./videoPlayer */ \"./assets/js/videoPlayer.js\");\n/* harmony import */ var _videoPlayer__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_videoPlayer__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\n\n//# sourceURL=webpack:///./assets/js/main.js?");
98 98
99 /***/ }), 99 /***/ }),
100 100
101 -/***/ "./assets/scss/style.scss": 101 +/***/ "./assets/js/videoPlayer.js":
102 -/*!********************************!*\ 102 +/*!**********************************!*\
103 - !*** ./assets/scss/style.scss ***! 103 + !*** ./assets/js/videoPlayer.js ***!
104 - \********************************/ 104 + \**********************************/
105 /*! no static exports found */ 105 /*! no static exports found */
106 /***/ (function(module, exports) { 106 /***/ (function(module, exports) {
107 107
108 -eval("// removed by extract-text-webpack-plugin\n\n//# sourceURL=webpack:///./assets/scss/style.scss?"); 108 +eval("\n\n//# sourceURL=webpack:///./assets/js/videoPlayer.js?");
109 +
110 +/***/ }),
111 +
112 +/***/ "./assets/scss/styles.scss":
113 +/*!*********************************!*\
114 + !*** ./assets/scss/styles.scss ***!
115 + \*********************************/
116 +/*! no static exports found */
117 +/***/ (function(module, exports) {
118 +
119 +eval("// removed by extract-text-webpack-plugin\n\n//# sourceURL=webpack:///./assets/scss/styles.scss?");
109 120
110 /***/ }), 121 /***/ }),
111 122
......
...@@ -140,6 +140,13 @@ input { ...@@ -140,6 +140,13 @@ input {
140 input:focus, input:active { 140 input:focus, input:active {
141 outline: none; } 141 outline: none; }
142 142
143 +.u-avatar {
144 + height: 80px;
145 + background-color: #ea232c;
146 + -webkit-border-radius: 50%;
147 + -moz-border-radius: 50%;
148 + border-radius: 50%; }
149 +
143 html, 150 html,
144 body { 151 body {
145 height: 100%; } 152 height: 100%; }
...@@ -413,6 +420,49 @@ input[type="submit"] { ...@@ -413,6 +420,49 @@ input[type="submit"] {
413 font-weight: 300; 420 font-weight: 300;
414 margin-bottom: 10px; } 421 margin-bottom: 10px; }
415 422
423 +.videoPlayer {
424 + position: relative; }
425 + .videoPlayer:hover .videoPlayer__controls {
426 + opacity: 1; }
427 + .videoPlayer video {
428 + max-width: 100%; }
429 + .videoPlayer .videoPlayer__controls {
430 + opacity: 0;
431 + -webkit-transition: opacity 0.4s linear;
432 + -o-transition: opacity 0.4s linear;
433 + -moz-transition: opacity 0.4s linear;
434 + transition: opacity 0.4s linear;
435 + color: white;
436 + position: absolute;
437 + z-index: 9;
438 + bottom: 5px;
439 + width: 100%;
440 + background-color: rgba(0, 0, 0, 0.5);
441 + padding: 10px;
442 + display: grid;
443 + grid-template-columns: repeat(3, 1fr);
444 + font-size: 16px; }
445 + .videoPlayer .videoPlayer__controls .videoPlayer__column:first-child {
446 + display: -webkit-box;
447 + display: -webkit-flex;
448 + display: -moz-box;
449 + display: -ms-flexbox;
450 + display: flex;
451 + -webkit-box-align: center;
452 + -webkit-align-items: center;
453 + -moz-box-align: center;
454 + -ms-flex-align: center;
455 + align-items: center; }
456 + .videoPlayer .videoPlayer__controls .videoPlayer__column:first-child span:first-child {
457 + margin-right: 10px; }
458 + .videoPlayer .videoPlayer__controls .videoPlayer__column:last-child {
459 + justify-self: end; }
460 + .videoPlayer .videoPlayer__controls .videoPlayer__column:nth-child(2) {
461 + justify-self: center; }
462 + .videoPlayer .videoPlayer__controls i {
463 + font-size: 25px;
464 + cursor: pointer; }
465 +
416 .home-videos { 466 .home-videos {
417 display: grid; 467 display: grid;
418 grid-template-columns: repeat(6, minmax(150px, 1fr)); 468 grid-template-columns: repeat(6, minmax(150px, 1fr));
...@@ -450,6 +500,8 @@ input[type="submit"] { ...@@ -450,6 +500,8 @@ input[type="submit"] {
450 .video-detail__container .video__info button { 500 .video-detail__container .video__info button {
451 width: 100px; 501 width: 100px;
452 margin-bottom: 25px; } 502 margin-bottom: 25px; }
503 + .video-detail__container .video__info .video__author a {
504 + color: #3498db; }
453 .video-detail__container .video__info .video__title, 505 .video-detail__container .video__info .video__title,
454 .video-detail__container .video__info .video__views, 506 .video-detail__container .video__info .video__views,
455 .video-detail__container .video__info .video__description { 507 .video-detail__container .video__info .video__description {
...@@ -466,3 +518,65 @@ input[type="submit"] { ...@@ -466,3 +518,65 @@ input[type="submit"] {
466 margin-top: 25px; } 518 margin-top: 25px; }
467 .video-detail__container .video__comments .video__comment-number { 519 .video-detail__container .video__comments .video__comment-number {
468 font-size: 18px; } 520 font-size: 18px; }
521 +
522 +.user-profile {
523 + width: 100%;
524 + display: -webkit-box;
525 + display: -webkit-flex;
526 + display: -moz-box;
527 + display: -ms-flexbox;
528 + display: flex;
529 + -webkit-box-align: center;
530 + -webkit-align-items: center;
531 + -moz-box-align: center;
532 + -ms-flex-align: center;
533 + align-items: center;
534 + -webkit-box-orient: vertical;
535 + -webkit-box-direction: normal;
536 + -webkit-flex-direction: column;
537 + -moz-box-orient: vertical;
538 + -moz-box-direction: normal;
539 + -ms-flex-direction: column;
540 + flex-direction: column; }
541 + .user-profile .user-profile__header {
542 + display: -webkit-box;
543 + display: -webkit-flex;
544 + display: -moz-box;
545 + display: -ms-flexbox;
546 + display: flex;
547 + -webkit-box-orient: vertical;
548 + -webkit-box-direction: normal;
549 + -webkit-flex-direction: column;
550 + -moz-box-orient: vertical;
551 + -moz-box-direction: normal;
552 + -ms-flex-direction: column;
553 + flex-direction: column;
554 + -webkit-box-align: center;
555 + -webkit-align-items: center;
556 + -moz-box-align: center;
557 + -ms-flex-align: center;
558 + align-items: center;
559 + margin-bottom: 18px; }
560 + .user-profile .user-profile__header .profile__username {
561 + font-size: 18px;
562 + margin-top: 15px; }
563 + .user-profile .user-profile__btns {
564 + display: -webkit-box;
565 + display: -webkit-flex;
566 + display: -moz-box;
567 + display: -ms-flexbox;
568 + display: flex;
569 + -webkit-box-orient: vertical;
570 + -webkit-box-direction: normal;
571 + -webkit-flex-direction: column;
572 + -moz-box-orient: vertical;
573 + -moz-box-direction: normal;
574 + -ms-flex-direction: column;
575 + flex-direction: column;
576 + -webkit-box-align: center;
577 + -webkit-align-items: center;
578 + -moz-box-align: center;
579 + -ms-flex-align: center;
580 + align-items: center; }
581 + .user-profile .user-profile__btns a:not(:last-child) {
582 + margin-bottom: 20px; }
......
...@@ -3,7 +3,7 @@ extends layouts/main ...@@ -3,7 +3,7 @@ extends layouts/main
3 block content 3 block content
4 .form-container 4 .form-container
5 form(action=`/users${routes.changePassword}`, method="post") 5 form(action=`/users${routes.changePassword}`, method="post")
6 - input(type="password", name="oldPasswod", placeholder="Current Password") 6 + input(type="password", name="oldPassword", placeholder="Current Password")
7 input(type="password", name="newPassword", placeholder="New Password") 7 input(type="password", name="newPassword", placeholder="New Password")
8 input(type="password", name="newPassword1", placeholder="Verify New Password") 8 input(type="password", name="newPassword1", placeholder="Verify New Password")
9 input(type="submit", value="Change Password") 9 input(type="submit", value="Change Password")
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -2,12 +2,11 @@ extends layouts/main ...@@ -2,12 +2,11 @@ extends layouts/main
2 2
3 block content 3 block content
4 .form-container 4 .form-container
5 - form(action=routes.editProfile, method="post") 5 + form(action=`/users${routes.editProfile}`, method="post", enctype="multipart/form-data")
6 .fileUpload 6 .fileUpload
7 label(for="avatar") Avatar 7 label(for="avatar") Avatar
8 - input(type="file", id="avatar", name="avatar") 8 + input(type="file", id="avatar", name="avatar", accept="image/*")
9 - input(type="text", placeholder="Name", name="name") 9 + input(type="text", placeholder="Name", name="name", value=loggedUser.name)
10 - input(type="email", placeholder="Email", name="email") 10 + input(type="email", placeholder="Email", name="email", value=loggedUser.email)
11 input(type="submit", value="Update Profile") 11 input(type="submit", value="Update Profile")
12 - a.form-container__link(href=`/users${routes.changePassword}`)
13 - button Change Password
...\ No newline at end of file ...\ No newline at end of file
12 +
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -10,69 +10,3 @@ block content ...@@ -10,69 +10,3 @@ block content
10 views: item.views, 10 views: item.views,
11 videoFile:item.fileUrl 11 videoFile:item.fileUrl
12 }) 12 })
...\ No newline at end of file ...\ No newline at end of file
13 - +videoBlock({
14 - id:item.id,
15 - title:item.title,
16 - views:item.views,
17 - videoFile:item.fileUrl
18 - })
19 - +videoBlock({
20 - id:item.id,
21 - title:item.title,
22 - views:item.views,
23 - videoFile:item.fileUrl
24 - })
25 - +videoBlock({
26 - id:item.id,
27 - title:item.title,
28 - views:item.views,
29 - videoFile:item.fileUrl
30 - })
31 - +videoBlock({
32 - id:item.id,
33 - title:item.title,
34 - views:item.views,
35 - videoFile:item.fileUrl
36 - })
37 - +videoBlock({
38 - id:item.id,
39 - title:item.title,
40 - views:item.views,
41 - videoFile:item.fileUrl
42 - })
43 - +videoBlock({
44 - id:item.id,
45 - title:item.title,
46 - views:item.views,
47 - videoFile:item.fileUrl
48 - })
49 - +videoBlock({
50 - id:item.id,
51 - title:item.title,
52 - views:item.views,
53 - videoFile:item.fileUrl
54 - })
55 - +videoBlock({
56 - id:item.id,
57 - title:item.title,
58 - views:item.views,
59 - videoFile:item.fileUrl
60 - })
61 - +videoBlock({
62 - id:item.id,
63 - title:item.title,
64 - views:item.views,
65 - videoFile:item.fileUrl
66 - })
67 - +videoBlock({
68 - id:item.id,
69 - title:item.title,
70 - views:item.views,
71 - videoFile:item.fileUrl
72 - })
73 - +videoBlock({
74 - id:item.id,
75 - title:item.title,
76 - views:item.views,
77 - videoFile:item.fileUrl
78 - })
......
1 +mixin videoPlayer(video={})
2 + .videoPlayer
3 + video(src=`/${video.src}`)
4 + .videoPlayer__controls
5 + .videoPlayer__column
6 + span
7 + i.fas.fa-volume-up
8 + span
9 + |00:00 / 10:00
10 + .videoPlayer__column
11 + span
12 + i.fas.fa-play
13 + .videoPlayer__column
14 + span
15 + i.fas.fa-expand
...\ No newline at end of file ...\ No newline at end of file
1 extends layouts/main 1 extends layouts/main
2 +include mixins/videoBlock
2 3
3 block content 4 block content
4 .user-profile 5 .user-profile
5 .user-profile__header 6 .user-profile__header
6 - img.avatar(src=user.avatarUrl) 7 + img.u-avatar(src=user.avatarUrl)
7 h4.profile__username=user.name 8 h4.profile__username=user.name
9 + if user.id === loggedUser.id
10 + .user-profile__btns
11 + a(href=`/users${routes.editProfile}`)
12 + button 🖌 Edit Profile
13 + a(href=`/users${routes.changePassword}`)
14 + button 🔒 Change Password
15 + .home-videos
16 + each item in user.videos
17 + +videoBlock({
18 + id: item.id,
19 + title : item.title,
20 + views: item.views,
21 + videoFile:item.fileUrl
22 + })
...\ No newline at end of file ...\ No newline at end of file
......
1 extends layouts/main 1 extends layouts/main
2 +include mixins/videoPlayer
2 3
3 block content 4 block content
4 - .video__player 5 + .video-detail__container
5 - video(src=`/${video.fileUrl}`) 6 + +videoPlayer({
7 + src:video.fileUrl
8 + })
6 .video__info 9 .video__info
10 + if loggedUser && video.creator.id === loggedUser.id
7 a(href=routes.editVideo(video.id)) 11 a(href=routes.editVideo(video.id))
8 button Edit video 12 button Edit video
9 h5.video__title=video.title 13 h5.video__title=video.title
10 - span.video__views=video.views
11 p.video__description=video.description 14 p.video__description=video.description
12 if video.views === 1 15 if video.views === 1
13 span.video__views 1 view 16 span.video__views 1 view
14 else 17 else
15 span.video__views #{video.views} views 18 span.video__views #{video.views} views
19 + .video__author
20 + |Uploaded by
21 + a(href=routes.userDetail(video.creator.id))=video.creator.name
16 .video__comment 22 .video__comment
17 if video.comments.length === 1 23 if video.comments.length === 1
18 span.video__comment-number 1 comment 24 span.video__comment-number 1 comment
......