├── .nojekyll ├── .gitignore ├── src ├── images │ ├── Алтай.jpg │ ├── Домбай.png │ ├── козлик.png │ ├── кусто.jpg │ ├── тюмень.png │ ├── Карачаевск.png │ ├── гораЭльбрус.png │ ├── Vector.svg │ ├── CloseIcon.svg │ ├── Vectoredit.svg │ ├── Union.svg │ ├── blacklike.svg │ ├── trash.svg │ ├── Vector3.svg │ ├── Vectormain.svg │ └── logo.svg ├── blocks │ ├── popup │ │ ├── _cards │ │ │ └── popup_cards.css │ │ ├── _opened │ │ │ └── popup_opened.css │ │ ├── __fieldset │ │ │ └── popup__fieldset.css │ │ ├── __input │ │ │ ├── _type_error │ │ │ │ └── popup__input_type_error.css │ │ │ ├── _type_error-active │ │ │ │ └── popup__input_type_error-active.css │ │ │ └── popup__input.css │ │ ├── __full-image │ │ │ └── popup__full-image.css │ │ ├── _full-screen │ │ │ └── popup_full-screen.css │ │ ├── __full-text │ │ │ └── popup__full-text.css │ │ ├── __button │ │ │ ├── _disabled │ │ │ │ └── popup__button_disabled.css │ │ │ └── popup__button.css │ │ ├── __close-image │ │ │ └── popup__close-image.css │ │ ├── popup.css │ │ ├── __container-full-screen │ │ │ └── popup__container-full-screen.css │ │ ├── __text │ │ │ └── popup__text.css │ │ ├── __close │ │ │ └── popup__close.css │ │ └── __container │ │ │ └── popup__container.css │ ├── element │ │ ├── __trash │ │ │ └── element__trash.css │ │ ├── __button-trash │ │ │ ├── _type_active │ │ │ │ └── element__button-trash_type_active.css │ │ │ └── element__button-trash.css │ │ ├── __like-counter │ │ │ └── element__like-counter.css │ │ ├── __like │ │ │ ├── _active │ │ │ │ └── element__like_active.css │ │ │ └── element__like.css │ │ ├── __button-like │ │ │ └── element__button-like.css │ │ ├── __title │ │ │ └── element__title.css │ │ ├── __text │ │ │ └── element__text.css │ │ ├── element.css │ │ └── __image │ │ │ └── element__image.css │ ├── profile │ │ ├── __image-edit │ │ │ └── profile__image-edit.css │ │ ├── __image-add │ │ │ └── profile__image-add.css │ │ ├── __info-container │ │ │ └── profile__info-container.css │ │ ├── __info │ │ │ └── profile__info.css │ │ ├── __avatar │ │ │ └── profile__avatar.css │ │ ├── profile.css │ │ ├── __pen │ │ │ └── profile__pen.css │ │ ├── __about │ │ │ └── profile__about.css │ │ ├── __button-edit │ │ │ └── profile__button-edit.css │ │ ├── __name │ │ │ └── profile__name.css │ │ └── __button-add │ │ │ └── profile__button-add.css │ ├── footer │ │ ├── footer.css │ │ └── __text │ │ │ └── footer__text.css │ ├── root │ │ └── root.css │ ├── header │ │ ├── header.css │ │ └── __logo │ │ │ └── header__logo.css │ ├── elements │ │ └── elements.css │ └── page │ │ └── page.css ├── vendor │ ├── fonts │ │ ├── Inter-Black.woff │ │ ├── Inter-Black.woff2 │ │ ├── Inter-Medium.woff │ │ ├── Inter-Medium.woff2 │ │ ├── Inter-Regular.woff │ │ ├── Inter-Regular.woff2 │ │ └── fonts.css │ └── normalize.css ├── components │ ├── PopupWithSubmit.js │ ├── Section.js │ ├── PopupWithImage.js │ ├── Popup.js │ ├── UserInfo.js │ ├── PopupWithForm.js │ ├── Api.js │ ├── FormValidator.js │ └── Card.js ├── utils │ └── constants.js ├── pages │ ├── index.css │ └── index.js └── index.html ├── postcss.config.js ├── babel.config.js ├── README.md ├── .editorconfig ├── webpack.config.js └── package.json /.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /src/images/Алтай.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/Алтай.jpg -------------------------------------------------------------------------------- /src/images/Домбай.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/Домбай.png -------------------------------------------------------------------------------- /src/images/козлик.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/козлик.png -------------------------------------------------------------------------------- /src/images/кусто.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/кусто.jpg -------------------------------------------------------------------------------- /src/images/тюмень.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/тюмень.png -------------------------------------------------------------------------------- /src/blocks/popup/_cards/popup_cards.css: -------------------------------------------------------------------------------- 1 | .popup_cards{ 2 | background-color: rgba(0, 0, 0, 0.5); 3 | } 4 | -------------------------------------------------------------------------------- /src/images/Карачаевск.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/Карачаевск.png -------------------------------------------------------------------------------- /src/images/гораЭльбрус.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/images/гораЭльбрус.png -------------------------------------------------------------------------------- /src/blocks/element/__trash/element__trash.css: -------------------------------------------------------------------------------- 1 | .element__trash{ 2 | width: 18px; 3 | height: 19px; 4 | } 5 | -------------------------------------------------------------------------------- /src/blocks/popup/_opened/popup_opened.css: -------------------------------------------------------------------------------- 1 | .popup_opened { 2 | visibility: visible; 3 | opacity: 1; 4 | } 5 | -------------------------------------------------------------------------------- /src/vendor/fonts/Inter-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/vendor/fonts/Inter-Black.woff -------------------------------------------------------------------------------- /src/vendor/fonts/Inter-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/vendor/fonts/Inter-Black.woff2 -------------------------------------------------------------------------------- /src/vendor/fonts/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/vendor/fonts/Inter-Medium.woff -------------------------------------------------------------------------------- /src/blocks/popup/__fieldset/popup__fieldset.css: -------------------------------------------------------------------------------- 1 | .popup__fieldset { 2 | padding: 0; 3 | margin: 0; 4 | border: 0; 5 | } 6 | -------------------------------------------------------------------------------- /src/blocks/profile/__image-edit/profile__image-edit.css: -------------------------------------------------------------------------------- 1 | .profile__image-edit { 2 | width: 10px; 3 | height: 10px; 4 | } 5 | -------------------------------------------------------------------------------- /src/vendor/fonts/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/vendor/fonts/Inter-Medium.woff2 -------------------------------------------------------------------------------- /src/vendor/fonts/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/vendor/fonts/Inter-Regular.woff -------------------------------------------------------------------------------- /src/vendor/fonts/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sonyamaster1/mesto/HEAD/src/vendor/fonts/Inter-Regular.woff2 -------------------------------------------------------------------------------- /src/blocks/element/__button-trash/_type_active/element__button-trash_type_active.css: -------------------------------------------------------------------------------- 1 | .element__button-trash_type_active{ 2 | display: block; 3 | } 4 | -------------------------------------------------------------------------------- /src/blocks/footer/footer.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | padding: 0; 3 | } 4 | @media (max-width: 425px) { 5 | .footer { 6 | padding: 0 19px; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/blocks/popup/__input/_type_error/popup__input_type_error.css: -------------------------------------------------------------------------------- 1 | .popup__input_type_error{ 2 | border-bottom: 1px solid #FF0000; 3 | outline: 1px solid red; 4 | } 5 | -------------------------------------------------------------------------------- /src/blocks/popup/__full-image/popup__full-image.css: -------------------------------------------------------------------------------- 1 | .popup__full-image{ 2 | max-width: 75vw; 3 | max-height: 75vh; 4 | object-fit: contain; 5 | z-index: 10; 6 | } 7 | -------------------------------------------------------------------------------- /src/blocks/element/__like-counter/element__like-counter.css: -------------------------------------------------------------------------------- 1 | .element__like-counter { 2 | width: 10px; 3 | height: 13px; 4 | color: black; 5 | margin: 3px 6px 14px auto; 6 | } 7 | -------------------------------------------------------------------------------- /src/blocks/element/__like/_active/element__like_active.css: -------------------------------------------------------------------------------- 1 | .element__like_active{ 2 | background-image: url(../../../../images/blacklike.svg); 3 | width: 22px; 4 | height: 19px; 5 | } 6 | -------------------------------------------------------------------------------- /src/blocks/popup/_full-screen/popup_full-screen.css: -------------------------------------------------------------------------------- 1 | .popup_full-screen{ 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | background-color: rgba(0, 0, 0, 0.9); 6 | } 7 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const cssnano = require('cssnano'); 3 | 4 | module.exports = { 5 | plugins: [ 6 | autoprefixer, 7 | cssnano({ preset: 'default' }) 8 | ] 9 | }; 10 | -------------------------------------------------------------------------------- /src/blocks/element/__button-like/element__button-like.css: -------------------------------------------------------------------------------- 1 | .element__button-like { 2 | width: 22px; 3 | height: 19px; 4 | background-color: transparent; 5 | border: none; 6 | padding: 0; 7 | margin: 30px 20px 31px 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/blocks/element/__like/element__like.css: -------------------------------------------------------------------------------- 1 | .element__like { 2 | width: 22px; 3 | height: 19px; 4 | transition: opacity 0.3s linear; 5 | } 6 | .element__like:hover { 7 | opacity: 0.5; 8 | cursor: pointer; 9 | } 10 | -------------------------------------------------------------------------------- /src/blocks/popup/__full-text/popup__full-text.css: -------------------------------------------------------------------------------- 1 | .popup__full-text{ 2 | font-weight: 400; 3 | font-size: 12px; 4 | line-height: 15px; 5 | padding: 0; 6 | margin: 10px 0 0 0; 7 | color: #fff; 8 | align-self: start; 9 | } 10 | -------------------------------------------------------------------------------- /src/images/Vector.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/blocks/popup/__button/_disabled/popup__button_disabled.css: -------------------------------------------------------------------------------- 1 | .popup__button_disabled{ 2 | color: rgba(0, 0, 0, 0.2); 3 | background: inherit; 4 | border: 1px solid rgba(0, 0, 0, 0.2); 5 | border-radius: 2px; 6 | cursor: default; 7 | } 8 | -------------------------------------------------------------------------------- /src/blocks/popup/__close-image/popup__close-image.css: -------------------------------------------------------------------------------- 1 | .popup__close-image { 2 | width: 32px; 3 | height: 32px; 4 | } 5 | @media (max-width: 650px) { 6 | .popup__close-image { 7 | width: 20px; 8 | height: 20px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/blocks/profile/__image-add/profile__image-add.css: -------------------------------------------------------------------------------- 1 | .profile__image-add { 2 | width: 22px; 3 | height: 22px; 4 | } 5 | @media (max-width: 320px) { 6 | .profile__image-add { 7 | width: 16px; 8 | height: 16px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/images/CloseIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/blocks/root/root.css: -------------------------------------------------------------------------------- 1 | .root { 2 | background-color: #000; 3 | color: #fff; 4 | margin: 0; 5 | padding: 0; 6 | font-family: inter, Arial, sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | -------------------------------------------------------------------------------- /src/images/Vectoredit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/blocks/element/__title/element__title.css: -------------------------------------------------------------------------------- 1 | .element__title { 2 | margin: 25px 0 31px 21px; 3 | padding: 0; 4 | font-weight: 900; 5 | font-size: 24px; 6 | line-height: 1.2; 7 | text-overflow: ellipsis; 8 | white-space: nowrap; 9 | overflow: hidden; 10 | } 11 | -------------------------------------------------------------------------------- /src/blocks/footer/__text/footer__text.css: -------------------------------------------------------------------------------- 1 | .footer__text { 2 | color: #545454; 3 | font-weight: 400; 4 | font-size: 18px; 5 | line-height: 1.2; 6 | margin: 0; 7 | padding: 0; 8 | } 9 | @media (max-width: 320px){ 10 | .footer__text { 11 | font-size: 14px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/blocks/popup/popup.css: -------------------------------------------------------------------------------- 1 | .popup { 2 | width: 100%; 3 | height: 100%; 4 | position: fixed; 5 | top: 0; 6 | left: 0; 7 | background-color: rgba(0, 0, 0, 0.8); 8 | z-index: 2; 9 | visibility: hidden; 10 | opacity: 0; 11 | transition: visibility 0.5s, opacity 0.5s linear; 12 | } 13 | -------------------------------------------------------------------------------- /src/blocks/header/header.css: -------------------------------------------------------------------------------- 1 | .header { 2 | max-width: 100%; 3 | border-bottom: 1px solid rgba(84, 84, 84, 0.7); 4 | padding-bottom: 41px; 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | @media (max-width: 425px) { 9 | .header { 10 | padding: 0 27px 42px 27px; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/blocks/profile/__info-container/profile__info-container.css: -------------------------------------------------------------------------------- 1 | .profile__info-container { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | margin: 0; 6 | padding: 0; 7 | } 8 | @media (max-width: 320px){ 9 | .profile__info-container { 10 | justify-content: center; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/blocks/header/__logo/header__logo.css: -------------------------------------------------------------------------------- 1 | .header__logo { 2 | transition: opacity 0.3s linear; 3 | width: 142px; 4 | height: 33px; 5 | } 6 | .header__logo:hover { 7 | opacity: 0.5; 8 | cursor: pointer; 9 | } 10 | @media (max-width: 650px) { 11 | .header__logo { 12 | width: 103px; 13 | height: 25px; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/blocks/profile/__info/profile__info.css: -------------------------------------------------------------------------------- 1 | .profile__info { 2 | max-width: 366px; 3 | } 4 | @media (max-width: 820px){ 5 | .profile__info { 6 | grid-area: info; 7 | margin: 0 auto; 8 | margin-bottom: 50px; 9 | } 10 | } 11 | @media (max-width: 320px){ 12 | .profile__info { 13 | width: 100%; 14 | margin-bottom: 36px; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/blocks/element/__text/element__text.css: -------------------------------------------------------------------------------- 1 | .element__text { 2 | background-color: #fff; 3 | color: black; 4 | border-radius: 0 0 10px 10px; 5 | padding: 0; 6 | display: flex; 7 | justify-content: space-between; 8 | align-items: center; 9 | width: 100%; 10 | } 11 | @media (max-width:320px) { 12 | .element__text{ 13 | max-width: 282px; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/blocks/popup/__container-full-screen/popup__container-full-screen.css: -------------------------------------------------------------------------------- 1 | .popup__container-full-screen { 2 | max-width: 75vw; 3 | max-height: 75vh; 4 | z-index: 10; 5 | opacity: 1; 6 | position: relative; 7 | margin: 0; 8 | padding: 0; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/PopupWithSubmit.js: -------------------------------------------------------------------------------- 1 | import Popup from "./Popup"; 2 | export default class PopupWithSubmit extends Popup { 3 | constructor(popupSelector) { 4 | super(popupSelector); 5 | this._deleteButton = document.querySelector(".popup__button_type_delete"); 6 | } 7 | open(call) { 8 | super.open(); 9 | this.call = call; 10 | this._deleteButton.onclick = this.call; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/blocks/popup/__text/popup__text.css: -------------------------------------------------------------------------------- 1 | .popup__text { 2 | font-weight: 900; 3 | font-size: 24px; 4 | line-height: 1.1; 5 | text-align: center; 6 | color: black; 7 | margin: 0 64px 54px 36px; 8 | padding: 0; 9 | max-width: 330px; 10 | } 11 | @media (max-width: 650px) { 12 | .popup__text { 13 | font-size: 18px; 14 | max-width: 238px; 15 | margin: 0 22px 75px 22px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/blocks/profile/__avatar/profile__avatar.css: -------------------------------------------------------------------------------- 1 | .profile__avatar { 2 | width: 120px; 3 | height: 120px; 4 | border-radius: 50%; 5 | margin: 0; 6 | padding: 0; 7 | margin-right: 30px; 8 | object-fit: cover; 9 | background-position: center; 10 | position: relative; 11 | } 12 | @media (max-width: 820px) { 13 | .profile__avatar { 14 | margin: 0 auto; 15 | margin-bottom: 30px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/components/Section.js: -------------------------------------------------------------------------------- 1 | export default class Section { 2 | constructor({ elem, renderer }, selector) { 3 | this._reversedElem = elem; 4 | this._container = document.querySelector(selector); 5 | this._renderer = renderer; 6 | } 7 | addItem(element) { 8 | this._container.prepend(element); 9 | } 10 | renderItems() { 11 | this._reversedElem.forEach((item) => this._renderer(item)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/vendor/fonts/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | src: url(./Inter-Regular.woff), url(./Inter-Regular.woff2); 3 | font-family: inter; 4 | font-weight: 400; 5 | } 6 | @font-face { 7 | src: url(./Inter-Black.woff), url(./Inter-Black.woff2); 8 | font-family: inter; 9 | font-weight: 900; 10 | } 11 | @font-face { 12 | src: url(./Inter-Medium.woff), url(./Inter-Medium.woff2); 13 | font-family: inter; 14 | font-weight: 500; 15 | } 16 | -------------------------------------------------------------------------------- /src/blocks/popup/__close/popup__close.css: -------------------------------------------------------------------------------- 1 | .popup__close { 2 | position: absolute; 3 | max-width: 32px; 4 | min-height: 32px; 5 | top: -40px; 6 | right: -40px; 7 | cursor: pointer; 8 | background-color: transparent; 9 | border: none; 10 | padding: 0; 11 | } 12 | @media (max-width: 650px) { 13 | .popup__close { 14 | max-width: 20px; 15 | min-height: 20px; 16 | top: -36px; 17 | right: 0px; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/blocks/element/__button-trash/element__button-trash.css: -------------------------------------------------------------------------------- 1 | .element__button-trash { 2 | display: none; 3 | width: 18px; 4 | height: 19px; 5 | z-index: 3; 6 | position: absolute; 7 | top: 20px; 8 | right: 20px; 9 | margin: 0; 10 | padding: 0; 11 | background-color: transparent; 12 | border: none; 13 | transition: opacity 0.3s linear; 14 | } 15 | .element__button-trash:hover { 16 | opacity: 0.5; 17 | cursor: pointer; 18 | } 19 | -------------------------------------------------------------------------------- /src/blocks/popup/__input/_type_error-active/popup__input_type_error-active.css: -------------------------------------------------------------------------------- 1 | .popup__input_type_error-active { 2 | color: red; 3 | display: block; 4 | position: absolute; 5 | top: 141px; 6 | left: 35px; 7 | min-height: 30px; 8 | padding: 0; 9 | margin: 5px 0 -35px 0; 10 | font-size: 12px; 11 | line-height: calc(1 / 12 * 15); 12 | } 13 | .popup__input_type_error-active:last-child { 14 | top: 205px; 15 | left: 35px; 16 | } 17 | -------------------------------------------------------------------------------- /src/blocks/popup/__container/popup__container.css: -------------------------------------------------------------------------------- 1 | .popup__container { 2 | transform: translate(-50%, -50%); 3 | top: 50%; 4 | left: 50%; 5 | width: 430px; 6 | padding: 34px 0 37px 0; 7 | background-color: #fff; 8 | color: #000; 9 | border-radius: 10px; 10 | z-index: 10; 11 | opacity: 1; 12 | position: relative; 13 | } 14 | @media (max-width:650px) { 15 | .popup__container{ 16 | width: 282px; 17 | padding: 25px 0; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/blocks/profile/profile.css: -------------------------------------------------------------------------------- 1 | .profile { 2 | max-width: 100%; 3 | align-items: center; 4 | display: grid; 5 | grid-template-columns: repeat(2, max-content) 1fr; 6 | padding-top: 40px; 7 | } 8 | @media (max-width: 820px) { 9 | .profile { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | padding-top: 38px; 14 | } 15 | } 16 | @media (max-width: 425px) { 17 | .profile { 18 | padding: 42px 19px 0 19px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/images/Union.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/blacklike.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = [ 2 | ['@babel/preset-env', { // какой пресет использовать 3 | targets: { // какие версии браузеров поддерживать 4 | edge: '17', 5 | ie: '11', 6 | firefox: '50', 7 | chrome: '64', 8 | safari: '11.1' 9 | }, 10 | 11 | // использовать полифиллы для браузеров из свойства target 12 | // по умолчанию babel использует поллифиллы библиотеки core-js 13 | useBuiltIns: "entry" 14 | }] 15 | ]; 16 | 17 | module.exports = { presets }; 18 | -------------------------------------------------------------------------------- /src/blocks/profile/__pen/profile__pen.css: -------------------------------------------------------------------------------- 1 | .profile__pen { 2 | position: absolute; 3 | width: 120px; 4 | height: 120px; 5 | opacity: 0; 6 | background-size: cover; 7 | background-position: center; 8 | background-image: url(../../../images/Vectoredit.svg); 9 | border-radius: 50%; 10 | background-color: black; 11 | background-repeat: no-repeat; 12 | } 13 | .profile__pen:hover { 14 | opacity: 0.8; 15 | transition: opacity 0.5s ease-in-out; 16 | background-size: 26px 26px; 17 | cursor: pointer; 18 | } 19 | -------------------------------------------------------------------------------- /src/blocks/profile/__about/profile__about.css: -------------------------------------------------------------------------------- 1 | .profile__about { 2 | font-weight: 400; 3 | font-size: 18px; 4 | line-height: 1.2; 5 | margin: 16px 0 0 0; 6 | padding: 0; 7 | text-overflow: ellipsis; 8 | white-space: nowrap; 9 | overflow: hidden; 10 | max-width: 366px; 11 | } 12 | @media (max-width: 980px) { 13 | .profile__about { 14 | font-size: 16px; 15 | max-width: 282px; 16 | } 17 | } 18 | @media (max-width: 320px) { 19 | .profile__about { 20 | text-align: center; 21 | font-size: 14px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/blocks/popup/__button/popup__button.css: -------------------------------------------------------------------------------- 1 | .popup__button { 2 | cursor: pointer; 3 | width: 358px; 4 | margin: 48px 36px 0 36px; 5 | font-weight: 400; 6 | font-size: 18px; 7 | line-height: 22px; 8 | text-align: center; 9 | border: none; 10 | background-color: #000; 11 | color: #fff; 12 | padding: 0; 13 | min-height: 50px; 14 | border-radius: 2px; 15 | } 16 | @media (max-width: 650px) { 17 | .popup__button { 18 | max-width: 238px; 19 | min-height: 46px; 20 | margin: 45px 22px 0 22px; 21 | font-size: 14px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/images/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/blocks/profile/__button-edit/profile__button-edit.css: -------------------------------------------------------------------------------- 1 | .profile__button-edit { 2 | width: 24px; 3 | height: 24px; 4 | border: 1px solid #fff; 5 | margin: 0; 6 | padding: 0; 7 | box-sizing: border-box; 8 | transition: opacity 0.3s linear; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | background-color: transparent; 13 | } 14 | .profile__button-edit:hover { 15 | opacity: 0.5; 16 | cursor: pointer; 17 | } 18 | @media (max-width: 320px) { 19 | .profile__button-edit { 20 | width: 18px; 21 | height: 18px; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/components/PopupWithImage.js: -------------------------------------------------------------------------------- 1 | import Popup from './Popup.js'; 2 | //попап большого изображения 3 | export default class PopupWithImage extends Popup { 4 | constructor(popupSelector) { 5 | super(popupSelector); 6 | this._fullImage = this._popup.querySelector('.popup__full-image'); //изображение попапа 7 | this._fullText = this._popup.querySelector('.popup__full-text'); //текст попапа 8 | } 9 | open(name, link) { 10 | this._fullText.textContent = name; 11 | this._fullImage.src = link; 12 | this._fullImage.alt = `Перед вами ${name}`; 13 | super.open(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/blocks/elements/elements.css: -------------------------------------------------------------------------------- 1 | .elements { 2 | max-width: 100%; 3 | display: grid; 4 | grid-template-columns: repeat(3, minmax(23%, 1fr)); 5 | gap: 20px 17px; 6 | padding: 50px 0 66px 0; 7 | } 8 | @media (max-width: 820px) { 9 | .elements { 10 | grid-template-columns: repeat(2, 1fr); 11 | padding: 40px 0 50px 0; 12 | } 13 | } 14 | @media (max-width: 600px) { 15 | .elements { 16 | display: flex; 17 | flex-direction: column; 18 | align-items: center; 19 | } 20 | } 21 | @media (max-width: 320px) { 22 | .elements { 23 | padding: 36px 19px 48px 19px; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/blocks/profile/__name/profile__name.css: -------------------------------------------------------------------------------- 1 | .profile__name { 2 | font-weight: 500; 3 | font-size: 42px; 4 | line-height: 1.1; 5 | margin: 0 18px 0 0; 6 | padding: 0; 7 | text-overflow: ellipsis; 8 | white-space: nowrap; 9 | overflow: hidden; 10 | max-width: 294px; 11 | } 12 | @media (max-width: 980px) { 13 | .profile__name { 14 | font-size: 36px; 15 | } 16 | } 17 | @media (max-width: 425px) { 18 | .profile__name { 19 | font-size: 27px; 20 | max-width: 189px; 21 | } 22 | } 23 | @media (max-width: 320px) { 24 | .profile__name { 25 | margin-right: 10px; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/blocks/popup/__input/popup__input.css: -------------------------------------------------------------------------------- 1 | .popup__input { 2 | margin: 0 36px 30px 36px; 3 | background-color: #fff; 4 | border: none; 5 | font-weight: 400; 6 | font-size: 14px; 7 | color: #000; 8 | line-height: 17px; 9 | text-align: left; 10 | padding: 0 0 13px 0; 11 | outline: none; 12 | border-bottom: 1px solid rgba(0, 0, 0, 0.2); 13 | width: 358px; 14 | } 15 | .popup__input:focus { 16 | border-radius: 2px; 17 | } 18 | .popup__input:last-of-type { 19 | margin-bottom: 0; 20 | } 21 | @media (max-width: 650px) { 22 | .popup__input { 23 | margin: 0 22px 30px 22px; 24 | width: 238px; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/blocks/element/element.css: -------------------------------------------------------------------------------- 1 | .element { 2 | max-width: 100%; 3 | display: flex; 4 | flex-direction: column; 5 | z-index: 2; 6 | position: relative; 7 | } 8 | @media (max-width: 820px) { 9 | .element { 10 | max-width: 282px; 11 | } 12 | } 13 | @media (max-width: 723px) { 14 | .element { 15 | max-width: 282px; 16 | } 17 | } 18 | @media (max-width: 675px) { 19 | .element { 20 | max-width: 250px; 21 | } 22 | } 23 | @media (max-width: 600px) { 24 | .element { 25 | max-width: 282px; 26 | margin: 0 auto; 27 | } 28 | } 29 | @media (max-width: 425px) { 30 | .element { 31 | margin: 0; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/blocks/element/__image/element__image.css: -------------------------------------------------------------------------------- 1 | .element__image { 2 | width: 100%; 3 | height: 282px; 4 | object-fit: fill; 5 | border-radius: 10px 10px 0px 0px; 6 | margin: 0; 7 | padding: 0; 8 | transition: opacity 0.3s linear; 9 | } 10 | .element__image:hover { 11 | opacity: 0.5; 12 | cursor: pointer; 13 | } 14 | @media (max-width: 1024px) { 15 | .element__image { 16 | height: 240px; 17 | } 18 | } 19 | @media (max-width: 820px) { 20 | .element__image { 21 | height: 282px; 22 | width: 282px; 23 | } 24 | } 25 | @media (max-width: 723px) { 26 | .element__image { 27 | width: 282px; 28 | } 29 | } 30 | @media (max-width: 675px) { 31 | .element__image { 32 | width: 250px; 33 | } 34 | } 35 | @media (max-width:600px) { 36 | .element__image{ 37 | width: 282px; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/images/Vector3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/images/Vectormain.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Проект Mesto 2 | ## Динамичное формирование карточек при помощи JavaScript и адаптивной весткой для таких разрешений как: 1280px, 1024px, 768px 320px. 3 | 4 | --- 5 | - Добавление / удаление карточек 6 | - Редактирование информации о пользователе и аватара 7 | - Постановка / удаление лайка карточке 8 | 9 | --- 10 | ## Технологии: 11 | ![JavaScript](https://img.shields.io/badge/-JavaScript-090909?style=for-the-badge&logo=JavaScript) 12 | ![Webpack](https://img.shields.io/badge/-Webpack-090909?style=for-the-badge&logo=Webpack) 13 | ![HTML5](https://img.shields.io/badge/-HTML5-090909?style=for-the-badge&logo=HTML5) 14 | ![CSS3](https://img.shields.io/badge/-CSS3-090909?style=for-the-badge&logo=CSS3) 15 | 16 | --- 17 | ## Инструкция по установке: 18 | 1. Клонировать репозиторий 19 | `git clone https://github.com/Sonyamaster1/mesto.git` 20 | 2. Установить зависимости 21 | `npm i` 22 | 3. Запустить проект локально 23 | `npm run dev` 24 | -------------------------------------------------------------------------------- /src/blocks/profile/__button-add/profile__button-add.css: -------------------------------------------------------------------------------- 1 | .profile__button-add { 2 | border: 2px solid #fff; 3 | border-radius: 2px; 4 | width: 150px; 5 | min-height: 50px; 6 | margin: 0; 7 | padding: 0; 8 | box-sizing: border-box; 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | transition: opacity 0.3s linear; 13 | justify-self: flex-end; 14 | background-color: transparent; 15 | } 16 | .profile__button-add:hover { 17 | opacity: 0.5; 18 | cursor: pointer; 19 | } 20 | @media (max-width: 1024px) { 21 | .profile__button-add { 22 | width: 120px; 23 | } 24 | } 25 | @media (max-width: 980px) { 26 | .profile__button-add { 27 | width: 100px; 28 | } 29 | } 30 | @media (max-width: 820px) { 31 | .profile__button-add { 32 | grid-area: button; 33 | width: 271px; 34 | margin: 0 auto; 35 | } 36 | } 37 | @media (max-width: 320px) { 38 | .profile__button-add { 39 | width: 100%; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | 4 | # A special property that should be specified at the top of the file outside of 5 | 6 | # any sections. Set to true to stop .editor config file search on current file 7 | 8 | root = true 9 | 10 | [*] 11 | # Indentation style 12 | 13 | # Possible values - tab, space 14 | 15 | indent_style = space 16 | 17 | # Indentation size in single-spaced characters 18 | 19 | # Possible values - an integer, tab 20 | 21 | indent_size = 2 22 | 23 | # Line ending file format 24 | 25 | # Possible values - lf, crlf, cr 26 | 27 | end_of_line = lf 28 | 29 | # File character encoding 30 | 31 | # Possible values - latin1, utf-8, utf-16be, utf-16le 32 | 33 | charset = utf-8 34 | 35 | # Denotes whether to trim whitespace at the end of lines 36 | 37 | # Possible values - true, false 38 | 39 | trim_trailing_whitespace = true 40 | 41 | # Denotes whether file should end with a newline 42 | 43 | # Possible values - true, false 44 | 45 | insert_final_newline = true -------------------------------------------------------------------------------- /src/components/Popup.js: -------------------------------------------------------------------------------- 1 | export default class Popup { 2 | constructor(popupSelector) { 3 | this._popup = document.querySelector(popupSelector); 4 | this._closeButton = this._popup.querySelector('.popup__close'); 5 | this._handleEscClose = this._handleEscClose.bind(this); 6 | } 7 | open() { 8 | this._popup.classList.add('popup_opened'); 9 | document.addEventListener('keydown', this._handleEscClose); 10 | } 11 | close() { 12 | this._popup.classList.remove('popup_opened'); 13 | document.removeEventListener('keydown', this._handleEscClose); 14 | } 15 | _handleEscClose(evt) { 16 | if (evt.key === 'Escape') { 17 | this.close(); 18 | } 19 | } 20 | _handleOverClose = (evt) => { 21 | if (evt.target.classList.contains('popup')) { 22 | this.close(); 23 | } 24 | }; 25 | setEventListeners() { 26 | this._closeButton.addEventListener('mousedown', this.close.bind(this)); 27 | this._popup.addEventListener('mousedown', this._handleOverClose.bind(this)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/blocks/page/page.css: -------------------------------------------------------------------------------- 1 | .page { 2 | margin: 0 auto; 3 | max-width: 1280px; 4 | padding: 45px 200px 60px 200px; 5 | box-sizing: border-box; 6 | } 7 | @media (max-width: 1100px) { 8 | .page { 9 | padding: 45px 170px 50px 170px; 10 | max-width: 1100px; 11 | } 12 | } 13 | @media (max-width: 1024px) { 14 | .page { 15 | max-width: 1024px; 16 | } 17 | } 18 | @media (max-width: 980px) { 19 | .page { 20 | padding: 45px 120px 50px 120px; 21 | max-width: 980px; 22 | } 23 | } 24 | @media (max-width: 820px) { 25 | .page { 26 | padding: 40px 100px 45px 100px; 27 | max-width: 820px; 28 | } 29 | } 30 | @media (max-width: 768px) { 31 | .page { 32 | max-width: 768px; 33 | padding: 35px 70px 40px 70px; 34 | } 35 | } 36 | @media (max-width: 650px) { 37 | .page { 38 | max-width: 650px; 39 | padding: 35px 56px 40px 56px; 40 | } 41 | } 42 | @media (max-width: 595px) { 43 | .page { 44 | max-width: 595px; 45 | } 46 | } 47 | @media (max-width: 425px) { 48 | .page { 49 | max-width: 425px; 50 | padding: 28px 0 36px 0; 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/components/UserInfo.js: -------------------------------------------------------------------------------- 1 | // попап редактирования 2 | export default class UserInfo { 3 | constructor({ profileName, profileAbout, profileAvatar }) { 4 | // передем обьект, чтобы потом вставить нужные значения 5 | this._profileName = document.querySelector(profileName); // селектор имя 6 | this._profileAbout = document.querySelector(profileAbout); //селектор обо мне 7 | this._profileAvatar = document.querySelector(profileAvatar); // селектор аватара 8 | } 9 | getUserInfo() { 10 | //возвращаем значения 11 | const info = {}; 12 | info.name = this._profileName.textContent; 13 | info.about = this._profileAbout.textContent; 14 | return info; 15 | } 16 | setUserInfo({ name, about, avatar }) { 17 | // проверяем значения чтобы вставить нужное 18 | if (name) { 19 | this._profileName.textContent = name; /// data from the user 20 | } 21 | if (about) { 22 | this._profileAbout.textContent = about; /// data from the user 23 | } 24 | if (avatar) { 25 | this._profileAvatar.src = avatar; /// data from the user 26 | } 27 | } 28 | // вставляем значения для аватара 29 | setAvatarInfo({ link }) { 30 | this._profileAvatar.src = link; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 4 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 5 | 6 | module.exports = { 7 | entry: { 8 | main: './src/pages/index.js' 9 | }, 10 | output: { 11 | path: path.resolve(__dirname, 'dist'), 12 | filename: 'main.js', 13 | publicPath: '', 14 | }, 15 | mode: 'development', 16 | devServer: { 17 | static: path.resolve(__dirname, './dist'), 18 | open: true, 19 | compress: true, 20 | port: 8080 21 | }, 22 | module: { 23 | rules: [{ 24 | test: /\.js$/, 25 | use: 'babel-loader', 26 | exclude: '/node_modules/' 27 | }, 28 | { 29 | test: /\.(png|svg|jpg|gif|woff(2)?|eot|ttf|otf)$/, 30 | type: 'asset/resource', 31 | }, 32 | { 33 | test: /\.css$/, 34 | use: [MiniCssExtractPlugin.loader, { 35 | loader: 'css-loader', 36 | options: { 37 | importLoaders: 1 38 | } 39 | }, 40 | 'postcss-loader' 41 | ] 42 | }, 43 | ] 44 | }, 45 | plugins: [ 46 | new HtmlWebpackPlugin({ 47 | template: './src/index.html' 48 | }), 49 | new CleanWebpackPlugin(), 50 | new MiniCssExtractPlugin(), 51 | 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /src/utils/constants.js: -------------------------------------------------------------------------------- 1 | export const validationConfig = { 2 | formSelector: ".popup__form", //формы 3 | inputSelector: ".popup__input", //поля ввода 4 | submitButtonSelector: ".popup__button", //кнопка сохранить 5 | inactiveButtonClass: "popup__button_disabled", //неактивная кнопка сохранить 6 | inputErrorClass: "popup__input_type_error", //поле ввода с ошибкой 7 | errorClass: "popup__input_type_error-active", //span 8 | }; 9 | export const popupProfileOpenButton = document.querySelector( 10 | ".profile__button-edit" 11 | ); //кнопка для редактирования 12 | export const popupProfileFormElement = 13 | document.querySelector(".popup__form-data"); //форма попапа редактирования 14 | export const popUpAdd = document.querySelector(".profile__button-add"); //кнопка добавления 15 | export const cardsForm = document.querySelector(".popup__cards-form"); //форма карточек 16 | export const avatarForm = document.querySelector(".popup__avatar-form"); // форма аватара 17 | export const avatarPen = document.querySelector(".profile__pen"); // карандаш аватара 18 | export const submitButtonAvatar = document.querySelector( 19 | ".popup__button_type_avatar" 20 | ); // кнопка аватара 21 | export const submitButtonProfile = document.querySelector( 22 | ".popup__button_type_save" 23 | ); // кнопка релактирования 24 | export const submitButtonAdd = document.querySelector( 25 | ".popup__button_type_create" 26 | ); // кнопка добавления 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mesto", 3 | "version": "1.0.0", 4 | "description": "### Это мой 7 проект на учебной платформе Яндекс Практикум. В данном проекте реализованны такие умения, как адаптивная верстка (на устройствах от 320px), работа с макетом из Figma, валидация форм посредством JS, добавление карточек через форму.", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "webpack --mode production", 8 | "dev": "webpack serve", 9 | "predeploy": "npm run build", 10 | "deploy": "gh-pages -d dist" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/Sonyamaster1/mesto.git" 15 | }, 16 | "author": "Mitrofanova Sofia", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/Sonyamaster1/mesto/issues" 20 | }, 21 | "homepage": "https://github.com/Sonyamaster1/mesto#readme", 22 | "devDependencies": { 23 | "@babel/core": "^7.19.0", 24 | "@babel/preset-env": "^7.19.0", 25 | "autoprefixer": "^10.4.10", 26 | "babel-loader": "^8.2.5", 27 | "clean-webpack-plugin": "^4.0.0", 28 | "css-loader": "^6.7.1", 29 | "cssnano": "^5.1.13", 30 | "gh-pages": "^4.0.0", 31 | "html-webpack-plugin": "^5.5.0", 32 | "mini-css-extract-plugin": "^2.6.1", 33 | "postcss-loader": "^7.0.1", 34 | "webpack": "^5.74.0", 35 | "webpack-cli": "^4.10.0", 36 | "webpack-dev-server": "^4.11.0" 37 | }, 38 | "dependencies": { 39 | "core-js": "^3.25.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/components/PopupWithForm.js: -------------------------------------------------------------------------------- 1 | import Popup from "./Popup.js"; 2 | // попап добавления карточек 3 | export default class PopupWithForm extends Popup { 4 | constructor({ handleFormSubmit }, popupSelector) { 5 | super(popupSelector); 6 | this._handleFormSubmit = handleFormSubmit; // колбек сабмита формы 7 | this._inputList = this._popup.querySelectorAll(".popup__input"); // поля ввода 8 | this._formList = this._popup.querySelector(".popup__form"); // форма 9 | this._submitButtonPopup = this._popup.querySelector(".popup__button"); //кнопка "сохранить" 10 | } 11 | _getInputValues() { 12 | this._formElement = {}; 13 | // перебираем inputs, присваиваем значение и возвращаем форму 14 | this._inputList.forEach( 15 | (elem) => (this._formElement[elem.name] = elem.value) 16 | ); 17 | return this._formElement; 18 | } 19 | setInputsValues(data) { 20 | this._newFormElement = {}; 21 | data = Object.values(data); 22 | for (let i = 0; i < data.length; i++) { 23 | this._inputList[i].value = data[i]; 24 | } 25 | } 26 | // метод для текста кнопки 27 | _getIsLoading() { 28 | this._submitButtonPopup.textContent = "Сохранение..."; 29 | } 30 | 31 | setEventListeners() { 32 | super.setEventListeners(); 33 | this._formList.addEventListener("submit", (evt) => { 34 | evt.preventDefault(); 35 | this._getIsLoading(); // меняем на Сохранение... 36 | this._handleFormSubmit(this._getInputValues()); 37 | }); 38 | } 39 | 40 | open() { 41 | super.open(); 42 | } 43 | close() { 44 | super.close(); 45 | this._formList.reset(); //очищаем поля после закрытия 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/components/Api.js: -------------------------------------------------------------------------------- 1 | export default class Api { 2 | constructor(config) { 3 | this._url = config.url; 4 | this._headers = config.headers; 5 | } 6 | // проверяет есть ли ошибка 7 | _checkError(res) { 8 | if (res.ok) { 9 | return res.json(); 10 | } 11 | return Promise.reject(`Статус ошибки: ${res.status}`); 12 | } 13 | // Загрузка карточек с сервера 14 | getInitialCards() { 15 | return fetch(`${this._url}/cards`, { 16 | method: "GET", 17 | headers: this._headers, 18 | }).then((res) => this._checkError(res)); 19 | } 20 | // добавление карточек на страницу 21 | postNewCard(data) { 22 | return fetch(`${this._url}/cards`, { 23 | method: "POST", 24 | headers: this._headers, 25 | body: JSON.stringify(data), 26 | }).then((res) => this._checkError(res)); 27 | } 28 | // удаление карточек 29 | deleteCard(cardId) { 30 | return fetch(`${this._url}/cards/${cardId}`, { 31 | method: "DELETE", 32 | headers: this._headers, 33 | }).then((res) => this._checkError(res)); 34 | } 35 | // получение данных с сервера 36 | getInfo() { 37 | return fetch(`${this._url}/users/me`, { 38 | method: "GET", 39 | headers: this._headers, 40 | }).then((res) => this._checkError(res)); 41 | } 42 | // изменение данных с сервера 43 | patchUserInfo(data) { 44 | return fetch(`${this._url}/users/me`, { 45 | method: "PATCH", 46 | headers: this._headers, 47 | body: JSON.stringify(data), 48 | }).then((res) => this._checkError(res)); 49 | } 50 | // изменение данных аватара 51 | patchAvatarInfo(data) { 52 | return fetch(`${this._url}/users/me/avatar`, { 53 | method: "PATCH", 54 | headers: this._headers, 55 | body: JSON.stringify(data), 56 | }).then((res) => this._checkError(res)); 57 | } 58 | // добавление лайка 59 | getLike(cardId) { 60 | return fetch(`${this._url}/cards/${cardId}/likes`, { 61 | method: "PUT", 62 | headers: this._headers, 63 | }).then((res) => this._checkError(res)); 64 | } 65 | // удаление лайка 66 | deleteLike(cardId) { 67 | return fetch(`${this._url}/cards/${cardId}/likes`, { 68 | method: "DELETE", 69 | headers: this._headers, 70 | }).then((res) => this._checkError(res)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/components/FormValidator.js: -------------------------------------------------------------------------------- 1 | export default class FormValidator { 2 | constructor(validationConfig, form) { 3 | this._validationConfig = validationConfig; //объект 4 | this._form = form; //форма 5 | this._inputCollection = Array.from( 6 | this._form.querySelectorAll(this._validationConfig.inputSelector) 7 | ); //input 8 | this._submitButtonElement = this._form.querySelector( 9 | this._validationConfig.submitButtonSelector 10 | ); //кнопка 11 | this._formCollection = Array.from( 12 | document.querySelectorAll(this._validationConfig.form) 13 | ); //forms 14 | } 15 | // показывает ошибку 16 | _showInputError = (inputSelector, errorMessage) => { 17 | const errorItem = this._form.querySelector(`.${inputSelector.id}-error`); 18 | inputSelector.classList.add(this._validationConfig.inputErrorClass); 19 | errorItem.classList.add(this._validationConfig.errorClass); 20 | errorItem.textContent = errorMessage; 21 | }; 22 | //скрывает ошибку 23 | _hideInputError = (inputSelector) => { 24 | const errorItem = this._form.querySelector(`.${inputSelector.id}-error`); 25 | inputSelector.classList.remove(this._validationConfig.inputErrorClass); 26 | errorItem.classList.remove(this._validationConfig.errorClass); 27 | errorItem.textContent = ''; 28 | }; 29 | //проверяет есть ли ошибка 30 | _isValid = (inputSelector) => { 31 | if (!inputSelector.validity.valid) { 32 | this._showInputError(inputSelector, inputSelector.validationMessage); 33 | } else { 34 | this._hideInputError(inputSelector); 35 | } 36 | }; 37 | //кнопка 38 | _toggleButtonState = () => { 39 | if (this._hasInvalidInput(this._inputCollection)) { 40 | this.disabledButton(); 41 | } else { 42 | this._submitButtonElement.classList.remove( 43 | this._validationConfig.inactiveButtonClass 44 | ); 45 | this._submitButtonElement.removeAttribute('disabled', 'disabled'); 46 | } 47 | }; 48 | _hasInvalidInput = () => { 49 | return this._inputCollection.some((inputSelector) => { 50 | return !inputSelector.validity.valid; 51 | }); 52 | }; 53 | //слушатель 54 | _setEventListener = () => { 55 | this._toggleButtonState(); //button 56 | this._inputCollection.forEach((inputSelector) => { 57 | inputSelector.addEventListener('input', () => { 58 | this._isValid(inputSelector); 59 | this._toggleButtonState(); //button 60 | }); 61 | }); 62 | }; 63 | enableValidation = () => { 64 | this._setEventListener(); 65 | }; 66 | disabledButton = () => { 67 | this._submitButtonElement.setAttribute('disabled', 'disabled'); 68 | this._submitButtonElement.classList.add( 69 | this._validationConfig.inactiveButtonClass 70 | ); 71 | }; 72 | // очистка от ошибок 73 | resetInputs = () => { 74 | this._toggleButtonState(); 75 | this._inputCollection.forEach((inputSelector) => { 76 | this._hideInputError(inputSelector); 77 | }); 78 | }; 79 | } 80 | -------------------------------------------------------------------------------- /src/pages/index.css: -------------------------------------------------------------------------------- 1 | @import url(../vendor/normalize.css); 2 | @import url(../vendor/fonts/fonts.css); 3 | @import url(../blocks/element/element.css); 4 | @import url(../blocks/element/__image/element__image.css); 5 | @import url(../blocks/element/__like/element__like.css); 6 | @import url(../blocks/element/__image/element__image.css); 7 | @import url(../blocks/element/__text/element__text.css); 8 | @import url(../blocks/element/__title/element__title.css); 9 | @import url(../blocks/elements/elements.css); 10 | @import url(../blocks/element/__button-like/element__button-like.css); 11 | @import url(../blocks/element/__button-trash/element__button-trash.css); 12 | @import url(../blocks/element/__like/_active/element__like_active.css); 13 | @import url(../blocks/element/__trash/element__trash.css); 14 | @import url(../blocks/footer/__text/footer__text.css); 15 | @import url(../blocks/header/__logo/header__logo.css); 16 | @import url(../blocks/header/header.css); 17 | @import url(../blocks/page/page.css); 18 | @import url(../blocks/popup/__button/popup__button.css); 19 | @import url(../blocks/popup/__close/popup__close.css); 20 | @import url(../blocks/popup/__close-image/popup__close-image.css); 21 | @import url(../blocks/popup/__container/popup__container.css); 22 | @import url(../blocks/popup/__input/popup__input.css); 23 | @import url(../blocks/popup/__text/popup__text.css); 24 | @import url(../blocks/popup/popup.css); 25 | @import url(../blocks/profile/__about/profile__about.css); 26 | @import url(../blocks/profile/__avatar/profile__avatar.css); 27 | @import url(../blocks/profile/__button-add/profile__button-add.css); 28 | @import url(../blocks/profile/__button-edit/profile__button-edit.css); 29 | @import url(../blocks/profile/__image-add/profile__image-add.css); 30 | @import url(../blocks/profile/__image-edit/profile__image-edit.css); 31 | @import url(../blocks/profile/__info-container/profile__info-container.css); 32 | @import url(../blocks/profile/__info/profile__info.css); 33 | @import url(../blocks/profile/__name/profile__name.css); 34 | @import url(../blocks/profile/profile.css); 35 | @import url(../blocks/root/root.css); 36 | @import url(../blocks/footer/footer.css); 37 | @import url(../blocks/popup/__full-image/popup__full-image.css); 38 | @import url(../blocks/popup/__container-full-screen/popup__container-full-screen.css); 39 | @import url(../blocks/popup/__full-text/popup__full-text.css); 40 | @import url(../blocks/popup/_full-screen/popup_full-screen.css); 41 | @import url(../blocks/popup/_opened/popup_opened.css); 42 | @import url(../blocks/popup/__input/_type_error/popup__input_type_error.css); 43 | @import url(../blocks/popup/__fieldset/popup__fieldset.css); 44 | @import url(../blocks/popup/__button/_disabled/popup__button_disabled.css); 45 | @import url(../blocks/popup/__input/_type_error-active/popup__input_type_error-active.css); 46 | @import url(../blocks/popup/_cards/popup_cards.css); 47 | @import url(../blocks/profile/__pen/profile__pen.css); 48 | @import url(../blocks/element/__like-counter/element__like-counter.css); 49 | @import url(../blocks/element/__button-trash/_type_active/element__button-trash_type_active.css); 50 | 51 | -------------------------------------------------------------------------------- /src/components/Card.js: -------------------------------------------------------------------------------- 1 | export default class Card { 2 | constructor( 3 | { 4 | data, 5 | userId, 6 | handleCardClick, 7 | handleDeleteCard, 8 | handleLikeCard, 9 | handleDeleteLikeCard, 10 | }, 11 | templateSelector 12 | ) { 13 | this._data = data; 14 | this._name = data.name; 15 | this._link = data.link; 16 | this._templateSelector = templateSelector; 17 | this.handleCardClick = handleCardClick; 18 | this.handleDeleteCard = handleDeleteCard; 19 | this.handleLikeCard = handleLikeCard; 20 | this.handleDeleteLikeCard = handleDeleteLikeCard; 21 | this._likes = data.likes; 22 | this._userId = userId; 23 | this._id = data._id; 24 | this._owner = data.owner._id; 25 | } 26 | _getTemplate() { 27 | const cardTemplate = document 28 | .querySelector(this._templateSelector) 29 | .content.querySelector(".element") 30 | .cloneNode(true); 31 | return cardTemplate; 32 | } 33 | generateCard() { 34 | this._element = this._getTemplate(); 35 | this.cardTitle = this._element.querySelector(".element__title"); 36 | this.cardImage = this._element.querySelector(".element__image"); 37 | this.cardLike = this._element.querySelector(".element__like"); 38 | this.likeCounter = this._element.querySelector(".element__like-counter"); 39 | this.deleteEl = this._element.querySelector(".element__button-trash"); 40 | this.cardImage.src = this._link; 41 | this.cardTitle.textContent = this._name; 42 | this.cardImage.alt = `Перед вами ${this._name}`; 43 | this.likeCounter.textContent = this._likes.length; 44 | this._checkOwner(); 45 | this._checkLikeOwner(); 46 | this._setEventListeners(); 47 | return this._element; 48 | } 49 | // добавляем или убираем лайк 50 | toggleLikeCard(data) { 51 | this._likes = data.likes; 52 | this.likeCounter.textContent = this._likes.length; 53 | this.cardLike.classList.toggle("element__like_active"); 54 | } 55 | // удаление 56 | remove() { 57 | this._element.remove(); 58 | this._element = null; 59 | } 60 | // открытие попапа 61 | _handleOpenImagePopup() { 62 | this.handleCardClick(this._name, this._link); 63 | } 64 | // все слушатели 65 | _setEventListeners() { 66 | this.cardLike.addEventListener("click", () => { 67 | if (this.cardLike.classList.contains("element__like_active")) { 68 | this.handleDeleteLikeCard(this); 69 | } else { 70 | this.handleLikeCard(this); 71 | } 72 | }); 73 | this.deleteEl.addEventListener("click", () => this.handleDeleteCard(this)); 74 | this.cardImage.addEventListener("click", () => { 75 | this._handleOpenImagePopup(); 76 | }); 77 | } 78 | // получаем id 79 | getId() { 80 | return this._data._id; 81 | } 82 | // проверяем пользователя 83 | _checkOwner() { 84 | if (this._owner === this._userId) { 85 | this.deleteEl.classList.add("element__button-trash_type_active"); 86 | } 87 | } 88 | // проверяем пользователя 89 | _checkLikeOwner() { 90 | // метод some проверяет условие 91 | if (this._likes.some((user) => this._userId === user._id)) { 92 | this.cardLike.classList.add("element__like_active"); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import "./index.css"; 2 | import Card from "../components/Card.js"; 3 | import FormValidator from "../components/FormValidator.js"; 4 | import { validationConfig } from "../utils/constants.js"; 5 | import Section from "../components/Section.js"; 6 | import PopupWithImage from "../components/PopupWithImage.js"; 7 | import PopupWithForm from "../components/PopupWithForm.js"; 8 | import UserInfo from "../components/UserInfo.js"; 9 | import Api from "../components/Api"; 10 | import PopupWithSubmit from "../components/PopupWithSubmit.js"; 11 | import { 12 | popupProfileOpenButton, 13 | popupProfileFormElement, 14 | popUpAdd, 15 | cardsForm, 16 | avatarForm, 17 | avatarPen, 18 | submitButtonAvatar, 19 | submitButtonProfile, 20 | submitButtonAdd, 21 | } from "../utils/constants.js"; 22 | 23 | // объект Api 24 | const apiData = { 25 | url: "https://mesto.nomoreparties.co/v1/cohort-51", 26 | headers: { 27 | "content-type": "application/json", 28 | authorization: "35801359-77af-460b-835b-a39f894888d4", 29 | }, 30 | }; 31 | //валидация 1 формы 32 | const popUpProfileValidation = new FormValidator( 33 | validationConfig, 34 | popupProfileFormElement 35 | ); 36 | popUpProfileValidation.enableValidation(); 37 | //валидация 2 формы 38 | const popUpCardsValidation = new FormValidator(validationConfig, cardsForm); 39 | popUpCardsValidation.enableValidation(); 40 | //валидация 3 формы 41 | const popUpAvatarValidation = new FormValidator(validationConfig, avatarForm); 42 | popUpAvatarValidation.enableValidation(); 43 | // объект класса Api 44 | const api = new Api(apiData); 45 | // получаем начальный набор карточек 46 | let cardList; // изменяю значение ниже, поэтому не могу обьявить константу 47 | const elementaryCards = api 48 | .getInitialCards() 49 | .then(function (data) { 50 | cardList = new Section( 51 | { 52 | elem: data.reverse(), // переворачивем массив, чтобы карточки добавлялись в начало 53 | renderer: (item) => { 54 | cardList.addItem(createNewCard(item)); 55 | }, 56 | }, 57 | ".elements" 58 | ); 59 | }) 60 | .catch((err) => { 61 | console.log(err); 62 | }); 63 | // функция для создания карточки 64 | function createNewCard(item) { 65 | const card = new Card( 66 | { 67 | data: item, 68 | userId: userId, 69 | handleCardClick: (name, link) => { 70 | fullScreen.open(name, link); 71 | }, 72 | handleDeleteCard, 73 | handleLikeCard, 74 | handleDeleteLikeCard, 75 | }, 76 | "#template-element" 77 | ); 78 | const cardTemplate = card.generateCard(); 79 | return cardTemplate; 80 | } 81 | // создание экземпляра UserInfo 82 | const profilePopup = new UserInfo({ 83 | profileName: ".profile__name", 84 | profileAbout: ".profile__about", 85 | profileAvatar: ".profile__avatar", 86 | }); 87 | // создание экземпляра PopupWithForm 88 | const newProfilePopup = new PopupWithForm( 89 | { 90 | handleFormSubmit: (data) => { 91 | api 92 | .patchUserInfo({ 93 | name: data.name, 94 | about: data.about, 95 | }) 96 | .then(() => { 97 | profilePopup.setUserInfo({ 98 | name: data.name, 99 | about: data.about, 100 | }); 101 | }) 102 | .then(() => newProfilePopup.close()) 103 | .then(() => { 104 | popUpProfileValidation.disabledButton(), 105 | popUpProfileValidation.resetInputs(); 106 | }) 107 | .catch((err) => { 108 | console.log(err); 109 | }) 110 | .finally(() => { 111 | submitButtonProfile.textContent = "Сохранить"; 112 | }); 113 | }, 114 | }, 115 | ".popup_edit" 116 | ); 117 | newProfilePopup.setEventListeners(); 118 | // попап добавления карточек 119 | const newCardPopup = new PopupWithForm( 120 | { 121 | handleFormSubmit: (item) => { 122 | api 123 | .postNewCard({ name: item.image, link: item.link }) 124 | .then((data) => { 125 | cardList.addItem( 126 | createNewCard({ 127 | name: data.name, 128 | link: data.link, 129 | owner: { _id: userId }, 130 | likes: data.likes, 131 | _id: data._id, 132 | }) 133 | ); 134 | }) 135 | .then( 136 | () => newCardPopup.close(), 137 | popUpCardsValidation.resetInputs(), 138 | popUpCardsValidation.disabledButton() 139 | ) 140 | .catch((err) => { 141 | console.log(err); 142 | }) 143 | .finally(() => { 144 | submitButtonAdd.textContent = "Создать"; 145 | }); 146 | }, 147 | }, 148 | ".popup_cards" 149 | ); 150 | newCardPopup.setEventListeners(); // создаются карточки 151 | 152 | // попап с картинкой 153 | const fullScreen = new PopupWithImage(".popup_full-screen"); 154 | fullScreen.setEventListeners(); 155 | 156 | // попап аватара 157 | const popupAvatar = new PopupWithForm( 158 | { 159 | handleFormSubmit: (data) => { 160 | api 161 | .patchAvatarInfo({ avatar: data.avatar }) // это метод класса Api 162 | .then((info) => { 163 | profilePopup.setAvatarInfo({ link: info.avatar }); // это метод из класса UserInfo. profilePopup - экземпляр класса UserInfo 164 | }) 165 | .then(() => { 166 | popupAvatar.close(), 167 | popUpAvatarValidation.resetInputs(), 168 | popUpAvatarValidation.disabledButton(); 169 | }) 170 | .catch((err) => console.log(err)) 171 | .finally(() => { 172 | submitButtonAvatar.textContent = "Сохранить"; 173 | }); 174 | }, 175 | }, 176 | ".popup_avatar" 177 | ); 178 | popupAvatar.setEventListeners(); 179 | // навешиваем слушатель на кнопку 180 | popUpAdd.addEventListener("click", () => { 181 | newCardPopup.open(); 182 | }); 183 | // навешиваем слушатель на кнопку 184 | popupProfileOpenButton.addEventListener("click", function () { 185 | newProfilePopup.open(); 186 | newProfilePopup.setInputsValues(profilePopup.getUserInfo()); 187 | }); 188 | // навешиваем слушатель на кнопку 189 | avatarPen.addEventListener("click", () => { 190 | popupAvatar.open(); 191 | }); 192 | // попап удаления 193 | const popupTrash = new PopupWithSubmit(".popup_trash"); 194 | popupTrash.setEventListeners(); 195 | // функция удаления карточек 196 | function handleDeleteCard(item) { 197 | popupTrash.open(() => { 198 | api 199 | .deleteCard(item.getId()) 200 | .then(() => { 201 | item.remove(); 202 | popupTrash.close(); 203 | }) 204 | .catch((err) => { 205 | console.log(err); 206 | }); 207 | }); 208 | } 209 | // функция добавления лайка 210 | function handleLikeCard(item) { 211 | api 212 | .getLike(item.getId()) 213 | .then((data) => { 214 | item.toggleLikeCard(data); 215 | }) 216 | .catch((err) => { 217 | console.log(err); 218 | }); 219 | } 220 | // функция удаления лайка 221 | function handleDeleteLikeCard(item) { 222 | api 223 | .deleteLike(item.getId()) 224 | .then((data) => { 225 | item.toggleLikeCard(data); 226 | }) 227 | .catch((err) => { 228 | console.log(err); 229 | }); 230 | } 231 | // данные пользователя 232 | let userId; // изменяю значение ниже, поэтому не могу обьявить константу 233 | const userInfo = api 234 | .getInfo() 235 | .then((data) => { 236 | userId = data._id; 237 | profilePopup.setUserInfo({ 238 | name: data.name, 239 | about: data.about, 240 | avatar: data.avatar, 241 | }); 242 | }) 243 | .catch((err) => { 244 | console.log(err); 245 | }); 246 | // чтобы все информация загружалась одновременно 247 | Promise.all([userInfo, elementaryCards]).then(() => cardList.renderItems()); 248 | -------------------------------------------------------------------------------- /src/vendor/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Место 7 | 8 | 9 |
10 |
11 | 16 |
17 |
18 |
19 | Аватарка страницы 24 |
25 |
26 |
27 |

Обновление...

28 | 35 |
36 |

Обновление...

37 |
38 | 45 |
46 |
47 |
48 | 51 | 86 | 136 | 185 | 202 | 203 | 224 | 239 |
240 | 241 | 242 | --------------------------------------------------------------------------------