Flare-k

[Add and Modified] CSS and Database

1 -$bgColor: red; 1 +$red: #ea232c;
2 +$dark-red: #bb2f2a;
3 +$grey: #f5f5f5;
4 +$black: #444444;
5 +$dark-grey: #e7e7e7;
......
1 +html,
2 +body,
3 +div,
4 +span,
5 +applet,
6 +object,
7 +iframe,
8 +h1,
9 +h2,
10 +h3,
11 +h4,
12 +h5,
13 +h6,
14 +p,
15 +blockquote,
16 +pre,
17 +a,
18 +abbr,
19 +acronym,
20 +address,
21 +big,
22 +cite,
23 +code,
24 +del,
25 +dfn,
26 +em,
27 +img,
28 +ins,
29 +kbd,
30 +q,
31 +s,
32 +samp,
33 +small,
34 +strike,
35 +strong,
36 +sub,
37 +sup,
38 +tt,
39 +var,
40 +b,
41 +u,
42 +i,
43 +center,
44 +dl,
45 +dt,
46 +dd,
47 +ol,
48 +ul,
49 +li,
50 +fieldset,
51 +form,
52 +label,
53 +legend,
54 +table,
55 +caption,
56 +tbody,
57 +tfoot,
58 +thead,
59 +tr,
60 +th,
61 +td,
62 +article,
63 +aside,
64 +canvas,
65 +details,
66 +embed,
67 +figure,
68 +figcaption,
69 +footer,
70 +header,
71 +hgroup,
72 +menu,
73 +nav,
74 +output,
75 +ruby,
76 +section,
77 +summary,
78 +time,
79 +mark,
80 +audio,
81 +video {
82 + margin: 0;
83 + padding: 0;
84 + border: 0;
85 + font-size: 100%;
86 + font: inherit;
87 + vertical-align: baseline;
88 +}
89 +/* HTML5 display-role reset for older browsers */
90 +article,
91 +aside,
92 +details,
93 +figcaption,
94 +figure,
95 +footer,
96 +header,
97 +hgroup,
98 +menu,
99 +nav,
100 +section {
101 + display: block;
102 +}
103 +body {
104 + line-height: 1;
105 +}
106 +ol,
107 +ul {
108 + list-style: none;
109 +}
110 +blockquote,
111 +q {
112 + quotes: none;
113 +}
114 +blockquote:before,
115 +blockquote:after,
116 +q:before,
117 +q:after {
118 + content: "";
119 + content: none;
120 +}
121 +table {
122 + border-collapse: collapse;
123 + border-spacing: 0;
124 +}
125 +a {
126 + all: unset;
127 + cursor: pointer;
128 +}
129 +
130 +*,
131 +input {
132 + box-sizing: border-box;
133 +}
134 +
135 +input {
136 + border: none;
137 + box-sizing: border-box;
138 + &:focus,
139 + &:active {
140 + outline: none;
141 + }
142 +}
1 +html,
2 +body {
3 + height: 100%;
4 +}
5 +body {
6 + background-color: #f5f5f5;
7 + color: $black;
8 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
9 + Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
10 + font-size: 14px;
11 +}
12 +
13 +main {
14 + width: 100%;
15 + max-width: 1200px;
16 + margin: 0 auto;
17 + min-height: 70vh;
18 +}
19 +
20 +button,
21 +input:not([type="file"]),
22 +textarea,
23 +.fileUpload {
24 + padding: 7px 10px;
25 + width: 100%;
26 + border: none;
27 + border-radius: 5px;
28 + font-size: 14px;
29 + color: $black;
30 + font-weight: 600;
31 + background-color: white;
32 + max-width: 320px;
33 + resize: none;
34 + &::placeholder {
35 + font-weight: 300;
36 + color: rgba(0, 0, 0, 0.7);
37 + }
38 +}
39 +
40 +button {
41 + border: none;
42 + background-color: #3498db;
43 + color: white;
44 +}
45 +
46 +button.delete {
47 + background-color: $dark-red;
48 +}
49 +
50 +button,
51 +input[type="submit"] {
52 + cursor: pointer;
53 +}
1 +.home-videos {
2 + display: grid;
3 + grid-template-columns: repeat(6, minmax(150px, 1fr));
4 + grid-gap: 30px;
5 + .videoBlock:first-child,
6 + .videoBlock:nth-child(2) {
7 + grid-column: span 3;
8 + }
9 + .videoBlock:nth-child(3),
10 + .videoBlock:nth-child(4),
11 + .videoBlock:nth-child(5) {
12 + grid-column: span 2;
13 + }
14 +}
1 +.video-detail__container {
2 + display: flex;
3 + flex-direction: column;
4 + align-items: center;
5 + .video__info {
6 + width: 100%;
7 + max-width: 850px;
8 + margin-top: 25px;
9 + button {
10 + width: 100px;
11 + margin-bottom: 25px;
12 + }
13 + .video__title,
14 + .video__views,
15 + .video__description {
16 + display: block;
17 + margin-bottom: 15px;
18 + }
19 + .video__title {
20 + font-size: 22px;
21 + font-weight: 300;
22 + }
23 + .video__views {
24 + font-size: 14px;
25 + }
26 + .video__description {
27 + font-size: 16px;
28 + }
29 + }
30 + .video__comments {
31 + margin-top: 25px;
32 + .video__comment-number {
33 + font-size: 18px;
34 + }
35 + }
36 +}
1 +.footer {
2 + margin: 50px 0;
3 + padding-top: 50px;
4 + border-top: 3px solid rgba(0, 0, 0, 0.1);
5 + width: 100%;
6 + display: flex;
7 + flex-direction: column;
8 + align-items: center;
9 + .footer__icon {
10 + color: rgba(0, 0, 0, 0.2);
11 + font-size: 40px;
12 + margin-bottom: 20px;
13 + }
14 + .footer__text {
15 + color: rgba(0, 0, 0, 0.2);
16 + font-weight: 800;
17 + text-transform: uppercase;
18 + }
19 +}
1 +.form-container {
2 + width: 100%;
3 + display: flex;
4 + flex-direction: column;
5 + align-items: center;
6 + form {
7 + width: 100%;
8 + max-width: 320px;
9 + margin-bottom: 50px;
10 + input:not([type="file"]),
11 + .fileUpload {
12 + display: block;
13 + width: 100%;
14 + padding-top: 10px;
15 + padding-bottom: 10px;
16 + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
17 + &:not(:last-child) {
18 + margin-bottom: 25px;
19 + }
20 + }
21 + textarea {
22 + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
23 + margin-bottom: 25px;
24 + }
25 + input[type="submit"] {
26 + background-color: #3498db;
27 + color: white;
28 + }
29 + }
30 + a {
31 + max-width: 320px;
32 + width: 100%;
33 + }
34 + .fileUpload {
35 + label {
36 + font-weight: 300;
37 + margin-right: 10px;
38 + }
39 + }
40 +}
1 +.header {
2 + background-color: $red;
3 + margin-bottom: 50px;
4 + .header__wrapper {
5 + padding: 5px 0px;
6 + width: 100%;
7 + margin: 0 auto;
8 + max-width: 1200px;
9 + display: grid;
10 + grid-template-columns: repeat(3, 1fr);
11 + align-items: center;
12 + .header__column {
13 + i {
14 + color: white;
15 + font-size: 30px;
16 + }
17 + &:nth-child(2) {
18 + width: 100%;
19 + justify-self: center;
20 + }
21 + &:last-child {
22 + justify-self: end;
23 + }
24 + ul {
25 + display: flex;
26 + color: white;
27 + font-weight: 600;
28 + text-transform: uppercase;
29 + a {
30 + color: inherit;
31 + text-decoration: none;
32 + }
33 + li:not(:last-child) {
34 + margin-right: 15px;
35 + }
36 + }
37 + form {
38 + width: 100%;
39 + input {
40 + padding: 7px 10px;
41 + width: 100%;
42 + border-radius: 5px;
43 + font-size: 14px;
44 + color: $black;
45 + font-weight: 600;
46 + max-width: none;
47 + &::placeholder {
48 + font-weight: 300;
49 + color: rgba(0, 0, 0, 0.7);
50 + }
51 + }
52 + }
53 + }
54 + }
55 +}
1 +.social-login {
2 + width: 100%;
3 + display: flex;
4 + flex-direction: column;
5 + align-items: center;
6 + button {
7 + width: 100%;
8 + max-width: 320px;
9 + display: flex;
10 + justify-content: center;
11 + align-items: center;
12 + &:not(:last-child) {
13 + margin-bottom: 15px;
14 + }
15 + span {
16 + margin-right: 10px;
17 + font-size: 20px;
18 + }
19 + }
20 + .social-login--github {
21 + background-color: $black;
22 + color: white;
23 + }
24 + .social-login--facebook {
25 + background-color: #3a5998;
26 + color: white;
27 + }
28 +}
1 +.videoBlock {
2 + video {
3 + margin-bottom: 10px;
4 + max-width: 100%;
5 + }
6 + .videoBlock__title {
7 + font-size: 18px;
8 + font-weight: 300;
9 + margin-bottom: 10px;
10 + }
11 +}
1 -@import "config/variables"; 1 +@import "config/_variables.scss";
2 -body { 2 +@import "config/reset.scss";
3 - background-color: $bgColor; 3 +@import "main.scss";
4 -} 4 +
5 +@import "partials/header.scss";
6 +@import "partials/footer.scss";
7 +@import "partials/form.scss";
8 +@import "partials/socialLogin.scss";
9 +@import "partials/videoBlock.scss";
10 +
11 +@import "pages/home.scss";
12 +@import "pages/videoDetail.scss";
......
...@@ -2,41 +2,40 @@ import routes from "../routes"; ...@@ -2,41 +2,40 @@ import routes from "../routes";
2 2
3 // 회원가입 -> 완료 -> 홈화면으로 Redirect 3 // 회원가입 -> 완료 -> 홈화면으로 Redirect
4 export const getJoin = (req, res) => { 4 export const getJoin = (req, res) => {
5 - res.render("join", { pageTitle: "Join" }); 5 + res.render("join", { pageTitle: "Join" });
6 }; 6 };
7 export const postJoin = (req, res) => { 7 export const postJoin = (req, res) => {
8 - const { 8 + const {
9 - body: { name, email, password, password2 }, 9 + body: { name, email, password, password2 },
10 - } = req; 10 + } = req;
11 - if (password !== password2) { 11 + if (password !== password2) {
12 - res.status(400); 12 + res.status(400);
13 - res.render("join", { pageTitle: "Join" }); 13 + res.render("join", { pageTitle: "Join" });
14 - } else { 14 + } else {
15 - // To Do: Register User 15 + // To Do: Register User
16 - // To Do: Log user in 16 + // To Do: Log user in
17 - res.redirect(routes.home); 17 + res.redirect(routes.home);
18 - } 18 + }
19 }; 19 };
20 20
21 export const getLogin = (req, res) => 21 export const getLogin = (req, res) =>
22 - res.render("login", { pageTitle: "Login" }); 22 + res.render("login", { pageTitle: "Login" });
23 export const postLogin = (req, res) => { 23 export const postLogin = (req, res) => {
24 - res.redirect(routes.home); 24 + res.redirect(routes.home);
25 }; 25 };
26 26
27 -//로그아웃을 클릭하면 LogOut페이지로 가는 것 대신에, 로그아웃을 처리한 후 27 +// 로그아웃을 클릭하면 LogOut페이지로 가는 것 대신에, 로그아웃을 처리한 후
28 // home 페이지로 Redirect로 표현할 것이다. 28 // home 페이지로 Redirect로 표현할 것이다.
29 -//즉, 초반에 만들어둔 logout.pug는 삭제해도 좋다. 29 +// 즉, 초반에 만들어둔 logout.pug는 삭제해도 좋다.
30 export const logout = (req, res) => { 30 export const logout = (req, res) => {
31 - //res.render("logout", { pageTitle: "Logout" }); 31 + // res.render("logout", { pageTitle: "Logout" });
32 - res.redirect(routes.home); 32 + res.redirect(routes.home);
33 }; 33 };
34 34
35 -
36 export const users = (req, res) => res.render("users", { pageTitle: "Users" }); 35 export const users = (req, res) => res.render("users", { pageTitle: "Users" });
37 export const userDetail = (req, res) => 36 export const userDetail = (req, res) =>
38 - res.render("userDetail", { pageTitle: "User Detail" }); 37 + res.render("userDetail", { pageTitle: "User Detail" });
39 export const editProfile = (req, res) => 38 export const editProfile = (req, res) =>
40 - res.render("editProfile", { pageTitle: "Edit Profile" }); 39 + res.render("editProfile", { pageTitle: "Edit Profile" });
41 export const changePassword = (req, res) => 40 export const changePassword = (req, res) =>
42 - res.render("changePassword", { pageTitle: "Change Password" });
...\ No newline at end of file ...\ No newline at end of file
41 + res.render("changePassword", { pageTitle: "Change Password" });
......
...@@ -86,7 +86,7 @@ export const postEditVideo = async (req, res) => { ...@@ -86,7 +86,7 @@ export const postEditVideo = async (req, res) => {
86 try { 86 try {
87 // id를 찾아서 body를 얻어와야 한다. 비디오 수정에서 제목과 설명을 가져와야 하기 때문이다. 87 // id를 찾아서 body를 얻어와야 한다. 비디오 수정에서 제목과 설명을 가져와야 하기 때문이다.
88 // mongoose엔 우리의 id가 없어서 _id : id로 찾아줘야 한다. 88 // mongoose엔 우리의 id가 없어서 _id : id로 찾아줘야 한다.
89 - await Video.findOneAndUpdate({ _id: id }, { title, description }); //title:title == title 89 + await Video.findOneAndUpdate({ _id: id }, { title, description }); // title:title == title
90 // 이렇게 하면 default로 얻어온 제목 및 내용을 수정하여 form을 전송하면 해당 내용으로 업데이트 된다. 90 // 이렇게 하면 default로 얻어온 제목 및 내용을 수정하여 form을 전송하면 해당 내용으로 업데이트 된다.
91 res.redirect(routes.videoDetail(id)); 91 res.redirect(routes.videoDetail(id));
92 } catch (error) { 92 } catch (error) {
......
1 +import dotenv from "dotenv";
1 import app from "./app"; // app.js에서 export default app했기 때문에 불러올 수 있다. 2 import app from "./app"; // app.js에서 export default app했기 때문에 불러올 수 있다.
2 import "./db"; 3 import "./db";
3 -import dotenv from "dotenv";
4 -dotenv.config();
5 import "./models/Video"; 4 import "./models/Video";
6 import "./models/Comment"; 5 import "./models/Comment";
7 6
7 +dotenv.config();
8 +
8 const PORT = process.env.PORT || 80; 9 const PORT = process.env.PORT || 80;
9 10
10 const handleListening = () => { 11 const handleListening = () => {
11 - console.log(`✅ Listening on: http://localhost:${PORT}`); 12 + console.log(`✅ Listening on: http://localhost:${PORT}`);
12 - //call-back함수. 13 + // call-back함수.
13 - //PORT를 listen하기 시작할 때 함수를 호출해준다. 14 + // PORT를 listen하기 시작할 때 함수를 호출해준다.
14 }; 15 };
15 16
16 -app.listen(PORT, handleListening);
...\ No newline at end of file ...\ No newline at end of file
17 +app.listen(PORT, handleListening);
......
...@@ -4,14 +4,14 @@ import routes from "./routes"; ...@@ -4,14 +4,14 @@ import routes from "./routes";
4 const multerVideo = multer({ dest: "uploads/videos/" }); 4 const multerVideo = multer({ dest: "uploads/videos/" });
5 5
6 export const localsMiddleware = (req, res, next) => { 6 export const localsMiddleware = (req, res, next) => {
7 - res.locals.siteName = "my Youtube"; 7 + res.locals.siteName = "my Youtube";
8 - res.locals.routes = routes; 8 + res.locals.routes = routes;
9 - res.locals.user = { 9 + res.locals.user = {
10 - isAuthenticated: true, 10 + isAuthenticated: false,
11 - id: 1, 11 + id: 1,
12 - }; 12 + };
13 - next(); 13 + next();
14 }; 14 };
15 15
16 export const uploadVideo = multerVideo.single("videoFile"); 16 export const uploadVideo = multerVideo.single("videoFile");
17 -//single에 들어간 videoFile은 upload.pug의 file 부분 input name
...\ No newline at end of file ...\ No newline at end of file
17 +// single에 들어간 videoFile은 upload.pug의 file 부분 input name
......
1 import mongoose from "mongoose"; 1 import mongoose from "mongoose";
2 -//video 댓글에 대한 Database 2 +// video 댓글에 대한 Database
3 3
4 const CommentSchema = new mongoose.Schema({ 4 const CommentSchema = new mongoose.Schema({
5 - text: { 5 + text: {
6 - type: String, 6 + type: String,
7 - required: "Text is required" 7 + required: "Text is required",
8 - }, //이러한 형태를 configuration object라 한다. 8 + }, // 이러한 형태를 configuration object라 한다.
9 - createdAt: { 9 + createdAt: {
10 - type: Date, 10 + type: Date,
11 - default: Date.now 11 + default: Date.now,
12 - } 12 + },
13 - /* 13 + /*
14 - , 14 +
15 video: { //video와 comment를 연결하는 방법 #2 15 video: { //video와 comment를 연결하는 방법 #2
16 type: mongoose.Schema.Types.ObjectId, //그 다음 어느 model에서 온 id인지 알려줘야 한다. 16 type: mongoose.Schema.Types.ObjectId, //그 다음 어느 model에서 온 id인지 알려줘야 한다.
17 ref: "Video" 17 ref: "Video"
18 - }*/ 18 + }
19 + */
19 }); 20 });
20 21
21 const model = mongoose.model("Comment", CommentSchema); 22 const model = mongoose.model("Comment", CommentSchema);
22 -export default model;
...\ No newline at end of file ...\ No newline at end of file
23 +export default model;
......
1 -//DB 모델을 작성한다. 1 +// DB 모델을 작성한다.
2 -//Video 자체를 DB에 저장하진 않을 것이다. 즉, byte를 저장하는 것이 아니라 video의 link를 저장한다. 2 +// Video 자체를 DB에 저장하진 않을 것이다. 즉, byte를 저장하는 것이 아니라 video의 link를 저장한다.
3 import mongoose from "mongoose"; 3 import mongoose from "mongoose";
4 4
5 const VideoSchema = new mongoose.Schema({ 5 const VideoSchema = new mongoose.Schema({
6 - fileUrl: { 6 + fileUrl: {
7 - type: String, 7 + type: String,
8 - required: "File URL is required" //url이 없으면 오류메시지 출력 8 + required: "File URL is required", // url이 없으면 오류메시지 출력
9 + },
10 + title: {
11 + type: String,
12 + required: "Title is required",
13 + },
14 + description: String,
15 + views: {
16 + type: Number,
17 + default: 0, // 비디오를 처음 생성하면 views를 0으로..
18 + },
19 + createdAt: {
20 + type: Date,
21 + default: Date.now, // 현재 날짜를 반환하는 function
22 + },
23 + // video와 comment를 연결하는 방법 #1
24 + comments: [
25 + {
26 + type: mongoose.Schema.Types.ObjectId, // 그 다음 어느 model에서 온 id인지 알려줘야 한다.
27 + ref: "Comment",
9 }, 28 },
10 - title: { 29 + ],
11 - type: String,
12 - required: "Title is required"
13 - },
14 - description: String,
15 - views: {
16 - type: Number,
17 - default: 0 //비디오를 처음 생성하면 views를 0으로..
18 - },
19 - createdAt: {
20 - type: Date,
21 - default: Date.now //현재 날짜를 반환하는 function
22 - },
23 - //video와 comment를 연결하는 방법 #1
24 - comments: [{
25 - type: mongoose.Schema.Types.ObjectId, //그 다음 어느 model에서 온 id인지 알려줘야 한다.
26 - ref: "Comment"
27 - }]
28 }); 30 });
29 // 이제 이 스키마를 이용하여 model을 만들어준다. 31 // 이제 이 스키마를 이용하여 model을 만들어준다.
30 -//모델의 이름은 "Video" 32 +// 모델의 이름은 "Video"
31 const model = mongoose.model("Video", VideoSchema); 33 const model = mongoose.model("Video", VideoSchema);
32 export default model; 34 export default model;
33 -//모델이 만들어짐을 알리기 위해 init.js에 import해준다.
...\ No newline at end of file ...\ No newline at end of file
35 +// 모델이 만들어짐을 알리기 위해 init.js에 import해준다.
......
...@@ -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", 7 + "dev:server": "nodemon --exec babel-node init.js --delay 2 --ignore 'scss'",
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 }, 10 },
......
1 import express from "express"; 1 import express from "express";
2 import routes from "../routes"; 2 import routes from "../routes";
3 import { 3 import {
4 - getUpload, 4 + getUpload,
5 - postUpload, 5 + postUpload,
6 - videoDetail, 6 + videoDetail,
7 - getEditVideo, 7 + getEditVideo,
8 - postEditVideo, 8 + postEditVideo,
9 - deleteVideo, 9 + deleteVideo,
10 } from "../controllers/videoController"; 10 } from "../controllers/videoController";
11 import { uploadVideo } from "../middlewares"; 11 import { uploadVideo } from "../middlewares";
12 -//export const videoRouter = express.Router(); 이렇게하면 이 변수만 export하게 된다. 12 +// export const videoRouter = express.Router(); 이렇게하면 이 변수만 export하게 된다.
13 const videoRouter = express.Router(); 13 const videoRouter = express.Router();
14 14
15 -//Upload 15 +// Upload
16 videoRouter.get(routes.upload, getUpload); 16 videoRouter.get(routes.upload, getUpload);
17 videoRouter.post(routes.upload, uploadVideo, postUpload); 17 videoRouter.post(routes.upload, uploadVideo, postUpload);
18 18
...@@ -26,4 +26,4 @@ videoRouter.post(routes.editVideo(), postEditVideo); ...@@ -26,4 +26,4 @@ videoRouter.post(routes.editVideo(), postEditVideo);
26 // Video Delete 26 // Video Delete
27 videoRouter.get(routes.deleteVideo(), deleteVideo); 27 videoRouter.get(routes.deleteVideo(), deleteVideo);
28 28
29 -export default videoRouter;
...\ No newline at end of file ...\ No newline at end of file
29 +export default videoRouter;
......
...@@ -19,44 +19,44 @@ const EDIT_VIDEO = "/:id/edit"; ...@@ -19,44 +19,44 @@ const EDIT_VIDEO = "/:id/edit";
19 const DELETE_VIDEO = "/:id/delete"; 19 const DELETE_VIDEO = "/:id/delete";
20 20
21 const routes = { 21 const routes = {
22 - home: HOME, 22 + home: HOME,
23 - join: JOIN, 23 + join: JOIN,
24 - login: LOGIN, 24 + login: LOGIN,
25 - logout: LOGOUT, 25 + logout: LOGOUT,
26 - search: SEARCH, 26 + search: SEARCH,
27 - users: USERS, 27 + users: USERS,
28 - userDetail: (id) => { 28 + userDetail: (id) => {
29 - if (id) { 29 + if (id) {
30 - return `/users/${id}`; 30 + return `/users/${id}`;
31 - } else { 31 + } else {
32 - return USER_DETAIL; 32 + return USER_DETAIL;
33 - } 33 + }
34 - }, 34 + },
35 - editProfile: EDIT_PROFILE, 35 + editProfile: EDIT_PROFILE,
36 - changePassword: CHANGE_PASSWORD, 36 + changePassword: CHANGE_PASSWORD,
37 - videos: VIDEOS, 37 + videos: VIDEOS,
38 - upload: UPLOAD, 38 + upload: UPLOAD,
39 - videoDetail: (id) => { 39 + videoDetail: (id) => {
40 - if (id) { 40 + if (id) {
41 - return `/videos/${id}`; 41 + return `/videos/${id}`;
42 - } else { 42 + } else {
43 - return VIDEO_DETAIL; 43 + return VIDEO_DETAIL;
44 - } 44 + }
45 - }, 45 + },
46 - editVideo: (id) => { 46 + editVideo: (id) => {
47 - if (id) { 47 + if (id) {
48 - return `/videos/${id}/edit`; 48 + return `/videos/${id}/edit`;
49 - } else { 49 + } else {
50 - return EDIT_VIDEO; 50 + return EDIT_VIDEO;
51 - } 51 + }
52 - }, 52 + },
53 - deleteVideo: (id) => { 53 + deleteVideo: (id) => {
54 - if (id) { 54 + if (id) {
55 - return `/videos/${id}/delete`; 55 + return `/videos/${id}/delete`;
56 - } else { 56 + } else {
57 - return DELETE_VIDEO; 57 + return DELETE_VIDEO;
58 - } 58 + }
59 - }, 59 + },
60 }; 60 };
61 61
62 -export default routes;
...\ No newline at end of file ...\ No newline at end of file
62 +export default routes;
......
1 +html,
2 +body,
3 +div,
4 +span,
5 +applet,
6 +object,
7 +iframe,
8 +h1,
9 +h2,
10 +h3,
11 +h4,
12 +h5,
13 +h6,
14 +p,
15 +blockquote,
16 +pre,
17 +a,
18 +abbr,
19 +acronym,
20 +address,
21 +big,
22 +cite,
23 +code,
24 +del,
25 +dfn,
26 +em,
27 +img,
28 +ins,
29 +kbd,
30 +q,
31 +s,
32 +samp,
33 +small,
34 +strike,
35 +strong,
36 +sub,
37 +sup,
38 +tt,
39 +var,
40 +b,
41 +u,
42 +i,
43 +center,
44 +dl,
45 +dt,
46 +dd,
47 +ol,
48 +ul,
49 +li,
50 +fieldset,
51 +form,
52 +label,
53 +legend,
54 +table,
55 +caption,
56 +tbody,
57 +tfoot,
58 +thead,
59 +tr,
60 +th,
61 +td,
62 +article,
63 +aside,
64 +canvas,
65 +details,
66 +embed,
67 +figure,
68 +figcaption,
69 +footer,
70 +header,
71 +hgroup,
72 +menu,
73 +nav,
74 +output,
75 +ruby,
76 +section,
77 +summary,
78 +time,
79 +mark,
80 +audio,
81 +video {
82 + margin: 0;
83 + padding: 0;
84 + border: 0;
85 + font-size: 100%;
86 + font: inherit;
87 + vertical-align: baseline; }
88 +
89 +/* HTML5 display-role reset for older browsers */
90 +article,
91 +aside,
92 +details,
93 +figcaption,
94 +figure,
95 +footer,
96 +header,
97 +hgroup,
98 +menu,
99 +nav,
100 +section {
101 + display: block; }
102 +
1 body { 103 body {
2 - background-color: red; } 104 + line-height: 1; }
105 +
106 +ol,
107 +ul {
108 + list-style: none; }
109 +
110 +blockquote,
111 +q {
112 + quotes: none; }
113 +
114 +blockquote:before,
115 +blockquote:after,
116 +q:before,
117 +q:after {
118 + content: "";
119 + content: none; }
120 +
121 +table {
122 + border-collapse: collapse;
123 + border-spacing: 0; }
124 +
125 +a {
126 + all: unset;
127 + cursor: pointer; }
128 +
129 +*,
130 +input {
131 + -webkit-box-sizing: border-box;
132 + -moz-box-sizing: border-box;
133 + box-sizing: border-box; }
134 +
135 +input {
136 + border: none;
137 + -webkit-box-sizing: border-box;
138 + -moz-box-sizing: border-box;
139 + box-sizing: border-box; }
140 + input:focus, input:active {
141 + outline: none; }
142 +
143 +html,
144 +body {
145 + height: 100%; }
146 +
147 +body {
148 + background-color: #f5f5f5;
149 + color: #444444;
150 + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
151 + font-size: 14px; }
152 +
153 +main {
154 + width: 100%;
155 + max-width: 1200px;
156 + margin: 0 auto;
157 + min-height: 70vh; }
158 +
159 +button,
160 +input:not([type="file"]),
161 +textarea,
162 +.fileUpload {
163 + padding: 7px 10px;
164 + width: 100%;
165 + border: none;
166 + -webkit-border-radius: 5px;
167 + -moz-border-radius: 5px;
168 + border-radius: 5px;
169 + font-size: 14px;
170 + color: #444444;
171 + font-weight: 600;
172 + background-color: white;
173 + max-width: 320px;
174 + resize: none; }
175 + button::-webkit-input-placeholder, input:not([type="file"])::-webkit-input-placeholder, textarea::-webkit-input-placeholder, .fileUpload::-webkit-input-placeholder {
176 + font-weight: 300;
177 + color: rgba(0, 0, 0, 0.7); }
178 + button:-moz-placeholder, input:not([type="file"]):-moz-placeholder, textarea:-moz-placeholder, .fileUpload:-moz-placeholder {
179 + font-weight: 300;
180 + color: rgba(0, 0, 0, 0.7); }
181 + button::-moz-placeholder, input:not([type="file"])::-moz-placeholder, textarea::-moz-placeholder, .fileUpload::-moz-placeholder {
182 + font-weight: 300;
183 + color: rgba(0, 0, 0, 0.7); }
184 + button:-ms-input-placeholder, input:not([type="file"]):-ms-input-placeholder, textarea:-ms-input-placeholder, .fileUpload:-ms-input-placeholder {
185 + font-weight: 300;
186 + color: rgba(0, 0, 0, 0.7); }
187 + button::-ms-input-placeholder, input:not([type="file"])::-ms-input-placeholder, textarea::-ms-input-placeholder, .fileUpload::-ms-input-placeholder {
188 + font-weight: 300;
189 + color: rgba(0, 0, 0, 0.7); }
190 + button::placeholder,
191 + input:not([type="file"])::placeholder,
192 + textarea::placeholder,
193 + .fileUpload::placeholder {
194 + font-weight: 300;
195 + color: rgba(0, 0, 0, 0.7); }
196 +
197 +button {
198 + border: none;
199 + background-color: #3498db;
200 + color: white; }
201 +
202 +button.delete {
203 + background-color: #bb2f2a; }
204 +
205 +button,
206 +input[type="submit"] {
207 + cursor: pointer; }
208 +
209 +.header {
210 + background-color: #ea232c;
211 + margin-bottom: 50px; }
212 + .header .header__wrapper {
213 + padding: 5px 0px;
214 + width: 100%;
215 + margin: 0 auto;
216 + max-width: 1200px;
217 + display: grid;
218 + grid-template-columns: repeat(3, 1fr);
219 + -webkit-box-align: center;
220 + -webkit-align-items: center;
221 + -moz-box-align: center;
222 + -ms-flex-align: center;
223 + align-items: center; }
224 + .header .header__wrapper .header__column i {
225 + color: white;
226 + font-size: 30px; }
227 + .header .header__wrapper .header__column:nth-child(2) {
228 + width: 100%;
229 + justify-self: center; }
230 + .header .header__wrapper .header__column:last-child {
231 + justify-self: end; }
232 + .header .header__wrapper .header__column ul {
233 + display: -webkit-box;
234 + display: -webkit-flex;
235 + display: -moz-box;
236 + display: -ms-flexbox;
237 + display: flex;
238 + color: white;
239 + font-weight: 600;
240 + text-transform: uppercase; }
241 + .header .header__wrapper .header__column ul a {
242 + color: inherit;
243 + text-decoration: none; }
244 + .header .header__wrapper .header__column ul li:not(:last-child) {
245 + margin-right: 15px; }
246 + .header .header__wrapper .header__column form {
247 + width: 100%; }
248 + .header .header__wrapper .header__column form input {
249 + padding: 7px 10px;
250 + width: 100%;
251 + -webkit-border-radius: 5px;
252 + -moz-border-radius: 5px;
253 + border-radius: 5px;
254 + font-size: 14px;
255 + color: #444444;
256 + font-weight: 600;
257 + max-width: none; }
258 + .header .header__wrapper .header__column form input::-webkit-input-placeholder {
259 + font-weight: 300;
260 + color: rgba(0, 0, 0, 0.7); }
261 + .header .header__wrapper .header__column form input:-moz-placeholder {
262 + font-weight: 300;
263 + color: rgba(0, 0, 0, 0.7); }
264 + .header .header__wrapper .header__column form input::-moz-placeholder {
265 + font-weight: 300;
266 + color: rgba(0, 0, 0, 0.7); }
267 + .header .header__wrapper .header__column form input:-ms-input-placeholder {
268 + font-weight: 300;
269 + color: rgba(0, 0, 0, 0.7); }
270 + .header .header__wrapper .header__column form input::-ms-input-placeholder {
271 + font-weight: 300;
272 + color: rgba(0, 0, 0, 0.7); }
273 + .header .header__wrapper .header__column form input::placeholder {
274 + font-weight: 300;
275 + color: rgba(0, 0, 0, 0.7); }
276 +
277 +.footer {
278 + margin: 50px 0;
279 + padding-top: 50px;
280 + border-top: 3px solid rgba(0, 0, 0, 0.1);
281 + width: 100%;
282 + display: -webkit-box;
283 + display: -webkit-flex;
284 + display: -moz-box;
285 + display: -ms-flexbox;
286 + display: flex;
287 + -webkit-box-orient: vertical;
288 + -webkit-box-direction: normal;
289 + -webkit-flex-direction: column;
290 + -moz-box-orient: vertical;
291 + -moz-box-direction: normal;
292 + -ms-flex-direction: column;
293 + flex-direction: column;
294 + -webkit-box-align: center;
295 + -webkit-align-items: center;
296 + -moz-box-align: center;
297 + -ms-flex-align: center;
298 + align-items: center; }
299 + .footer .footer__icon {
300 + color: rgba(0, 0, 0, 0.2);
301 + font-size: 40px;
302 + margin-bottom: 20px; }
303 + .footer .footer__text {
304 + color: rgba(0, 0, 0, 0.2);
305 + font-weight: 800;
306 + text-transform: uppercase; }
307 +
308 +.form-container {
309 + width: 100%;
310 + display: -webkit-box;
311 + display: -webkit-flex;
312 + display: -moz-box;
313 + display: -ms-flexbox;
314 + display: flex;
315 + -webkit-box-orient: vertical;
316 + -webkit-box-direction: normal;
317 + -webkit-flex-direction: column;
318 + -moz-box-orient: vertical;
319 + -moz-box-direction: normal;
320 + -ms-flex-direction: column;
321 + flex-direction: column;
322 + -webkit-box-align: center;
323 + -webkit-align-items: center;
324 + -moz-box-align: center;
325 + -ms-flex-align: center;
326 + align-items: center; }
327 + .form-container form {
328 + width: 100%;
329 + max-width: 320px;
330 + margin-bottom: 50px; }
331 + .form-container form input:not([type="file"]),
332 + .form-container form .fileUpload {
333 + display: block;
334 + width: 100%;
335 + padding-top: 10px;
336 + padding-bottom: 10px;
337 + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
338 + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
339 + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); }
340 + .form-container form input:not([type="file"]):not(:last-child),
341 + .form-container form .fileUpload:not(:last-child) {
342 + margin-bottom: 25px; }
343 + .form-container form textarea {
344 + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
345 + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
346 + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
347 + margin-bottom: 25px; }
348 + .form-container form input[type="submit"] {
349 + background-color: #3498db;
350 + color: white; }
351 + .form-container a {
352 + max-width: 320px;
353 + width: 100%; }
354 + .form-container .fileUpload label {
355 + font-weight: 300;
356 + margin-right: 10px; }
357 +
358 +.social-login {
359 + width: 100%;
360 + display: -webkit-box;
361 + display: -webkit-flex;
362 + display: -moz-box;
363 + display: -ms-flexbox;
364 + display: flex;
365 + -webkit-box-orient: vertical;
366 + -webkit-box-direction: normal;
367 + -webkit-flex-direction: column;
368 + -moz-box-orient: vertical;
369 + -moz-box-direction: normal;
370 + -ms-flex-direction: column;
371 + flex-direction: column;
372 + -webkit-box-align: center;
373 + -webkit-align-items: center;
374 + -moz-box-align: center;
375 + -ms-flex-align: center;
376 + align-items: center; }
377 + .social-login button {
378 + width: 100%;
379 + max-width: 320px;
380 + display: -webkit-box;
381 + display: -webkit-flex;
382 + display: -moz-box;
383 + display: -ms-flexbox;
384 + display: flex;
385 + -webkit-box-pack: center;
386 + -webkit-justify-content: center;
387 + -moz-box-pack: center;
388 + -ms-flex-pack: center;
389 + justify-content: center;
390 + -webkit-box-align: center;
391 + -webkit-align-items: center;
392 + -moz-box-align: center;
393 + -ms-flex-align: center;
394 + align-items: center; }
395 + .social-login button:not(:last-child) {
396 + margin-bottom: 15px; }
397 + .social-login button span {
398 + margin-right: 10px;
399 + font-size: 20px; }
400 + .social-login .social-login--github {
401 + background-color: #444444;
402 + color: white; }
403 + .social-login .social-login--facebook {
404 + background-color: #3a5998;
405 + color: white; }
406 +
407 +.videoBlock video {
408 + margin-bottom: 10px;
409 + max-width: 100%; }
410 +
411 +.videoBlock .videoBlock__title {
412 + font-size: 18px;
413 + font-weight: 300;
414 + margin-bottom: 10px; }
415 +
416 +.home-videos {
417 + display: grid;
418 + grid-template-columns: repeat(6, minmax(150px, 1fr));
419 + grid-gap: 30px; }
420 + .home-videos .videoBlock:first-child,
421 + .home-videos .videoBlock:nth-child(2) {
422 + grid-column: span 3; }
423 + .home-videos .videoBlock:nth-child(3),
424 + .home-videos .videoBlock:nth-child(4),
425 + .home-videos .videoBlock:nth-child(5) {
426 + grid-column: span 2; }
427 +
428 +.video-detail__container {
429 + display: -webkit-box;
430 + display: -webkit-flex;
431 + display: -moz-box;
432 + display: -ms-flexbox;
433 + display: flex;
434 + -webkit-box-orient: vertical;
435 + -webkit-box-direction: normal;
436 + -webkit-flex-direction: column;
437 + -moz-box-orient: vertical;
438 + -moz-box-direction: normal;
439 + -ms-flex-direction: column;
440 + flex-direction: column;
441 + -webkit-box-align: center;
442 + -webkit-align-items: center;
443 + -moz-box-align: center;
444 + -ms-flex-align: center;
445 + align-items: center; }
446 + .video-detail__container .video__info {
447 + width: 100%;
448 + max-width: 850px;
449 + margin-top: 25px; }
450 + .video-detail__container .video__info button {
451 + width: 100px;
452 + margin-bottom: 25px; }
453 + .video-detail__container .video__info .video__title,
454 + .video-detail__container .video__info .video__views,
455 + .video-detail__container .video__info .video__description {
456 + display: block;
457 + margin-bottom: 15px; }
458 + .video-detail__container .video__info .video__title {
459 + font-size: 22px;
460 + font-weight: 300; }
461 + .video-detail__container .video__info .video__views {
462 + font-size: 14px; }
463 + .video-detail__container .video__info .video__description {
464 + font-size: 16px; }
465 + .video-detail__container .video__comments {
466 + margin-top: 25px; }
467 + .video-detail__container .video__comments .video__comment-number {
468 + font-size: 18px; }
......
...@@ -3,9 +3,11 @@ extends layouts/main ...@@ -3,9 +3,11 @@ extends layouts/main
3 block content 3 block content
4 .form-container 4 .form-container
5 form(action=routes.editProfile, method="post") 5 form(action=routes.editProfile, method="post")
6 - label(for="avatar") Avatar 6 + .fileUpload
7 - input(type="file", id="avatar", name="avatar") 7 + label(for="avatar") Avatar
8 + input(type="file", id="avatar", name="avatar")
8 input(type="text", placeholder="Name", name="name") 9 input(type="text", placeholder="Name", name="name")
9 input(type="email", placeholder="Email", name="email") 10 input(type="email", placeholder="Email", name="email")
10 input(type="submit", value="Update Profile") 11 input(type="submit", value="Update Profile")
11 - a.form-container__link(href=`/users${routes.changePassword}`) Change Password
...\ No newline at end of file ...\ No newline at end of file
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
......
...@@ -6,4 +6,5 @@ block content ...@@ -6,4 +6,5 @@ block content
6 input(type="text", placeholder="Title", name="title", value=video.title) 6 input(type="text", placeholder="Title", name="title", value=video.title)
7 textarea(name="description", placeholder="Description")=video.description 7 textarea(name="description", placeholder="Description")=video.description
8 input(type="submit", value="Update Video") 8 input(type="submit", value="Update Video")
9 - a.form-container__link.form-container__link--delete(href=routes.deleteVideo(video.id)) Delete Video
...\ No newline at end of file ...\ No newline at end of file
9 + a.form-container__link(href=routes.deleteVideo(video.id))
10 + button.delete Delete Video
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -2,11 +2,77 @@ extends layouts/main ...@@ -2,11 +2,77 @@ extends layouts/main
2 include mixins/videoBlock 2 include mixins/videoBlock
3 3
4 block content 4 block content
5 - .videos 5 + .home-videos
6 each item in videos 6 each item in videos
7 +videoBlock({ 7 +videoBlock({
8 id: item.id, 8 id: item.id,
9 title : item.title, 9 title : item.title,
10 views: item.views, 10 views: item.views,
11 videoFile:item.fileUrl 11 videoFile:item.fileUrl
12 - })
...\ No newline at end of file ...\ No newline at end of file
12 + })
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 + })
......
...@@ -3,5 +3,8 @@ mixin videoBlock(video = {}) ...@@ -3,5 +3,8 @@ mixin videoBlock(video = {})
3 a(href=routes.videoDetail(video.id)) 3 a(href=routes.videoDetail(video.id))
4 video.videoBlock__thumbnail(src=video.videoFile, controls=true) 4 video.videoBlock__thumbnail(src=video.videoFile, controls=true)
5 h4.videoBlock__title=video.title 5 h4.videoBlock__title=video.title
6 - h6.videoBlock__views=video.views 6 + if video.views === 1
7 + h6.videoBlock__views 1 view
8 + else
9 + h6.videoBlock__views #{video.views} views
7 10
...\ No newline at end of file ...\ No newline at end of file
......
1 header.header 1 header.header
2 - .header__column 2 + .header__wrapper
3 - a(href=routes.home) 3 + .header__column
4 - i.fab.fa-youtube 4 + a(href=routes.home)
5 - .header__column 5 + i.fab.fa-youtube
6 - form(action=routes.search, method="get") 6 + .header__column
7 - input(type="text", placeholder="Search by term...", name="term") 7 + form(action=routes.search, method="get")
8 - .header__column 8 + input(type="text", placeholder="Search by term...", name="term")
9 - ul 9 + .header__column
10 - if !user.isAuthenticated 10 + ul
11 - li 11 + if !user.isAuthenticated
12 - a(href=routes.join) Join 12 + li
13 - li 13 + a(href=routes.join) Join
14 - a(href=routes.login) Log In 14 + li
15 - else 15 + a(href=routes.login) Log In
16 - li 16 + else
17 - a(href=`/videos${routes.upload}`) Upload 17 + li
18 - li 18 + a(href=`/videos${routes.upload}`) Upload
19 - a(href=routes.userDetail(user.id)) Profile 19 + li
20 - li 20 + a(href=routes.userDetail(user.id)) Profile
21 - a(href=routes.logout) Log out 21 + li
22 + a(href=routes.logout) Log out
......
...@@ -11,7 +11,6 @@ block content ...@@ -11,7 +11,6 @@ block content
11 +videoBlock({ 11 +videoBlock({
12 title : item.title, 12 title : item.title,
13 views: item.views, 13 views: item.views,
14 - videoFile:item.videoFile
15 videoFile:item.videoFile, 14 videoFile:item.videoFile,
16 id: item.id 15 id: item.id
17 }) 16 })
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -3,8 +3,9 @@ extends layouts/main ...@@ -3,8 +3,9 @@ extends layouts/main
3 block content 3 block content
4 .form-container 4 .form-container
5 form(action=`/videos${routes.upload}`, method="post", enctype="multipart/form-data") 5 form(action=`/videos${routes.upload}`, method="post", enctype="multipart/form-data")
6 - label(for="file") Video File 6 + div.fileUpload
7 - input(type="file", id="file", name="videoFile", required=true, accept = "video/*") 7 + label(for="file") Video File
8 + input(type="file", id="file", name="videoFile", required=true, accept = "video/*")
8 input(type="text", placeholder="Title", name="title", required=true) 9 input(type="text", placeholder="Title", name="title", required=true)
9 textarea(name="description", placeholder="Description", required=true) 10 textarea(name="description", placeholder="Description", required=true)
10 input(type="submit", value="Upload Video") 11 input(type="submit", value="Upload Video")
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -4,10 +4,15 @@ block content ...@@ -4,10 +4,15 @@ block content
4 .video__player 4 .video__player
5 video(src=`/${video.fileUrl}`) 5 video(src=`/${video.fileUrl}`)
6 .video__info 6 .video__info
7 - a(href=routes.editVideo(video.id)) Edit video 7 + a(href=routes.editVideo(video.id))
8 + button Edit video
8 h5.video__title=video.title 9 h5.video__title=video.title
9 span.video__views=video.views 10 span.video__views=video.views
10 p.video__description=video.description 11 p.video__description=video.description
12 + if video.views === 1
13 + span.video__views 1 view
14 + else
15 + span.video__views #{video.views} views
11 .video__comment 16 .video__comment
12 if video.comments.length === 1 17 if video.comments.length === 1
13 span.video__comment-number 1 comment 18 span.video__comment-number 1 comment
......