├── .babelrc ├── .gitignore ├── README.md ├── assets ├── css │ ├── plugins │ │ └── fancybox │ │ │ ├── blank.gif │ │ │ ├── fancybox_loading.gif │ │ │ ├── fancybox_overlay.png │ │ │ ├── fancybox_sprite.png │ │ │ ├── helpers │ │ │ ├── fancybox_buttons.png │ │ │ ├── jquery.fancybox-buttons.css │ │ │ ├── jquery.fancybox-buttons.js │ │ │ ├── jquery.fancybox-media.js │ │ │ ├── jquery.fancybox-thumbs.css │ │ │ └── jquery.fancybox-thumbs.js │ │ │ └── jquery.fancybox.css │ ├── style.css │ └── style.min.css ├── fonts │ ├── fonts │ │ ├── Grands.eot │ │ ├── Grands.svg │ │ ├── Grands.ttf │ │ └── Grands.woff │ └── grand.css └── img │ ├── page │ ├── auth.png │ ├── auth_h.png │ └── blur.jpg │ └── user │ ├── heart.png │ └── video-play.png ├── auth.html ├── bundle.js ├── gulpfile.js ├── icon-app.png ├── package.json ├── react └── index.html ├── src ├── app │ ├── Root.jsx │ ├── actions │ │ ├── followers.js │ │ ├── index.js │ │ ├── profile.js │ │ ├── searchByTag.js │ │ ├── searchByUser.js │ │ └── timeline.js │ ├── api │ │ └── index.js │ ├── constants │ │ └── index.js │ ├── handlers │ │ ├── App.jsx │ │ ├── Followers.jsx │ │ ├── PageNotFound.jsx │ │ ├── Profile.jsx │ │ ├── SearchPhotos.jsx │ │ ├── SearchUsers.jsx │ │ └── Timeline.jsx │ ├── reducers │ │ ├── followers.js │ │ ├── index.js │ │ ├── profile.js │ │ ├── searchByTag.js │ │ ├── searchByUser.js │ │ └── timeline.js │ └── store │ │ └── index.js ├── helpers │ └── index.js └── stylus │ ├── _about.styl │ ├── _column.styl │ ├── _comments.styl │ ├── _feed.styl │ ├── _follow.styl │ ├── _fonts.styl │ ├── _footer.styl │ ├── _form.styl │ ├── _globals.styl │ ├── _grid.styl │ ├── _header.styl │ ├── _loader.styl │ ├── _main.styl │ ├── _menu.styl │ ├── _mixins.styl │ ├── _normalize.styl │ ├── _page.styl │ ├── _photo-list.styl │ ├── _photo.styl │ ├── _popup.styl │ ├── _profile.styl │ ├── _responsive.styl │ ├── _row.styl │ ├── _search.styl │ ├── _sidebar.styl │ ├── _social.styl │ ├── _user.styl │ ├── _vars.styl │ └── style.styl └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-0", "react"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .gitignore 3 | .module-cache 4 | node_modules 5 | index.html 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | React Instagram App 2 | == 3 | -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/blank.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/css/plugins/fancybox/blank.gif -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/fancybox_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/css/plugins/fancybox/fancybox_loading.gif -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/fancybox_overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/css/plugins/fancybox/fancybox_overlay.png -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/fancybox_sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/css/plugins/fancybox/fancybox_sprite.png -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/helpers/fancybox_buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/css/plugins/fancybox/helpers/fancybox_buttons.png -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/helpers/jquery.fancybox-buttons.css: -------------------------------------------------------------------------------- 1 | #fancybox-buttons { 2 | position: fixed; 3 | left: 0; 4 | width: 100%; 5 | z-index: 8050; 6 | } 7 | 8 | #fancybox-buttons.top { 9 | top: 10px; 10 | } 11 | 12 | #fancybox-buttons.bottom { 13 | bottom: 10px; 14 | } 15 | 16 | #fancybox-buttons ul { 17 | display: block; 18 | width: 166px; 19 | height: 30px; 20 | margin: 0 auto; 21 | padding: 0; 22 | list-style: none; 23 | border: 1px solid #111; 24 | border-radius: 3px; 25 | -webkit-box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); 26 | -moz-box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); 27 | box-shadow: inset 0 0 0 1px rgba(255,255,255,.05); 28 | background: rgb(50,50,50); 29 | background: -moz-linear-gradient(top, rgb(68,68,68) 0%, rgb(52,52,52) 50%, rgb(41,41,41) 50%, rgb(51,51,51) 100%); 30 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgb(68,68,68)), color-stop(50%,rgb(52,52,52)), color-stop(50%,rgb(41,41,41)), color-stop(100%,rgb(51,51,51))); 31 | background: -webkit-linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); 32 | background: -o-linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); 33 | background: -ms-linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); 34 | background: linear-gradient(top, rgb(68,68,68) 0%,rgb(52,52,52) 50%,rgb(41,41,41) 50%,rgb(51,51,51) 100%); 35 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#444444', endColorstr='#222222',GradientType=0 ); 36 | } 37 | 38 | #fancybox-buttons ul li { 39 | float: left; 40 | margin: 0; 41 | padding: 0; 42 | } 43 | 44 | #fancybox-buttons a { 45 | display: block; 46 | width: 30px; 47 | height: 30px; 48 | text-indent: -9999px; 49 | background-image: url('fancybox_buttons.png'); 50 | background-repeat: no-repeat; 51 | outline: none; 52 | opacity: 0.8; 53 | } 54 | 55 | #fancybox-buttons a:hover { 56 | opacity: 1; 57 | } 58 | 59 | #fancybox-buttons a.btnPrev { 60 | background-position: 5px 0; 61 | } 62 | 63 | #fancybox-buttons a.btnNext { 64 | background-position: -33px 0; 65 | border-right: 1px solid #3e3e3e; 66 | } 67 | 68 | #fancybox-buttons a.btnPlay { 69 | background-position: 0 -30px; 70 | } 71 | 72 | #fancybox-buttons a.btnPlayOn { 73 | background-position: -30px -30px; 74 | } 75 | 76 | #fancybox-buttons a.btnToggle { 77 | background-position: 3px -60px; 78 | border-left: 1px solid #111; 79 | border-right: 1px solid #3e3e3e; 80 | width: 35px 81 | } 82 | 83 | #fancybox-buttons a.btnToggleOn { 84 | background-position: -27px -60px; 85 | } 86 | 87 | #fancybox-buttons a.btnClose { 88 | border-left: 1px solid #111; 89 | width: 35px; 90 | background-position: -56px 0px; 91 | } 92 | 93 | #fancybox-buttons a.btnDisabled { 94 | opacity : 0.4; 95 | cursor: default; 96 | } -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/helpers/jquery.fancybox-buttons.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Buttons helper for fancyBox 3 | * version: 1.0.5 (Mon, 15 Oct 2012) 4 | * @requires fancyBox v2.0 or later 5 | * 6 | * Usage: 7 | * $(".fancybox").fancybox({ 8 | * helpers : { 9 | * buttons: { 10 | * position : 'top' 11 | * } 12 | * } 13 | * }); 14 | * 15 | */ 16 | (function ($) { 17 | //Shortcut for fancyBox object 18 | var F = $.fancybox; 19 | 20 | //Add helper object 21 | F.helpers.buttons = { 22 | defaults : { 23 | skipSingle : false, // disables if gallery contains single image 24 | position : 'top', // 'top' or 'bottom' 25 | tpl : '
' 26 | }, 27 | 28 | list : null, 29 | buttons: null, 30 | 31 | beforeLoad: function (opts, obj) { 32 | //Remove self if gallery do not have at least two items 33 | 34 | if (opts.skipSingle && obj.group.length < 2) { 35 | obj.helpers.buttons = false; 36 | obj.closeBtn = true; 37 | 38 | return; 39 | } 40 | 41 | //Increase top margin to give space for buttons 42 | obj.margin[ opts.position === 'bottom' ? 2 : 0 ] += 30; 43 | }, 44 | 45 | onPlayStart: function () { 46 | if (this.buttons) { 47 | this.buttons.play.attr('title', 'Pause slideshow').addClass('btnPlayOn'); 48 | } 49 | }, 50 | 51 | onPlayEnd: function () { 52 | if (this.buttons) { 53 | this.buttons.play.attr('title', 'Start slideshow').removeClass('btnPlayOn'); 54 | } 55 | }, 56 | 57 | afterShow: function (opts, obj) { 58 | var buttons = this.buttons; 59 | 60 | if (!buttons) { 61 | this.list = $(opts.tpl).addClass(opts.position).appendTo('body'); 62 | 63 | buttons = { 64 | prev : this.list.find('.btnPrev').click( F.prev ), 65 | next : this.list.find('.btnNext').click( F.next ), 66 | play : this.list.find('.btnPlay').click( F.play ), 67 | toggle : this.list.find('.btnToggle').click( F.toggle ) 68 | } 69 | } 70 | 71 | //Prev 72 | if (obj.index > 0 || obj.loop) { 73 | buttons.prev.removeClass('btnDisabled'); 74 | } else { 75 | buttons.prev.addClass('btnDisabled'); 76 | } 77 | 78 | //Next / Play 79 | if (obj.loop || obj.index < obj.group.length - 1) { 80 | buttons.next.removeClass('btnDisabled'); 81 | buttons.play.removeClass('btnDisabled'); 82 | 83 | } else { 84 | buttons.next.addClass('btnDisabled'); 85 | buttons.play.addClass('btnDisabled'); 86 | } 87 | 88 | this.buttons = buttons; 89 | 90 | this.onUpdate(opts, obj); 91 | }, 92 | 93 | onUpdate: function (opts, obj) { 94 | var toggle; 95 | 96 | if (!this.buttons) { 97 | return; 98 | } 99 | 100 | toggle = this.buttons.toggle.removeClass('btnDisabled btnToggleOn'); 101 | 102 | //Size toggle button 103 | if (obj.canShrink) { 104 | toggle.addClass('btnToggleOn'); 105 | 106 | } else if (!obj.canExpand) { 107 | toggle.addClass('btnDisabled'); 108 | } 109 | }, 110 | 111 | beforeClose: function () { 112 | if (this.list) { 113 | this.list.remove(); 114 | } 115 | 116 | this.list = null; 117 | this.buttons = null; 118 | } 119 | }; 120 | 121 | }(jQuery)); -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/helpers/jquery.fancybox-media.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Media helper for fancyBox 3 | * version: 1.0.5 (Tue, 23 Oct 2012) 4 | * @requires fancyBox v2.0 or later 5 | * 6 | * Usage: 7 | * $(".fancybox").fancybox({ 8 | * helpers : { 9 | * media: true 10 | * } 11 | * }); 12 | * 13 | * Set custom URL parameters: 14 | * $(".fancybox").fancybox({ 15 | * helpers : { 16 | * media: { 17 | * youtube : { 18 | * params : { 19 | * autoplay : 0 20 | * } 21 | * } 22 | * } 23 | * } 24 | * }); 25 | * 26 | * Or: 27 | * $(".fancybox").fancybox({, 28 | * helpers : { 29 | * media: true 30 | * }, 31 | * youtube : { 32 | * autoplay: 0 33 | * } 34 | * }); 35 | * 36 | * Supports: 37 | * 38 | * Youtube 39 | * http://www.youtube.com/watch?v=opj24KnzrWo 40 | * http://www.youtube.com/embed/opj24KnzrWo 41 | * http://youtu.be/opj24KnzrWo 42 | * Vimeo 43 | * http://vimeo.com/40648169 44 | * http://vimeo.com/channels/staffpicks/38843628 45 | * http://vimeo.com/groups/surrealism/videos/36516384 46 | * http://player.vimeo.com/video/45074303 47 | * Metacafe 48 | * http://www.metacafe.com/watch/7635964/dr_seuss_the_lorax_movie_trailer/ 49 | * http://www.metacafe.com/watch/7635964/ 50 | * Dailymotion 51 | * http://www.dailymotion.com/video/xoytqh_dr-seuss-the-lorax-premiere_people 52 | * Twitvid 53 | * http://twitvid.com/QY7MD 54 | * Twitpic 55 | * http://twitpic.com/7p93st 56 | * Instagram 57 | * http://instagr.am/p/IejkuUGxQn/ 58 | * http://instagram.com/p/IejkuUGxQn/ 59 | * Google maps 60 | * http://maps.google.com/maps?q=Eiffel+Tower,+Avenue+Gustave+Eiffel,+Paris,+France&t=h&z=17 61 | * http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16 62 | * http://maps.google.com/?ll=48.859463,2.292626&spn=0.000965,0.002642&t=m&z=19&layer=c&cbll=48.859524,2.292532&panoid=YJ0lq28OOy3VT2IqIuVY0g&cbp=12,151.58,,0,-15.56 63 | */ 64 | (function ($) { 65 | "use strict"; 66 | 67 | //Shortcut for fancyBox object 68 | var F = $.fancybox, 69 | format = function( url, rez, params ) { 70 | params = params || ''; 71 | 72 | if ( $.type( params ) === "object" ) { 73 | params = $.param(params, true); 74 | } 75 | 76 | $.each(rez, function(key, value) { 77 | url = url.replace( '$' + key, value || '' ); 78 | }); 79 | 80 | if (params.length) { 81 | url += ( url.indexOf('?') > 0 ? '&' : '?' ) + params; 82 | } 83 | 84 | return url; 85 | }; 86 | 87 | //Add helper object 88 | F.helpers.media = { 89 | defaults : { 90 | youtube : { 91 | matcher : /(youtube\.com|youtu\.be)\/(watch\?v=|v\/|u\/|embed\/?)?(videoseries\?list=(.*)|[\w-]{11}|\?listType=(.*)&list=(.*)).*/i, 92 | params : { 93 | autoplay : 1, 94 | autohide : 1, 95 | fs : 1, 96 | rel : 0, 97 | hd : 1, 98 | wmode : 'opaque', 99 | enablejsapi : 1 100 | }, 101 | type : 'iframe', 102 | url : '//www.youtube.com/embed/$3' 103 | }, 104 | vimeo : { 105 | matcher : /(?:vimeo(?:pro)?.com)\/(?:[^\d]+)?(\d+)(?:.*)/, 106 | params : { 107 | autoplay : 1, 108 | hd : 1, 109 | show_title : 1, 110 | show_byline : 1, 111 | show_portrait : 0, 112 | fullscreen : 1 113 | }, 114 | type : 'iframe', 115 | url : '//player.vimeo.com/video/$1' 116 | }, 117 | metacafe : { 118 | matcher : /metacafe.com\/(?:watch|fplayer)\/([\w\-]{1,10})/, 119 | params : { 120 | autoPlay : 'yes' 121 | }, 122 | type : 'swf', 123 | url : function( rez, params, obj ) { 124 | obj.swf.flashVars = 'playerVars=' + $.param( params, true ); 125 | 126 | return '//www.metacafe.com/fplayer/' + rez[1] + '/.swf'; 127 | } 128 | }, 129 | dailymotion : { 130 | matcher : /dailymotion.com\/video\/(.*)\/?(.*)/, 131 | params : { 132 | additionalInfos : 0, 133 | autoStart : 1 134 | }, 135 | type : 'swf', 136 | url : '//www.dailymotion.com/swf/video/$1' 137 | }, 138 | twitvid : { 139 | matcher : /twitvid\.com\/([a-zA-Z0-9_\-\?\=]+)/i, 140 | params : { 141 | autoplay : 0 142 | }, 143 | type : 'iframe', 144 | url : '//www.twitvid.com/embed.php?guid=$1' 145 | }, 146 | twitpic : { 147 | matcher : /twitpic\.com\/(?!(?:place|photos|events)\/)([a-zA-Z0-9\?\=\-]+)/i, 148 | type : 'image', 149 | url : '//twitpic.com/show/full/$1/' 150 | }, 151 | instagram : { 152 | matcher : /(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i, 153 | type : 'image', 154 | url : '//$1/p/$2/media/' 155 | }, 156 | google_maps : { 157 | matcher : /maps\.google\.([a-z]{2,3}(\.[a-z]{2})?)\/(\?ll=|maps\?)(.*)/i, 158 | type : 'iframe', 159 | url : function( rez ) { 160 | return '//maps.google.' + rez[1] + '/' + rez[3] + '' + rez[4] + '&output=' + (rez[4].indexOf('layer=c') > 0 ? 'svembed' : 'embed'); 161 | } 162 | } 163 | }, 164 | 165 | beforeLoad : function(opts, obj) { 166 | var url = obj.href || '', 167 | type = false, 168 | what, 169 | item, 170 | rez, 171 | params; 172 | 173 | for (what in opts) { 174 | item = opts[ what ]; 175 | rez = url.match( item.matcher ); 176 | 177 | if (rez) { 178 | type = item.type; 179 | params = $.extend(true, {}, item.params, obj[ what ] || ($.isPlainObject(opts[ what ]) ? opts[ what ].params : null)); 180 | 181 | url = $.type( item.url ) === "function" ? item.url.call( this, rez, params, obj ) : format( item.url, rez, params ); 182 | 183 | break; 184 | } 185 | } 186 | 187 | if (type) { 188 | obj.href = url; 189 | obj.type = type; 190 | 191 | obj.autoHeight = false; 192 | } 193 | } 194 | }; 195 | 196 | }(jQuery)); -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/helpers/jquery.fancybox-thumbs.css: -------------------------------------------------------------------------------- 1 | #fancybox-thumbs { 2 | position: fixed; 3 | left: 0; 4 | width: 100%; 5 | overflow: hidden; 6 | z-index: 8050; 7 | } 8 | 9 | #fancybox-thumbs.bottom { 10 | bottom: 2px; 11 | } 12 | 13 | #fancybox-thumbs.top { 14 | top: 2px; 15 | } 16 | 17 | #fancybox-thumbs ul { 18 | position: relative; 19 | list-style: none; 20 | margin: 0; 21 | padding: 0; 22 | } 23 | 24 | #fancybox-thumbs ul li { 25 | float: left; 26 | padding: 1px; 27 | opacity: 0.5; 28 | } 29 | 30 | #fancybox-thumbs ul li.active { 31 | opacity: 0.75; 32 | padding: 0; 33 | border: 1px solid #fff; 34 | } 35 | 36 | #fancybox-thumbs ul li:hover { 37 | opacity: 1; 38 | } 39 | 40 | #fancybox-thumbs ul li a { 41 | display: block; 42 | position: relative; 43 | overflow: hidden; 44 | border: 1px solid #222; 45 | background: #111; 46 | outline: none; 47 | } 48 | 49 | #fancybox-thumbs ul li img { 50 | display: block; 51 | position: relative; 52 | border: 0; 53 | padding: 0; 54 | } -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/helpers/jquery.fancybox-thumbs.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Thumbnail helper for fancyBox 3 | * version: 1.0.7 (Mon, 01 Oct 2012) 4 | * @requires fancyBox v2.0 or later 5 | * 6 | * Usage: 7 | * $(".fancybox").fancybox({ 8 | * helpers : { 9 | * thumbs: { 10 | * width : 50, 11 | * height : 50 12 | * } 13 | * } 14 | * }); 15 | * 16 | */ 17 | (function ($) { 18 | //Shortcut for fancyBox object 19 | var F = $.fancybox; 20 | 21 | //Add helper object 22 | F.helpers.thumbs = { 23 | defaults : { 24 | width : 50, // thumbnail width 25 | height : 50, // thumbnail height 26 | position : 'bottom', // 'top' or 'bottom' 27 | source : function ( item ) { // function to obtain the URL of the thumbnail image 28 | var href; 29 | 30 | if (item.element) { 31 | href = $(item.element).find('img').attr('src'); 32 | } 33 | 34 | if (!href && item.type === 'image' && item.href) { 35 | href = item.href; 36 | } 37 | 38 | return href; 39 | } 40 | }, 41 | 42 | wrap : null, 43 | list : null, 44 | width : 0, 45 | 46 | init: function (opts, obj) { 47 | var that = this, 48 | list, 49 | thumbWidth = opts.width, 50 | thumbHeight = opts.height, 51 | thumbSource = opts.source; 52 | 53 | //Build list structure 54 | list = ''; 55 | 56 | for (var n = 0; n < obj.group.length; n++) { 57 | list += '
  • '; 58 | } 59 | 60 | this.wrap = $('
    ').addClass(opts.position).appendTo('body'); 61 | this.list = $('').appendTo(this.wrap); 62 | 63 | //Load each thumbnail 64 | $.each(obj.group, function (i) { 65 | var href = thumbSource( obj.group[ i ] ); 66 | 67 | if (!href) { 68 | return; 69 | } 70 | 71 | $("").load(function () { 72 | var width = this.width, 73 | height = this.height, 74 | widthRatio, heightRatio, parent; 75 | 76 | if (!that.list || !width || !height) { 77 | return; 78 | } 79 | 80 | //Calculate thumbnail width/height and center it 81 | widthRatio = width / thumbWidth; 82 | heightRatio = height / thumbHeight; 83 | 84 | parent = that.list.children().eq(i).find('a'); 85 | 86 | if (widthRatio >= 1 && heightRatio >= 1) { 87 | if (widthRatio > heightRatio) { 88 | width = Math.floor(width / heightRatio); 89 | height = thumbHeight; 90 | 91 | } else { 92 | width = thumbWidth; 93 | height = Math.floor(height / widthRatio); 94 | } 95 | } 96 | 97 | $(this).css({ 98 | width : width, 99 | height : height, 100 | top : Math.floor(thumbHeight / 2 - height / 2), 101 | left : Math.floor(thumbWidth / 2 - width / 2) 102 | }); 103 | 104 | parent.width(thumbWidth).height(thumbHeight); 105 | 106 | $(this).hide().appendTo(parent).fadeIn(300); 107 | 108 | }).attr('src', href); 109 | }); 110 | 111 | //Set initial width 112 | this.width = this.list.children().eq(0).outerWidth(true); 113 | 114 | this.list.width(this.width * (obj.group.length + 1)).css('left', Math.floor($(window).width() * 0.5 - (obj.index * this.width + this.width * 0.5))); 115 | }, 116 | 117 | beforeLoad: function (opts, obj) { 118 | //Remove self if gallery do not have at least two items 119 | if (obj.group.length < 2) { 120 | obj.helpers.thumbs = false; 121 | 122 | return; 123 | } 124 | 125 | //Increase bottom margin to give space for thumbs 126 | obj.margin[ opts.position === 'top' ? 0 : 2 ] += ((opts.height) + 15); 127 | }, 128 | 129 | afterShow: function (opts, obj) { 130 | //Check if exists and create or update list 131 | if (this.list) { 132 | this.onUpdate(opts, obj); 133 | 134 | } else { 135 | this.init(opts, obj); 136 | } 137 | 138 | //Set active element 139 | this.list.children().removeClass('active').eq(obj.index).addClass('active'); 140 | }, 141 | 142 | //Center list 143 | onUpdate: function (opts, obj) { 144 | if (this.list) { 145 | this.list.stop(true).animate({ 146 | 'left': Math.floor($(window).width() * 0.5 - (obj.index * this.width + this.width * 0.5)) 147 | }, 150); 148 | } 149 | }, 150 | 151 | beforeClose: function () { 152 | if (this.wrap) { 153 | this.wrap.remove(); 154 | } 155 | 156 | this.wrap = null; 157 | this.list = null; 158 | this.width = 0; 159 | } 160 | } 161 | 162 | }(jQuery)); -------------------------------------------------------------------------------- /assets/css/plugins/fancybox/jquery.fancybox.css: -------------------------------------------------------------------------------- 1 | /*! fancyBox v2.1.4 fancyapps.com | fancyapps.com/fancybox/#license */ 2 | .fancybox-wrap, 3 | .fancybox-skin, 4 | .fancybox-outer, 5 | .fancybox-inner, 6 | .fancybox-image, 7 | .fancybox-wrap iframe, 8 | .fancybox-wrap object, 9 | .fancybox-nav, 10 | .fancybox-nav span, 11 | .fancybox-tmp 12 | { 13 | padding: 0; 14 | margin: 0; 15 | border: 0; 16 | outline: none; 17 | vertical-align: top; 18 | } 19 | 20 | .fancybox-wrap { 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | z-index: 8020; 25 | } 26 | 27 | .fancybox-skin { 28 | position: relative; 29 | background: #f9f9f9; 30 | color: #444; 31 | text-shadow: none; 32 | -webkit-border-radius: 4px; 33 | -moz-border-radius: 4px; 34 | border-radius: 4px; 35 | } 36 | 37 | .fancybox-opened { 38 | z-index: 8030; 39 | } 40 | 41 | .fancybox-opened .fancybox-skin { 42 | -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); 43 | -moz-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); 44 | box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5); 45 | } 46 | 47 | .fancybox-outer, .fancybox-inner { 48 | position: relative; 49 | } 50 | 51 | .fancybox-inner { 52 | overflow: hidden; 53 | } 54 | 55 | .fancybox-type-iframe .fancybox-inner { 56 | -webkit-overflow-scrolling: touch; 57 | } 58 | 59 | .fancybox-error { 60 | color: #444; 61 | font: 14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; 62 | margin: 0; 63 | padding: 15px; 64 | white-space: nowrap; 65 | } 66 | 67 | .fancybox-image, .fancybox-iframe { 68 | display: block; 69 | width: 100%; 70 | height: 100%; 71 | } 72 | 73 | .fancybox-image { 74 | max-width: 100%; 75 | max-height: 100%; 76 | } 77 | 78 | #fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span { 79 | background-image: url('fancybox_sprite.png'); 80 | } 81 | 82 | #fancybox-loading { 83 | position: fixed; 84 | top: 50%; 85 | left: 50%; 86 | margin-top: -22px; 87 | margin-left: -22px; 88 | background-position: 0 -108px; 89 | opacity: 0.8; 90 | cursor: pointer; 91 | z-index: 8060; 92 | } 93 | 94 | #fancybox-loading div { 95 | width: 44px; 96 | height: 44px; 97 | background: url('fancybox_loading.gif') center center no-repeat; 98 | } 99 | 100 | .fancybox-close { 101 | position: absolute; 102 | top: -18px; 103 | right: -18px; 104 | width: 36px; 105 | height: 36px; 106 | cursor: pointer; 107 | z-index: 8040; 108 | } 109 | 110 | .fancybox-nav { 111 | position: absolute; 112 | top: 0; 113 | width: 40%; 114 | height: 100%; 115 | cursor: pointer; 116 | text-decoration: none; 117 | background: transparent url('blank.gif'); /* helps IE */ 118 | -webkit-tap-highlight-color: rgba(0,0,0,0); 119 | z-index: 8040; 120 | } 121 | 122 | .fancybox-prev { 123 | left: 0; 124 | } 125 | 126 | .fancybox-next { 127 | right: 0; 128 | } 129 | 130 | .fancybox-nav span { 131 | position: absolute; 132 | top: 50%; 133 | width: 36px; 134 | height: 34px; 135 | margin-top: -18px; 136 | cursor: pointer; 137 | z-index: 8040; 138 | visibility: hidden; 139 | } 140 | 141 | .fancybox-prev span { 142 | left: 10px; 143 | background-position: 0 -36px; 144 | } 145 | 146 | .fancybox-next span { 147 | right: 10px; 148 | background-position: 0 -72px; 149 | } 150 | 151 | .fancybox-nav:hover span { 152 | visibility: visible; 153 | } 154 | 155 | .fancybox-tmp { 156 | position: absolute; 157 | top: -99999px; 158 | left: -99999px; 159 | visibility: hidden; 160 | max-width: 99999px; 161 | max-height: 99999px; 162 | overflow: visible !important; 163 | } 164 | 165 | /* Overlay helper */ 166 | 167 | .fancybox-lock { 168 | overflow: hidden; 169 | } 170 | 171 | .fancybox-overlay { 172 | position: absolute; 173 | top: 0; 174 | left: 0; 175 | overflow: hidden; 176 | display: none; 177 | z-index: 8010; 178 | background: url('fancybox_overlay.png'); 179 | } 180 | 181 | .fancybox-overlay-fixed { 182 | position: fixed; 183 | bottom: 0; 184 | right: 0; 185 | } 186 | 187 | .fancybox-lock .fancybox-overlay { 188 | overflow: auto; 189 | overflow-y: scroll; 190 | } 191 | 192 | /* Title helper */ 193 | 194 | .fancybox-title { 195 | visibility: hidden; 196 | font: normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif; 197 | position: relative; 198 | text-shadow: none; 199 | z-index: 8050; 200 | } 201 | 202 | .fancybox-opened .fancybox-title { 203 | visibility: visible; 204 | } 205 | 206 | .fancybox-title-float-wrap { 207 | position: absolute; 208 | bottom: 0; 209 | right: 50%; 210 | margin-bottom: -35px; 211 | z-index: 8050; 212 | text-align: center; 213 | } 214 | 215 | .fancybox-title-float-wrap .child { 216 | display: inline-block; 217 | margin-right: -100%; 218 | padding: 2px 20px; 219 | background: transparent; /* Fallback for web browsers that doesn't support RGBa */ 220 | background: rgba(0, 0, 0, 0.8); 221 | -webkit-border-radius: 15px; 222 | -moz-border-radius: 15px; 223 | border-radius: 15px; 224 | text-shadow: 0 1px 2px #222; 225 | color: #FFF; 226 | font-weight: bold; 227 | line-height: 24px; 228 | white-space: nowrap; 229 | } 230 | 231 | .fancybox-title-outside-wrap { 232 | position: relative; 233 | margin-top: 10px; 234 | color: #fff; 235 | } 236 | 237 | .fancybox-title-inside-wrap { 238 | padding-top: 10px; 239 | } 240 | 241 | .fancybox-title-over-wrap { 242 | position: absolute; 243 | bottom: 0; 244 | left: 0; 245 | color: #fff; 246 | padding: 10px; 247 | background: #000; 248 | background: rgba(0, 0, 0, .8); 249 | } -------------------------------------------------------------------------------- /assets/css/style.css: -------------------------------------------------------------------------------- 1 | /* Шрифты */ 2 | @import url('http://fonts.googleapis.com/css?family=PT+Sans:400,700&subset=latin,cyrillic'); 3 | @import url('../fonts/grand.css'); 4 | /* Normalize */ 5 | /* normalize.css v3.0.0 | MIT License | git.io/normalize */ 6 | html 7 | { 8 | font-family: sans-serif; 9 | 10 | -ms-text-size-adjust: 100%; 11 | -webkit-text-size-adjust: 100%; 12 | } 13 | body 14 | { 15 | margin: 0; 16 | } 17 | article, 18 | aside, 19 | details, 20 | figcaption, 21 | figure, 22 | footer, 23 | header, 24 | hgroup, 25 | main, 26 | nav, 27 | section, 28 | summary 29 | { 30 | display: block; 31 | } 32 | audio, 33 | canvas, 34 | progress, 35 | video 36 | { 37 | display: inline-block; 38 | 39 | vertical-align: baseline; 40 | } 41 | audio:not([controls]) 42 | { 43 | display: none; 44 | 45 | height: 0; 46 | } 47 | [hidden], 48 | template 49 | { 50 | display: none; 51 | } 52 | a 53 | { 54 | background: transparent; 55 | } 56 | a:active, 57 | a:hover 58 | { 59 | outline: 0; 60 | } 61 | abbr[title] 62 | { 63 | border-bottom: 1px dotted; 64 | } 65 | b, 66 | strong 67 | { 68 | font-weight: bold; 69 | } 70 | dfn 71 | { 72 | font-style: italic; 73 | } 74 | h1 75 | { 76 | font-size: 2em; 77 | 78 | margin: .67em 0; 79 | } 80 | mark 81 | { 82 | color: #000; 83 | background: #ff0; 84 | } 85 | small 86 | { 87 | font-size: 80%; 88 | } 89 | sub, 90 | sup 91 | { 92 | font-size: 75%; 93 | line-height: 0; 94 | 95 | position: relative; 96 | 97 | vertical-align: baseline; 98 | } 99 | sup 100 | { 101 | top: -.5em; 102 | } 103 | sub 104 | { 105 | bottom: -.25em; 106 | } 107 | img 108 | { 109 | border: 0; 110 | } 111 | svg:not(:root) 112 | { 113 | overflow: hidden; 114 | } 115 | figure 116 | { 117 | margin: 1em 40px; 118 | } 119 | hr 120 | { 121 | -moz-box-sizing: content-box; 122 | box-sizing: content-box; 123 | height: 0; 124 | } 125 | pre 126 | { 127 | overflow: auto; 128 | } 129 | code, 130 | kbd, 131 | pre, 132 | samp 133 | { 134 | font-family: monospace, monospace; 135 | font-size: 1em; 136 | } 137 | button, 138 | input, 139 | optgroup, 140 | select, 141 | textarea 142 | { 143 | font: inherit; 144 | 145 | margin: 0; 146 | 147 | color: inherit; 148 | } 149 | button 150 | { 151 | overflow: visible; 152 | } 153 | button, 154 | select 155 | { 156 | text-transform: none; 157 | } 158 | button, 159 | html input[type='button'], 160 | input[type='reset'], 161 | input[type='submit'] 162 | { 163 | cursor: pointer; 164 | 165 | -webkit-appearance: button; 166 | } 167 | button[disabled], 168 | html input[disabled] 169 | { 170 | cursor: default; 171 | } 172 | button::-moz-focus-inner, 173 | input::-moz-focus-inner 174 | { 175 | padding: 0; 176 | 177 | border: 0; 178 | } 179 | input 180 | { 181 | line-height: normal; 182 | } 183 | input[type='checkbox'], 184 | input[type='radio'] 185 | { 186 | box-sizing: border-box; 187 | padding: 0; 188 | } 189 | input[type='number']::-webkit-inner-spin-button, 190 | input[type='number']::-webkit-outer-spin-button 191 | { 192 | height: auto; 193 | } 194 | input[type='search'] 195 | { 196 | -webkit-box-sizing: content-box; 197 | -moz-box-sizing: content-box; 198 | box-sizing: content-box; 199 | 200 | -webkit-appearance: textfield; 201 | } 202 | input[type='search']::-webkit-search-cancel-button, 203 | input[type='search']::-webkit-search-decoration 204 | { 205 | -webkit-appearance: none; 206 | } 207 | fieldset 208 | { 209 | margin: 0 2px; 210 | padding: .35em .625em .75em; 211 | 212 | border: 1px solid #c0c0c0; 213 | } 214 | legend 215 | { 216 | padding: 0; 217 | 218 | border: 0; 219 | } 220 | textarea 221 | { 222 | overflow: auto; 223 | } 224 | optgroup 225 | { 226 | font-weight: bold; 227 | } 228 | table 229 | { 230 | border-spacing: 0; 231 | border-collapse: collapse; 232 | } 233 | td, 234 | th 235 | { 236 | padding: 0; 237 | } 238 | /* Глобальные стили */ 239 | * 240 | { 241 | -webkit-box-sizing: border-box; 242 | -moz-box-sizing: border-box; 243 | box-sizing: border-box; 244 | } 245 | .g-clf:after, 246 | .g-clf:before 247 | { 248 | display: table; 249 | clear: both; 250 | 251 | content: ''; 252 | } 253 | /* Обвязка */ 254 | html, 255 | body 256 | { 257 | font: normal 16px 'PT Sans', Verdana, Tahoma; 258 | 259 | height: 100%; 260 | } 261 | body 262 | { 263 | background: #bdc3c7; 264 | } 265 | body.welcome 266 | { 267 | background: url('../img/page/blur.jpg') no-repeat 0 0; 268 | -webkit-background-size: cover; 269 | -moz-background-size: cover; 270 | background-size: cover; 271 | 272 | -ms-background-size: cover; 273 | } 274 | body .auth 275 | { 276 | position: absolute; 277 | top: 50%; 278 | left: 50%; 279 | 280 | display: block; 281 | 282 | width: 200px; 283 | height: 29px; 284 | margin-left: -100px; 285 | 286 | cursor: pointer; 287 | text-indent: -9999px; 288 | 289 | outline: none; 290 | background: url('../img/page/auth.png') no-repeat 0 0; 291 | } 292 | body .auth:hover 293 | { 294 | background: url('../img/page/auth_h.png') no-repeat 0 0; 295 | } 296 | .page 297 | { 298 | position: relative; 299 | 300 | min-height: 100%; 301 | margin: 0 auto; 302 | } 303 | /* Шапка */ 304 | .header 305 | { 306 | position: fixed; 307 | z-index: 9999; 308 | top: 0; 309 | left: 0; 310 | 311 | width: 100%; 312 | height: 50px; 313 | 314 | background: #17b287; 315 | -webkit-box-shadow: 0 1px 1px 2px rgba(0,0,0,.5); 316 | -moz-box-shadow: 0 1px 1px 2px rgba(0,0,0,.5); 317 | box-shadow: 0 1px 1px 2px rgba(0,0,0,.5); 318 | } 319 | /* Menu */ 320 | .menu 321 | { 322 | margin: 0; 323 | padding: 14px 0 0; 324 | 325 | list-style: none; 326 | 327 | text-align: center; 328 | } 329 | .menu__item 330 | { 331 | display: inline-block; 332 | 333 | margin-right: 15px; 334 | 335 | cursor: pointer; 336 | } 337 | .menu__item:last-child 338 | { 339 | margin-right: 0; 340 | } 341 | .menu__link 342 | { 343 | padding: 5px 20px; 344 | 345 | -webkit-transition: color .5s ease; 346 | -moz-transition: color .5s ease; 347 | transition: color .5s ease; 348 | text-decoration: none; 349 | 350 | color: #17b287; 351 | background: #f9f9f9; 352 | } 353 | .menu__link:hover 354 | { 355 | color: #ff4c4b; 356 | } 357 | /* Основной контент */ 358 | .main 359 | { 360 | margin: 0 auto; 361 | padding: 50px 10px 115px; 362 | } 363 | /* Боковое меню */ 364 | /* Подвал */ 365 | .footer 366 | { 367 | position: absolute; 368 | bottom: 0; 369 | 370 | width: 100%; 371 | height: 89px; 372 | 373 | border-top: 1px solid #4f4f50; 374 | border-bottom: 1px solid #4f4f50; 375 | background: #444; 376 | } 377 | .footer__copyright 378 | { 379 | font: normal .75em 'Tahoma', Arial, Verdana; 380 | 381 | float: right; 382 | 383 | margin: 38px 60px 0 0; 384 | 385 | color: #dddbdb; 386 | } 387 | /* Форма */ 388 | .form 389 | { 390 | position: relative; 391 | 392 | width: 605px; 393 | } 394 | .form__field 395 | { 396 | margin: 0; 397 | padding: 0; 398 | 399 | border: 0; 400 | } 401 | .form__label 402 | { 403 | display: block; 404 | 405 | padding: 5px 0; 406 | } 407 | .form__label-title 408 | { 409 | display: inline-block; 410 | 411 | width: 200px; 412 | 413 | vertical-align: top; 414 | } 415 | .form__input, 416 | .form__select, 417 | .form__textarea 418 | { 419 | font-size: .875em; 420 | 421 | width: 400px; 422 | 423 | border: 1px solid #a0a0a0; 424 | outline: none; 425 | } 426 | .form__input 427 | { 428 | height: 30px; 429 | } 430 | .form__input, 431 | .form__textarea 432 | { 433 | padding: 0 5px; 434 | } 435 | .form__input:focus, 436 | .form__textarea:focus 437 | { 438 | -webkit-box-shadow: 0 0 2px 2px #ffe500; 439 | -moz-box-shadow: 0 0 2px 2px #ffe500; 440 | box-shadow: 0 0 2px 2px #ffe500; 441 | } 442 | .form__select 443 | { 444 | width: 200px; 445 | } 446 | .form__textarea 447 | { 448 | padding: 3px 5px; 449 | 450 | resize: vertical; 451 | } 452 | .form__answer 453 | { 454 | display: inline-block; 455 | 456 | width: 400px; 457 | } 458 | .form__radio-wrapper 459 | { 460 | display: block; 461 | } 462 | /* Сетка */ 463 | .grid 464 | { 465 | display: block; 466 | } 467 | /* Строка сетки */ 468 | .row 469 | { 470 | margin-bottom: 15px; 471 | } 472 | /* Колонка сетки */ 473 | [class*='column_xs-'] 474 | { 475 | float: left; 476 | } 477 | .column 478 | { 479 | position: relative; 480 | 481 | min-height: 1px; 482 | padding-right: 10px; 483 | padding-left: 10px; 484 | } 485 | .column_xs-1 486 | { 487 | width: 8.333333333333334%; 488 | } 489 | .column_xs-2 490 | { 491 | width: 16.666666666666668%; 492 | } 493 | .column_xs-3 494 | { 495 | width: 25%; 496 | } 497 | .column_xs-4 498 | { 499 | width: 33.333333333333336%; 500 | } 501 | .column_xs-5 502 | { 503 | width: 41.66666666666667%; 504 | } 505 | .column_xs-6 506 | { 507 | width: 50%; 508 | } 509 | .column_xs-7 510 | { 511 | width: 58.333333333333336%; 512 | } 513 | .column_xs-8 514 | { 515 | width: 66.66666666666667%; 516 | } 517 | .column_xs-9 518 | { 519 | width: 75%; 520 | } 521 | .column_xs-10 522 | { 523 | width: 83.33333333333334%; 524 | } 525 | .column_xs-11 526 | { 527 | width: 91.66666666666667%; 528 | } 529 | .column_xs-12 530 | { 531 | width: 100%; 532 | } 533 | .column__offset_xs-1 534 | { 535 | margin-left: 8.333333333333334%; 536 | } 537 | .column__offset_xs-2 538 | { 539 | margin-left: 16.666666666666668%; 540 | } 541 | .column__offset_xs-3 542 | { 543 | margin-left: 25%; 544 | } 545 | .column__offset_xs-4 546 | { 547 | margin-left: 33.333333333333336%; 548 | } 549 | .column__offset_xs-5 550 | { 551 | margin-left: 41.66666666666667%; 552 | } 553 | .column__offset_xs-6 554 | { 555 | margin-left: 50%; 556 | } 557 | .column__offset_xs-7 558 | { 559 | margin-left: 58.333333333333336%; 560 | } 561 | .column__offset_xs-8 562 | { 563 | margin-left: 66.66666666666667%; 564 | } 565 | .column__offset_xs-9 566 | { 567 | margin-left: 75%; 568 | } 569 | .column__offset_xs-10 570 | { 571 | margin-left: 83.33333333333334%; 572 | } 573 | .column__offset_xs-11 574 | { 575 | margin-left: 91.66666666666667%; 576 | } 577 | .column__offset_xs-12 578 | { 579 | margin-left: 100%; 580 | } 581 | /* Profile */ 582 | .profile 583 | { 584 | margin: 40px 0 0; 585 | } 586 | .profile__photo 587 | { 588 | display: block; 589 | 590 | width: 150px; 591 | height: 150px; 592 | margin: 0 auto; 593 | } 594 | .profile__username 595 | { 596 | font: bold 2em; 597 | line-height: 20px; 598 | 599 | margin: 10px 0 0; 600 | 601 | text-align: center; 602 | 603 | color: #fff; 604 | text-shadow: 0 1px 2px #333; 605 | } 606 | .profile__stats, 607 | .profile__info 608 | { 609 | margin: 20px 0 30px; 610 | padding: 0; 611 | 612 | list-style: none; 613 | 614 | text-align: center; 615 | } 616 | .profile__item 617 | { 618 | font: normal 1.25em; 619 | 620 | display: inline-block; 621 | 622 | padding: 0 20px; 623 | 624 | text-align: center; 625 | 626 | color: #fff; 627 | text-shadow: 0 1px 1px #333; 628 | } 629 | .profile__item a 630 | { 631 | -webkit-transition: color .5s ease; 632 | -moz-transition: color .5s ease; 633 | transition: color .5s ease; 634 | text-decoration: none; 635 | 636 | color: #fff; 637 | text-shadow: 0 1px 1px #333; 638 | } 639 | .profile__item a:hover 640 | { 641 | color: #17b287; 642 | } 643 | .profile__info .profile__item 644 | { 645 | display: block; 646 | 647 | text-align: center; 648 | 649 | color: #333; 650 | text-shadow: none; 651 | } 652 | /* Popular */ 653 | .search 654 | { 655 | margin: 40px 0 0; 656 | } 657 | .search__form 658 | { 659 | width: 100%; 660 | height: 60px; 661 | margin: 0 auto 30px; 662 | } 663 | .search__input 664 | { 665 | font: normal 24px 'Roboto Condensed'; 666 | 667 | display: inline-block; 668 | 669 | width: 100%; 670 | height: 60px; 671 | padding: 0 14px; 672 | 673 | color: #bdbab4; 674 | border: 0; 675 | outline: none; 676 | } 677 | /* Photo List */ 678 | .photo-list 679 | { 680 | margin: 0; 681 | padding: 0; 682 | 683 | list-style: none; 684 | } 685 | .photo-list__item 686 | { 687 | display: inline-block; 688 | 689 | width: 20.5%; 690 | margin: 0 6% 6% 0; 691 | 692 | cursor: pointer; 693 | } 694 | .photo-list__item:nth-child(4n) 695 | { 696 | margin-right: 0; 697 | } 698 | .photo-list__item img 699 | { 700 | max-width: 100%; 701 | 702 | -webkit-box-shadow: 0 0 2px 3px rgba(0,0,0,.7); 703 | -moz-box-shadow: 0 0 2px 3px rgba(0,0,0,.7); 704 | box-shadow: 0 0 2px 3px rgba(0,0,0,.7); 705 | } 706 | .photo-list__likes 707 | { 708 | font-size: .7em; 709 | 710 | float: right; 711 | 712 | color: #333; 713 | } 714 | .photo-list__likes:hover 715 | { 716 | text-decoration: underline; 717 | } 718 | /* About page */ 719 | .about 720 | { 721 | padding-top: 40px; 722 | 723 | text-align: center; 724 | } 725 | .about__header 726 | { 727 | font: bold 2em 'Roboto Condensed', Arial, Tahoma; 728 | 729 | color: #fff; 730 | text-shadow: 0 1px 1px #333; 731 | } 732 | .about__text 733 | { 734 | color: #333; 735 | text-shadow: 0 1px 1px #fff; 736 | } 737 | .about__text a 738 | { 739 | -webkit-transition: border-color .5s ease; 740 | -moz-transition: border-color .5s ease; 741 | transition: border-color .5s ease; 742 | text-decoration: none; 743 | 744 | color: #333; 745 | border-bottom: 1px dashed #27ae60; 746 | } 747 | .about__text a:hover 748 | { 749 | border-color: #ff4c4b; 750 | } 751 | /* Social Icons */ 752 | .social 753 | { 754 | float: left; 755 | 756 | margin: 32px 0 0 60px; 757 | padding: 0; 758 | 759 | list-style: none; 760 | } 761 | .social__item 762 | { 763 | display: inline-block; 764 | float: left; 765 | 766 | margin-left: 15px; 767 | } 768 | .social__item:first-child 769 | { 770 | margin-left: 0; 771 | } 772 | .social__link 773 | { 774 | font: normal 24px 'Arial', Tahoma, Verdana; 775 | 776 | -webkit-transition: color .4s ease; 777 | -moz-transition: color .4s ease; 778 | transition: color .4s ease; 779 | text-decoration: none; 780 | text-indent: -9999px; 781 | 782 | color: #dddbdb; 783 | } 784 | .social__link:hover 785 | { 786 | color: #27ae60; 787 | } 788 | /* Feed */ 789 | .feed 790 | { 791 | width: 95%; 792 | margin: 2% auto 0; 793 | padding: 0; 794 | 795 | list-style: none; 796 | } 797 | .feed__item 798 | { 799 | display: block; 800 | 801 | width: 76%; 802 | min-height: 400px; 803 | margin: 40px auto 0; 804 | } 805 | /* User in Feed */ 806 | .user 807 | { 808 | margin-bottom: 10px; 809 | } 810 | .user__pic 811 | { 812 | float: left; 813 | 814 | width: 100px; 815 | height: 100px; 816 | margin-right: 20px; 817 | } 818 | .user__pic img 819 | { 820 | width: 100px; 821 | 822 | border-radius: 50%; 823 | } 824 | .user__name 825 | { 826 | display: block; 827 | 828 | color: #333; 829 | } 830 | .user__likes 831 | { 832 | display: block; 833 | 834 | height: 80px; 835 | } 836 | .user__like 837 | { 838 | display: inline-block; 839 | 840 | width: 80px; 841 | height: 80px; 842 | 843 | cursor: pointer; 844 | vertical-align: middle; 845 | 846 | background: url('data:image/png;base64,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') no-repeat 0 0; 847 | } 848 | .user__like:hover, 849 | .user__like_liked 850 | { 851 | background-position: 0 -80px; 852 | } 853 | .user__likes-count 854 | { 855 | font-size: 2.5em; 856 | 857 | position: relative; 858 | 859 | display: inline-block; 860 | 861 | vertical-align: middle; 862 | } 863 | .user__video 864 | { 865 | display: block; 866 | 867 | width: 100px; 868 | height: 100px; 869 | 870 | cursor: pointer; 871 | 872 | background: url('../img/user/video-play.png'); 873 | } 874 | /* Photo in Feed */ 875 | .photo 876 | { 877 | overflow: hidden; 878 | } 879 | .photo__pic 880 | { 881 | display: block; 882 | 883 | width: 500px; 884 | max-width: 100%; 885 | margin-left: 100px; 886 | } 887 | /* Comments in Feed */ 888 | .comments 889 | { 890 | overflow: hidden; 891 | 892 | margin: 10px 0 0 100px; 893 | padding: 0; 894 | 895 | list-style: none; 896 | } 897 | .comments__item 898 | { 899 | display: block; 900 | 901 | margin: 0 0 5px 0; 902 | } 903 | .comments__pic 904 | { 905 | float: left; 906 | 907 | width: 20px; 908 | margin-right: 5px; 909 | } 910 | .comments__username 911 | { 912 | font-size: .85em; 913 | font-weight: bold; 914 | 915 | text-decoration: none; 916 | 917 | color: #444; 918 | } 919 | .comments__username:hover 920 | { 921 | border-bottom: 1px dashed #444; 922 | } 923 | .comments__text 924 | { 925 | font-size: .85em; 926 | } 927 | /* Followers and Follows */ 928 | .follow__header 929 | { 930 | font-size: 2em; 931 | font-weight: 700; 932 | 933 | margin: 20px 0; 934 | 935 | text-align: center; 936 | 937 | color: #fff; 938 | text-shadow: 0 1px 1px #333; 939 | } 940 | .follow__list 941 | { 942 | margin: 0; 943 | padding: 0; 944 | 945 | list-style: none; 946 | } 947 | .follow__item 948 | { 949 | float: left; 950 | 951 | width: 100%; 952 | height: 100px; 953 | margin: 0; 954 | 955 | vertical-align: top; 956 | 957 | border-right: 1px solid #17b287; 958 | border-bottom: 1px solid #17b287; 959 | border-left: 1px solid #17b287; 960 | background: #fff; 961 | } 962 | .follow__item:first-child 963 | { 964 | border-top: 1px solid #17b287; 965 | } 966 | .follow__item:nth-child(4n) 967 | { 968 | margin-right: 0; 969 | } 970 | .follow__item a 971 | { 972 | font-size: 1.25em; 973 | font-weight: bold; 974 | 975 | text-align: center; 976 | text-decoration: none; 977 | 978 | color: #333; 979 | } 980 | .follow__avatar 981 | { 982 | display: inline-block; 983 | float: left; 984 | 985 | width: 99px; 986 | margin-right: 10px; 987 | } 988 | .follow__username 989 | { 990 | position: relative; 991 | top: 35px; 992 | 993 | overflow: hidden; 994 | 995 | -webkit-transition: color .5s ease; 996 | -moz-transition: color .5s ease; 997 | transition: color .5s ease; 998 | } 999 | .follow__username:hover 1000 | { 1001 | color: #ff4c4b; 1002 | } 1003 | .follow__btn 1004 | { 1005 | float: right; 1006 | 1007 | margin: 35px 10px 0 0; 1008 | padding: 3px 10px; 1009 | 1010 | color: #fff; 1011 | border: 0; 1012 | background: #ff4c4b; 1013 | -webkit-box-shadow: 2px 2px 2px 1px rgba(0,0,0,.5); 1014 | -moz-box-shadow: 2px 2px 2px 1px rgba(0,0,0,.5); 1015 | box-shadow: 2px 2px 2px 1px rgba(0,0,0,.5); 1016 | } 1017 | .follow__btn_read 1018 | { 1019 | background: #27ae60; 1020 | } 1021 | /* Всплывающие окна */ 1022 | /* Responsive */ 1023 | @media (min-width: 768px) 1024 | { 1025 | [class*='column_sm-'] 1026 | { 1027 | float: left; 1028 | } 1029 | .column_sm-1 1030 | { 1031 | width: 8.333333333333334%; 1032 | } 1033 | .column_sm-2 1034 | { 1035 | width: 16.666666666666668%; 1036 | } 1037 | .column_sm-3 1038 | { 1039 | width: 25%; 1040 | } 1041 | .column_sm-4 1042 | { 1043 | width: 33.333333333333336%; 1044 | } 1045 | .column_sm-5 1046 | { 1047 | width: 41.66666666666667%; 1048 | } 1049 | .column_sm-6 1050 | { 1051 | width: 50%; 1052 | } 1053 | .column_sm-7 1054 | { 1055 | width: 58.333333333333336%; 1056 | } 1057 | .column_sm-8 1058 | { 1059 | width: 66.66666666666667%; 1060 | } 1061 | .column_sm-9 1062 | { 1063 | width: 75%; 1064 | } 1065 | .column_sm-10 1066 | { 1067 | width: 83.33333333333334%; 1068 | } 1069 | .column_sm-11 1070 | { 1071 | width: 91.66666666666667%; 1072 | } 1073 | .column_sm-12 1074 | { 1075 | width: 100%; 1076 | } 1077 | .column__offset_sm-1 1078 | { 1079 | margin-left: 8.333333333333334%; 1080 | } 1081 | .column__offset_sm-2 1082 | { 1083 | margin-left: 16.666666666666668%; 1084 | } 1085 | .column__offset_sm-3 1086 | { 1087 | margin-left: 25%; 1088 | } 1089 | .column__offset_sm-4 1090 | { 1091 | margin-left: 33.333333333333336%; 1092 | } 1093 | .column__offset_sm-5 1094 | { 1095 | margin-left: 41.66666666666667%; 1096 | } 1097 | .column__offset_sm-6 1098 | { 1099 | margin-left: 50%; 1100 | } 1101 | .column__offset_sm-7 1102 | { 1103 | margin-left: 58.333333333333336%; 1104 | } 1105 | .column__offset_sm-8 1106 | { 1107 | margin-left: 66.66666666666667%; 1108 | } 1109 | .column__offset_sm-9 1110 | { 1111 | margin-left: 75%; 1112 | } 1113 | .column__offset_sm-10 1114 | { 1115 | margin-left: 83.33333333333334%; 1116 | } 1117 | .column__offset_sm-11 1118 | { 1119 | margin-left: 91.66666666666667%; 1120 | } 1121 | .column__offset_sm-12 1122 | { 1123 | margin-left: 100%; 1124 | } 1125 | } 1126 | @media (min-width: 992px) 1127 | { 1128 | .page 1129 | { 1130 | width: 940px; 1131 | } 1132 | [class*='column_md-'] 1133 | { 1134 | float: left; 1135 | } 1136 | .column_md-1 1137 | { 1138 | width: 8.333333333333334%; 1139 | } 1140 | .column_md-2 1141 | { 1142 | width: 16.666666666666668%; 1143 | } 1144 | .column_md-3 1145 | { 1146 | width: 25%; 1147 | } 1148 | .column_md-4 1149 | { 1150 | width: 33.333333333333336%; 1151 | } 1152 | .column_md-5 1153 | { 1154 | width: 41.66666666666667%; 1155 | } 1156 | .column_md-6 1157 | { 1158 | width: 50%; 1159 | } 1160 | .column_md-7 1161 | { 1162 | width: 58.333333333333336%; 1163 | } 1164 | .column_md-8 1165 | { 1166 | width: 66.66666666666667%; 1167 | } 1168 | .column_md-9 1169 | { 1170 | width: 75%; 1171 | } 1172 | .column_md-10 1173 | { 1174 | width: 83.33333333333334%; 1175 | } 1176 | .column_md-11 1177 | { 1178 | width: 91.66666666666667%; 1179 | } 1180 | .column_md-12 1181 | { 1182 | width: 100%; 1183 | } 1184 | .column__offset_md-1 1185 | { 1186 | margin-left: 8.333333333333334%; 1187 | } 1188 | .column__offset_md-2 1189 | { 1190 | margin-left: 16.666666666666668%; 1191 | } 1192 | .column__offset_md-3 1193 | { 1194 | margin-left: 25%; 1195 | } 1196 | .column__offset_md-4 1197 | { 1198 | margin-left: 33.333333333333336%; 1199 | } 1200 | .column__offset_md-5 1201 | { 1202 | margin-left: 41.66666666666667%; 1203 | } 1204 | .column__offset_md-6 1205 | { 1206 | margin-left: 50%; 1207 | } 1208 | .column__offset_md-7 1209 | { 1210 | margin-left: 58.333333333333336%; 1211 | } 1212 | .column__offset_md-8 1213 | { 1214 | margin-left: 66.66666666666667%; 1215 | } 1216 | .column__offset_md-9 1217 | { 1218 | margin-left: 75%; 1219 | } 1220 | .column__offset_md-10 1221 | { 1222 | margin-left: 83.33333333333334%; 1223 | } 1224 | .column__offset_md-11 1225 | { 1226 | margin-left: 91.66666666666667%; 1227 | } 1228 | .column__offset_md-12 1229 | { 1230 | margin-left: 100%; 1231 | } 1232 | } 1233 | @media (min-width: 1170px) 1234 | { 1235 | [class*='column_lg-'] 1236 | { 1237 | float: left; 1238 | } 1239 | .column_lg-1 1240 | { 1241 | width: 8.333333333333334%; 1242 | } 1243 | .column_lg-2 1244 | { 1245 | width: 16.666666666666668%; 1246 | } 1247 | .column_lg-3 1248 | { 1249 | width: 25%; 1250 | } 1251 | .column_lg-4 1252 | { 1253 | width: 33.333333333333336%; 1254 | } 1255 | .column_lg-5 1256 | { 1257 | width: 41.66666666666667%; 1258 | } 1259 | .column_lg-6 1260 | { 1261 | width: 50%; 1262 | } 1263 | .column_lg-7 1264 | { 1265 | width: 58.333333333333336%; 1266 | } 1267 | .column_lg-8 1268 | { 1269 | width: 66.66666666666667%; 1270 | } 1271 | .column_lg-9 1272 | { 1273 | width: 75%; 1274 | } 1275 | .column_lg-10 1276 | { 1277 | width: 83.33333333333334%; 1278 | } 1279 | .column_lg-11 1280 | { 1281 | width: 91.66666666666667%; 1282 | } 1283 | .column_lg-12 1284 | { 1285 | width: 100%; 1286 | } 1287 | .column__offset_lg-1 1288 | { 1289 | margin-left: 8.333333333333334%; 1290 | } 1291 | .column__offset_lg-2 1292 | { 1293 | margin-left: 16.666666666666668%; 1294 | } 1295 | .column__offset_lg-3 1296 | { 1297 | margin-left: 25%; 1298 | } 1299 | .column__offset_lg-4 1300 | { 1301 | margin-left: 33.333333333333336%; 1302 | } 1303 | .column__offset_lg-5 1304 | { 1305 | margin-left: 41.66666666666667%; 1306 | } 1307 | .column__offset_lg-6 1308 | { 1309 | margin-left: 50%; 1310 | } 1311 | .column__offset_lg-7 1312 | { 1313 | margin-left: 58.333333333333336%; 1314 | } 1315 | .column__offset_lg-8 1316 | { 1317 | margin-left: 66.66666666666667%; 1318 | } 1319 | .column__offset_lg-9 1320 | { 1321 | margin-left: 75%; 1322 | } 1323 | .column__offset_lg-10 1324 | { 1325 | margin-left: 83.33333333333334%; 1326 | } 1327 | .column__offset_lg-11 1328 | { 1329 | margin-left: 91.66666666666667%; 1330 | } 1331 | .column__offset_lg-12 1332 | { 1333 | margin-left: 100%; 1334 | } 1335 | } 1336 | -------------------------------------------------------------------------------- /assets/css/style.min.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=PT+Sans:400,700&subset=latin,cyrillic);@import url(../fonts/grand.css);html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{font:inherit;margin:0;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{margin:0 2px;padding:.35em .625em .75em;border:1px solid silver}legend{border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}legend,td,th{padding:0}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.g-clf:after,.g-clf:before{display:table;clear:both;content:''}body,html{font:16px 'PT Sans',Verdana,Tahoma;height:100%}body{background:#bdc3c7}body.welcome{background:url(../img/page/blur.jpg) no-repeat 0 0;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-ms-background-size:cover}body .auth{position:absolute;top:50%;left:50%;display:block;width:200px;height:29px;margin-left:-100px;cursor:pointer;text-indent:-9999px;outline:none;background:url(../img/page/auth.png) no-repeat 0 0}body .auth:hover{background:url(../img/page/auth_h.png) no-repeat 0 0}.page{position:relative;min-height:100%;margin:0 auto}.header{position:fixed;z-index:9999;top:0;left:0;width:100%;height:50px;background:#17b287;-webkit-box-shadow:0 1px 1px 2px rgba(0,0,0,.5);-moz-box-shadow:0 1px 1px 2px rgba(0,0,0,.5);box-shadow:0 1px 1px 2px rgba(0,0,0,.5)}.menu{margin:0;padding:14px 0 0;list-style:none;text-align:center}.menu__item{display:inline-block;margin-right:15px;cursor:pointer}.menu__item:last-child{margin-right:0}.menu__link{padding:5px 20px;-webkit-transition:color .5s ease;-moz-transition:color .5s ease;transition:color .5s ease;text-decoration:none;color:#17b287;background:#f9f9f9}.menu__link:hover{color:#ff4c4b}.main{margin:0 auto;padding:50px 10px 115px}.footer{position:absolute;bottom:0;width:100%;height:89px;border-top:1px solid #4f4f50;border-bottom:1px solid #4f4f50;background:#444}.footer__copyright{font:.75em 'Tahoma',Arial,Verdana;float:right;margin:38px 60px 0 0;color:#dddbdb}.form{position:relative;width:605px}.form__field{margin:0;padding:0;border:0}.form__label{display:block;padding:5px 0}.form__label-title{display:inline-block;width:200px;vertical-align:top}.form__input{width:400px}.form__input,.form__select,.form__textarea{font-size:.875em;border:1px solid #a0a0a0;outline:none}.form__textarea{width:400px}.form__input{height:30px;padding:0 5px}.form__input:focus,.form__textarea:focus{-webkit-box-shadow:0 0 2px 2px #ffe500;-moz-box-shadow:0 0 2px 2px #ffe500;box-shadow:0 0 2px 2px #ffe500}.form__select{width:200px}.form__textarea{padding:3px 5px;resize:vertical}.form__answer{display:inline-block;width:400px}.form__radio-wrapper,.grid{display:block}.row{margin-bottom:15px}[class*=column_xs-]{float:left}.column{position:relative;min-height:1px;padding-right:10px;padding-left:10px}.column_xs-1{width:8.333333333333334%}.column_xs-2{width:16.666666666666668%}.column_xs-3{width:25%}.column_xs-4{width:33.333333333333336%}.column_xs-5{width:41.66666666666667%}.column_xs-6{width:50%}.column_xs-7{width:58.333333333333336%}.column_xs-8{width:66.66666666666667%}.column_xs-9{width:75%}.column_xs-10{width:83.33333333333334%}.column_xs-11{width:91.66666666666667%}.column_xs-12{width:100%}.column__offset_xs-1{margin-left:8.333333333333334%}.column__offset_xs-2{margin-left:16.666666666666668%}.column__offset_xs-3{margin-left:25%}.column__offset_xs-4{margin-left:33.333333333333336%}.column__offset_xs-5{margin-left:41.66666666666667%}.column__offset_xs-6{margin-left:50%}.column__offset_xs-7{margin-left:58.333333333333336%}.column__offset_xs-8{margin-left:66.66666666666667%}.column__offset_xs-9{margin-left:75%}.column__offset_xs-10{margin-left:83.33333333333334%}.column__offset_xs-11{margin-left:91.66666666666667%}.column__offset_xs-12{margin-left:100%}.profile{margin:40px 0 0}.profile__photo{display:block;width:150px;height:150px;margin:0 auto}.profile__username{font:700 2em;line-height:20px;margin:10px 0 0;text-align:center;color:#fff;text-shadow:0 1px 2px #333}.profile__info,.profile__stats{margin:20px 0 30px;padding:0;list-style:none;text-align:center}.profile__item,.profile__item a{color:#fff;text-shadow:0 1px 1px #333}.profile__item{font:1.25em;display:inline-block;padding:0 20px;text-align:center}.profile__item a{-webkit-transition:color .5s ease;-moz-transition:color .5s ease;transition:color .5s ease;text-decoration:none}.profile__item a:hover{color:#17b287}.profile__info .profile__item{display:block;text-align:center;color:#333;text-shadow:none}.search{margin:40px 0 0}.search__form{width:100%;height:60px;margin:0 auto 30px}.search__input{font:24px 'Roboto Condensed';display:inline-block;width:100%;height:60px;padding:0 14px;color:#bdbab4;border:0;outline:none}.photo-list{margin:0;padding:0;list-style:none}.photo-list__item{display:inline-block;width:20.5%;margin:0 6% 6% 0;cursor:pointer}.photo-list__item:nth-child(4n){margin-right:0}.photo-list__item img{max-width:100%;-webkit-box-shadow:0 0 2px 3px rgba(0,0,0,.7);-moz-box-shadow:0 0 2px 3px rgba(0,0,0,.7);box-shadow:0 0 2px 3px rgba(0,0,0,.7)}.photo-list__likes{font-size:.7em;float:right;color:#333}.photo-list__likes:hover{text-decoration:underline}.about{padding-top:40px;text-align:center}.about__header{font:700 2em 'Roboto Condensed',Arial,Tahoma;color:#fff;text-shadow:0 1px 1px #333}.about__text{color:#333;text-shadow:0 1px 1px #fff}.about__text a{-webkit-transition:border-color .5s ease;-moz-transition:border-color .5s ease;transition:border-color .5s ease;text-decoration:none;color:#333;border-bottom:1px dashed #27ae60}.about__text a:hover{border-color:#ff4c4b}.social{float:left;margin:32px 0 0 60px;padding:0;list-style:none}.social__item{display:inline-block;float:left;margin-left:15px}.social__item:first-child{margin-left:0}.social__link{font:24px 'Arial',Tahoma,Verdana;-webkit-transition:color .4s ease;-moz-transition:color .4s ease;transition:color .4s ease;text-decoration:none;text-indent:-9999px;color:#dddbdb}.social__link:hover{color:#27ae60}.feed{width:95%;margin:2% auto 0;padding:0;list-style:none}.feed__item{display:block;width:76%;min-height:400px;margin:40px auto 0}.user{margin-bottom:10px}.user__pic{float:left;width:100px;height:100px;margin-right:20px}.user__pic img{width:100px;border-radius:50%}.user__name{display:block;color:#333}.user__likes{display:block;height:80px}.user__like{display:inline-block;width:80px;height:80px;cursor:pointer;vertical-align:middle;background:url(data:image/png;base64,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) no-repeat 0 0}.user__like:hover,.user__like_liked{background-position:0 -80px}.user__likes-count{font-size:2.5em;position:relative;display:inline-block;vertical-align:middle}.user__video{display:block;width:100px;height:100px;cursor:pointer;background:url(../img/user/video-play.png)}.photo{overflow:hidden}.photo__pic{display:block;width:500px;max-width:100%;margin-left:100px}.comments{overflow:hidden;margin:10px 0 0 100px;padding:0;list-style:none}.comments__item{display:block;margin:0 0 5px}.comments__pic{float:left;width:20px;margin-right:5px}.comments__username{font-size:.85em;font-weight:700;text-decoration:none;color:#444}.comments__username:hover{border-bottom:1px dashed #444}.comments__text{font-size:.85em}.follow__header{font-size:2em;font-weight:700;margin:20px 0;text-align:center;color:#fff;text-shadow:0 1px 1px #333}.follow__list{margin:0;padding:0;list-style:none}.follow__item{float:left;width:100%;height:100px;margin:0;vertical-align:top;border-right:1px solid #17b287;border-bottom:1px solid #17b287;border-left:1px solid #17b287;background:#fff}.follow__item:first-child{border-top:1px solid #17b287}.follow__item:nth-child(4n){margin-right:0}.follow__item a{font-size:1.25em;font-weight:700;text-align:center;text-decoration:none;color:#333}.follow__avatar{display:inline-block;float:left;width:99px;margin-right:10px}.follow__username{position:relative;top:35px;overflow:hidden;-webkit-transition:color .5s ease;-moz-transition:color .5s ease;transition:color .5s ease}.follow__username:hover{color:#ff4c4b}.follow__btn{float:right;margin:35px 10px 0 0;padding:3px 10px;color:#fff;border:0;background:#ff4c4b;-webkit-box-shadow:2px 2px 2px 1px rgba(0,0,0,.5);-moz-box-shadow:2px 2px 2px 1px rgba(0,0,0,.5);box-shadow:2px 2px 2px 1px rgba(0,0,0,.5)}.follow__btn_read{background:#27ae60}@media (min-width:768px){[class*=column_sm-]{float:left}.column_sm-1{width:8.333333333333334%}.column_sm-2{width:16.666666666666668%}.column_sm-3{width:25%}.column_sm-4{width:33.333333333333336%}.column_sm-5{width:41.66666666666667%}.column_sm-6{width:50%}.column_sm-7{width:58.333333333333336%}.column_sm-8{width:66.66666666666667%}.column_sm-9{width:75%}.column_sm-10{width:83.33333333333334%}.column_sm-11{width:91.66666666666667%}.column_sm-12{width:100%}.column__offset_sm-1{margin-left:8.333333333333334%}.column__offset_sm-2{margin-left:16.666666666666668%}.column__offset_sm-3{margin-left:25%}.column__offset_sm-4{margin-left:33.333333333333336%}.column__offset_sm-5{margin-left:41.66666666666667%}.column__offset_sm-6{margin-left:50%}.column__offset_sm-7{margin-left:58.333333333333336%}.column__offset_sm-8{margin-left:66.66666666666667%}.column__offset_sm-9{margin-left:75%}.column__offset_sm-10{margin-left:83.33333333333334%}.column__offset_sm-11{margin-left:91.66666666666667%}.column__offset_sm-12{margin-left:100%}}@media (min-width:992px){.page{width:940px}[class*=column_md-]{float:left}.column_md-1{width:8.333333333333334%}.column_md-2{width:16.666666666666668%}.column_md-3{width:25%}.column_md-4{width:33.333333333333336%}.column_md-5{width:41.66666666666667%}.column_md-6{width:50%}.column_md-7{width:58.333333333333336%}.column_md-8{width:66.66666666666667%}.column_md-9{width:75%}.column_md-10{width:83.33333333333334%}.column_md-11{width:91.66666666666667%}.column_md-12{width:100%}.column__offset_md-1{margin-left:8.333333333333334%}.column__offset_md-2{margin-left:16.666666666666668%}.column__offset_md-3{margin-left:25%}.column__offset_md-4{margin-left:33.333333333333336%}.column__offset_md-5{margin-left:41.66666666666667%}.column__offset_md-6{margin-left:50%}.column__offset_md-7{margin-left:58.333333333333336%}.column__offset_md-8{margin-left:66.66666666666667%}.column__offset_md-9{margin-left:75%}.column__offset_md-10{margin-left:83.33333333333334%}.column__offset_md-11{margin-left:91.66666666666667%}.column__offset_md-12{margin-left:100%}}@media (min-width:1170px){[class*=column_lg-]{float:left}.column_lg-1{width:8.333333333333334%}.column_lg-2{width:16.666666666666668%}.column_lg-3{width:25%}.column_lg-4{width:33.333333333333336%}.column_lg-5{width:41.66666666666667%}.column_lg-6{width:50%}.column_lg-7{width:58.333333333333336%}.column_lg-8{width:66.66666666666667%}.column_lg-9{width:75%}.column_lg-10{width:83.33333333333334%}.column_lg-11{width:91.66666666666667%}.column_lg-12{width:100%}.column__offset_lg-1{margin-left:8.333333333333334%}.column__offset_lg-2{margin-left:16.666666666666668%}.column__offset_lg-3{margin-left:25%}.column__offset_lg-4{margin-left:33.333333333333336%}.column__offset_lg-5{margin-left:41.66666666666667%}.column__offset_lg-6{margin-left:50%}.column__offset_lg-7{margin-left:58.333333333333336%}.column__offset_lg-8{margin-left:66.66666666666667%}.column__offset_lg-9{margin-left:75%}.column__offset_lg-10{margin-left:83.33333333333334%}.column__offset_lg-11{margin-left:91.66666666666667%}.column__offset_lg-12{margin-left:100%}} -------------------------------------------------------------------------------- /assets/fonts/fonts/Grands.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/fonts/fonts/Grands.eot -------------------------------------------------------------------------------- /assets/fonts/fonts/Grands.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | This is a custom SVG font generated by IcoMoon. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 38 | 45 | 50 | 62 | 70 | 78 | 84 | 102 | 104 | 110 | 130 | 135 | 140 | 154 | 155 | 163 | 173 | 177 | 181 | 190 | 201 | 207 | 225 | 234 | 275 | 283 | 285 | 295 | 306 | 317 | 324 | 330 | 336 | 339 | 356 | 362 | 371 | 378 | 387 | 393 | 394 | -------------------------------------------------------------------------------- /assets/fonts/fonts/Grands.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/fonts/fonts/Grands.ttf -------------------------------------------------------------------------------- /assets/fonts/fonts/Grands.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/fonts/fonts/Grands.woff -------------------------------------------------------------------------------- /assets/fonts/grand.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Grands'; 3 | src:url('fonts/Grands.eot'); 4 | src:url('fonts/Grands.eot?#iefix') format('embedded-opentype'), 5 | url('fonts/Grands.svg#Grands') format('svg'), 6 | url('fonts/Grands.woff') format('woff'), 7 | url('fonts/Grands.ttf') format('truetype'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | /* Use the following CSS code if you want to use data attributes for inserting your icons */ 13 | [data-icon]:before { 14 | font-family: 'Grands'; 15 | content: attr(data-icon); 16 | speak: none; 17 | font-weight: normal; 18 | -webkit-font-smoothing: antialiased; 19 | } 20 | 21 | /* Use the following CSS code if you want to have a class per icon */ 22 | [class^="icon-"]:before, [class*=" icon-"]:before { 23 | font-family: 'Grands'; 24 | font-style: normal; 25 | speak: none; 26 | font-weight: normal; 27 | -webkit-font-smoothing: antialiased; 28 | } 29 | .icon-YouTube:before { 30 | content: "\e000"; 31 | } 32 | .icon-Yandex:before { 33 | content: "\e001"; 34 | } 35 | .icon-Vkontakte:before { 36 | content: "\e002"; 37 | } 38 | .icon-VK:before { 39 | content: "\e003"; 40 | } 41 | .icon-vimeo:before { 42 | content: "\e004"; 43 | } 44 | .icon-twitter:before { 45 | content: "\e005"; 46 | } 47 | .icon-tumblr:before { 48 | content: "\e006"; 49 | } 50 | .icon-Steam:before { 51 | content: "\e007"; 52 | } 53 | .icon-StackOverflow:before { 54 | content: "\e008"; 55 | } 56 | .icon-SoundCloud:before { 57 | content: "\e009"; 58 | } 59 | .icon-Skype:before { 60 | content: "\e00a"; 61 | } 62 | .icon-Share:before { 63 | content: "\e00b"; 64 | } 65 | .icon-RSS:before { 66 | content: "\e00c"; 67 | } 68 | .icon-Readability:before { 69 | content: "\e00d"; 70 | } 71 | .icon-Read-it-Later:before { 72 | content: "\e00e"; 73 | } 74 | .icon-Pocket:before { 75 | content: "\e00f"; 76 | } 77 | .icon-Pinterest:before { 78 | content: "\e010"; 79 | } 80 | .icon-Picasa:before { 81 | content: "\e011"; 82 | } 83 | .icon-OpenID:before { 84 | content: "\e012"; 85 | } 86 | .icon-MySpace:before { 87 | content: "\e013"; 88 | } 89 | .icon-MoiKrug:before { 90 | content: "\e014"; 91 | } 92 | .icon-Linked-in:before { 93 | content: "\e015"; 94 | } 95 | .icon-LifeJournal:before { 96 | content: "\e016"; 97 | } 98 | .icon-lastfm:before { 99 | content: "\e017"; 100 | } 101 | .icon-Jabber:before { 102 | content: "\e018"; 103 | } 104 | .icon-Instapaper:before { 105 | content: "\e019"; 106 | } 107 | .icon-HabraHabr:before { 108 | content: "\e01a"; 109 | } 110 | .icon-google:before { 111 | content: "\e01b"; 112 | } 113 | .icon-GitHub-octoface:before { 114 | content: "\e01c"; 115 | } 116 | .icon-GitHub-circle:before { 117 | content: "\e01d"; 118 | } 119 | .icon-FourSquare:before { 120 | content: "\e01e"; 121 | } 122 | .icon-flickr:before { 123 | content: "\e01f"; 124 | } 125 | .icon-Flattr:before { 126 | content: "\e020"; 127 | } 128 | .icon-facebook:before { 129 | content: "\e021"; 130 | } 131 | .icon-Evernote:before { 132 | content: "\e022"; 133 | } 134 | .icon-Email:before { 135 | content: "\e023"; 136 | } 137 | .icon-DropBox:before { 138 | content: "\e024"; 139 | } 140 | .icon-Blogspot:before { 141 | content: "\e025"; 142 | } 143 | .icon-BitBucket:before { 144 | content: "\e026"; 145 | } 146 | .icon-YouTube-play:before { 147 | content: "\e027"; 148 | } 149 | -------------------------------------------------------------------------------- /assets/img/page/auth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/img/page/auth.png -------------------------------------------------------------------------------- /assets/img/page/auth_h.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/img/page/auth_h.png -------------------------------------------------------------------------------- /assets/img/page/blur.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/img/page/blur.jpg -------------------------------------------------------------------------------- /assets/img/user/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/img/user/heart.png -------------------------------------------------------------------------------- /assets/img/user/video-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/assets/img/user/video-play.png -------------------------------------------------------------------------------- /auth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Auth Instagram 6 | 7 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var stylus = require('gulp-stylus'); 3 | var uglify = require('gulp-uglify'); 4 | var csscomb = require('gulp-csscomb'); 5 | var cssmin = require('gulp-csso'); 6 | var rename = require('gulp-rename'); 7 | var webpack = require('gulp-webpack'); 8 | var browserSync = require('browser-sync').create(); 9 | 10 | var paths = { 11 | scripts: 'src/js/*.js', 12 | jsx: 'src/app/**/*.jsx', 13 | styles: 'src/stylus/**.styl' 14 | }; 15 | 16 | gulp.task('uglify', function () { 17 | return gulp.src(paths.scripts) 18 | .pipe(uglify({mangle: true, compress: true})) 19 | .pipe(rename({suffix: '.min'})) 20 | .pipe(gulp.dest('./assets/js')) 21 | .pipe(browserSync.stream()); 22 | }); 23 | 24 | gulp.task('react', function() { 25 | return gulp.src('src/app/Root.jsx') 26 | .pipe(webpack(require('./webpack.config.js'))) 27 | .pipe(gulp.dest('./')); 28 | }); 29 | 30 | gulp.task('browser-sync', function() { 31 | browserSync.init({ 32 | server: { 33 | baseDir: "./" 34 | } 35 | }); 36 | }); 37 | 38 | gulp.task('stylus', function () { 39 | return gulp.src('src/stylus/style.styl') 40 | .pipe(stylus()) 41 | .pipe(csscomb()) 42 | .pipe(gulp.dest('./assets/css')) 43 | .pipe(cssmin()) 44 | .pipe(rename({ 45 | basename: 'style', 46 | suffix: '.min', 47 | ext: '.css' 48 | })) 49 | .pipe(gulp.dest('./assets/css')) 50 | .pipe(browserSync.stream()); 51 | }); 52 | 53 | gulp.task('watch', function() { 54 | gulp.watch('./*.html').on('change', browserSync.reload); 55 | gulp.watch(paths.jsx, ['react']); 56 | gulp.watch(paths.scripts, ['uglify']); 57 | gulp.watch(paths.styles, ['stylus']); 58 | }); 59 | 60 | gulp.task('default', ['browser-sync', 'react', 'uglify', 'stylus', 'watch']); 61 | -------------------------------------------------------------------------------- /icon-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isnifer/react-redux-instagram-example/aa41f2eec42ce05250e7659e60b0b65e8609a473/icon-app.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactInstagramApp", 3 | "version": "2.0.0", 4 | "main": "bundle.js", 5 | "author": "Anton Kuznetsov (https://github.com/isnifer)", 6 | "description": "React Redux Instagram App", 7 | "homepage": "http://isnifer.me", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:isnifer/InstaAngular.git" 12 | }, 13 | "scripts": { 14 | "dev": "./node_modules/.bin/gulp" 15 | }, 16 | "devDependencies": { 17 | "babel-loader": "^6.2.4", 18 | "browser-sync": "^2.12.3", 19 | "css-loader": "^0.23.1", 20 | "gulp": "^3.9.1", 21 | "gulp-csscomb": "^3.0.7", 22 | "gulp-csso": "^2.0.0", 23 | "gulp-rename": "^1.2.2", 24 | "gulp-stylus": "^2.3.1", 25 | "gulp-uglify": "^1.5.3", 26 | "gulp-webpack": "^1.5.0", 27 | "style-loader": "^0.13.1", 28 | "stylus-loader": "^2.0.0", 29 | "webpack": "^1.12.15" 30 | }, 31 | "dependencies": { 32 | "babel-preset-es2015": "^6.6.0", 33 | "babel-preset-react": "^6.5.0", 34 | "babel-preset-stage-0": "^6.5.0", 35 | "history": "^2.0.1", 36 | "react": "^15.0.1", 37 | "react-dom": "^15.0.1", 38 | "react-redux": "^4.4.5", 39 | "react-router": "^2.2.2", 40 | "redux": "^3.4.0", 41 | "redux-logger": "^2.6.1", 42 | "redux-thunk": "^2.0.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Instagram App 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/app/Root.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Router, Route, IndexRoute, Link, useRouterHistory } from 'react-router'; 4 | import { createHashHistory } from 'history' 5 | import { Provider } from 'react-redux'; 6 | import store from './store'; 7 | 8 | // Pages 9 | import App from './handlers/App'; 10 | import Timeline from './handlers/Timeline'; 11 | import SearchPhotos from './handlers/SearchPhotos'; 12 | import SearchUsers from './handlers/SearchUsers'; 13 | import Profile from './handlers/Profile'; 14 | import Followers from './handlers/Followers'; 15 | import PageNotFound from './handlers/PageNotFound'; 16 | 17 | const appHistory = useRouterHistory(createHashHistory)({queryKey: false}); 18 | render(( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ), document.querySelector('.page')); 34 | -------------------------------------------------------------------------------- /src/app/actions/followers.js: -------------------------------------------------------------------------------- 1 | import { getFollowers } from '../api'; 2 | import { 3 | GET_FOLLOWERS_REQUEST, 4 | GET_FOLLOWERS_RESPONSE, 5 | UPDATE_FOLLOWERS_REQUEST, 6 | UPDATE_FOLLOWERS_RESPONSE 7 | } from '../constants'; 8 | 9 | const token = localStorage.accessToken; 10 | 11 | export const getFollowersAction = ({url, userId, type}) => (dispatch, getState) => { 12 | dispatch({ 13 | type: GET_FOLLOWERS_REQUEST, 14 | payload: { 15 | followers: [], 16 | followersPagination: {} 17 | } 18 | }); 19 | 20 | getFollowers({url, userId, type, token}).then(payload => { 21 | dispatch({ 22 | type: GET_FOLLOWERS_RESPONSE, 23 | payload 24 | }) 25 | }); 26 | }; 27 | 28 | export const updateFollowersAction = ({url, userId, type}) => (dispatch, getState) => { 29 | dispatch({ 30 | type: UPDATE_FOLLOWERS_REQUEST 31 | }); 32 | 33 | getFollowers({url, userId, type, token}).then(payload => { 34 | dispatch({ 35 | type: UPDATE_FOLLOWERS_RESPONSE, 36 | payload 37 | }) 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /src/app/actions/index.js: -------------------------------------------------------------------------------- 1 | export { getTimelineAction, updateTimelineAction } from './timeline'; 2 | export { getProfileDataAction, getProfilePhotosAction, updateProfilePhotosAction } from './profile'; 3 | export { searchByUserAction } from './searchByUser'; 4 | export { searchByTagAction, getPopularAction } from './searchByTag'; 5 | export { getFollowersAction, updateFollowersAction } from './followers'; 6 | -------------------------------------------------------------------------------- /src/app/actions/profile.js: -------------------------------------------------------------------------------- 1 | import { getProfileData, getProfilePhotos } from '../api'; 2 | import { 3 | GET_PROFILE_REQUEST, 4 | GET_PROFILE_RESPONSE, 5 | UPDATE_PROFILE_PHOTOS_REQUEST, 6 | UPDATE_PROFILE_PHOTOS_RESPONSE, 7 | GET_PROFILE_PHOTOS_REQUEST, 8 | GET_PROFILE_PHOTOS_RESPONSE 9 | } from '../constants'; 10 | 11 | const token = localStorage.accessToken; 12 | 13 | export const getProfileDataAction = ({url, userId}) => (dispatch, getState) => { 14 | dispatch({ 15 | type: GET_PROFILE_REQUEST, 16 | payload: { 17 | profileLoaded: false, 18 | profileError: null 19 | } 20 | }); 21 | 22 | getProfileData({userId, token}).then(payload => { 23 | payload.profileLoaded = true; 24 | 25 | dispatch({ 26 | type: GET_PROFILE_RESPONSE, 27 | payload 28 | }); 29 | }); 30 | } 31 | 32 | export const getProfilePhotosAction = ({url, userId}) => (dispatch, getState) => { 33 | dispatch({ 34 | type: GET_PROFILE_PHOTOS_REQUEST, 35 | profileError: null 36 | }); 37 | 38 | getProfilePhotos({url, userId, token}).then(payload => { 39 | dispatch({ 40 | type: GET_PROFILE_PHOTOS_RESPONSE, 41 | payload 42 | }); 43 | }); 44 | } 45 | 46 | export const updateProfilePhotosAction = ({url, userId}) => (dispatch, getState) => { 47 | dispatch({ 48 | type: UPDATE_PROFILE_PHOTOS_REQUEST 49 | }); 50 | 51 | getProfilePhotos({url, userId, token}).then(payload => { 52 | dispatch({ 53 | type: UPDATE_PROFILE_PHOTOS_RESPONSE, 54 | payload 55 | }); 56 | }); 57 | } 58 | -------------------------------------------------------------------------------- /src/app/actions/searchByTag.js: -------------------------------------------------------------------------------- 1 | import { searchByTag, getPopular } from '../api'; 2 | import { 3 | SEARCH_BY_TAG_REQUEST, 4 | SEARCH_BY_TAG_RESPONSE, 5 | GET_POPULAR_REQUEST, 6 | GET_POPULAR_RESPONSE 7 | } from '../constants'; 8 | 9 | const token = localStorage.accessToken; 10 | 11 | export const searchByTagAction = (tag) => (dispatch, getState) => { 12 | 13 | tag = tag.replace(/\s/, ''); 14 | 15 | dispatch({ 16 | type: SEARCH_BY_TAG_REQUEST 17 | }); 18 | 19 | searchByTag({tag, token}).then(payload => { 20 | dispatch({ 21 | type: SEARCH_BY_TAG_RESPONSE, 22 | payload 23 | }); 24 | }); 25 | }; 26 | 27 | export const getPopularAction = () => (dispatch, getState) => { 28 | 29 | dispatch({ 30 | type: GET_POPULAR_REQUEST 31 | }); 32 | 33 | getPopular({token}).then(payload => { 34 | dispatch({ 35 | type: GET_POPULAR_RESPONSE, 36 | payload 37 | }) 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /src/app/actions/searchByUser.js: -------------------------------------------------------------------------------- 1 | import { searchByUser } from '../api'; 2 | import { 3 | SEARCH_BY_USER_REQUEST, 4 | SEARCH_BY_USER_RESPONSE 5 | } from '../constants'; 6 | 7 | const token = localStorage.accessToken; 8 | 9 | export const searchByUserAction = (username) => (dispatch, getState) => { 10 | 11 | username = username.replace(/\s/, ''); 12 | 13 | dispatch({ 14 | type: SEARCH_BY_USER_REQUEST 15 | }); 16 | 17 | searchByUser({username, token}).then(payload => { 18 | dispatch({ 19 | type: SEARCH_BY_USER_RESPONSE, 20 | payload 21 | }) 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /src/app/actions/timeline.js: -------------------------------------------------------------------------------- 1 | import { getTimeline } from '../api'; 2 | import { 3 | GET_TIMELINE_REQUEST, 4 | GET_TIMELINE_RESPONSE, 5 | UPDATE_TIMELINE_RESPONSE 6 | } from '../constants'; 7 | 8 | const token = localStorage.accessToken; 9 | const userId = localStorage.userId; 10 | 11 | export const getTimelineAction = ({url}) => (dispatch, getState) => { 12 | 13 | dispatch({ 14 | type: GET_TIMELINE_REQUEST, 15 | payload: { 16 | timelineLoaded: false 17 | } 18 | }); 19 | 20 | getTimeline({url, token}).then(payload => { 21 | dispatch({ 22 | type: GET_TIMELINE_RESPONSE, 23 | payload: { 24 | timelineItems: payload.data, 25 | pagination: payload.pagination, 26 | timelineLoaded: true 27 | } 28 | }) 29 | }); 30 | } 31 | 32 | export const updateTimelineAction = ({url}) => (dispatch, getState) => { 33 | 34 | getTimeline({url, token}).then(payload => { 35 | dispatch({ 36 | type: UPDATE_TIMELINE_RESPONSE, 37 | payload: { 38 | timelineItems: payload.data, 39 | pagination: payload.pagination 40 | } 41 | }) 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /src/app/api/index.js: -------------------------------------------------------------------------------- 1 | const dataType = 'jsonp'; 2 | 3 | export const getFollowers = ({url, userId, type, token}) => { 4 | const defaultUrl = `https://api.instagram.com/v1/users/${userId}/${type}?access_token=${token}`; 5 | return $.ajax({url: url || defaultUrl, dataType}).then(payload => { 6 | return { 7 | followers: payload.data, 8 | followersPagination: payload.pagination 9 | } 10 | }); 11 | }; 12 | 13 | export const getRelationshipStatus = ({follower, callback, id, token}) => { 14 | const url = `https://api.instagram.com/v1/users/${id}/relationship?access_token=${token}`; 15 | return $.ajax({url, dataType}).then(payload => { 16 | return { 17 | outgoingStatus: data.data.outgoing_status 18 | } 19 | }); 20 | } 21 | 22 | export const getProfileData = ({userId, token}) => { 23 | const url = `https://api.instagram.com/v1/users/${userId}?access_token=${token}`; 24 | return $.ajax({url, dataType}).then(payload => { 25 | if (payload.meta.code !== 200) { 26 | return { 27 | profile: {}, 28 | counts: {}, 29 | profileError: payload.meta.error_message 30 | } 31 | } 32 | 33 | return { 34 | profile: payload.data, 35 | counts: payload.data.counts, 36 | profileError: null 37 | }; 38 | }); 39 | }; 40 | 41 | export const getProfilePhotos = ({url, userId, token}) => { 42 | const defaultUrl = `https://api.instagram.com/v1/users/${userId}/media/recent?access_token=${token}`; 43 | 44 | return $.ajax({url: url || defaultUrl, dataType}).then(payload => { 45 | if (payload.meta.code !== 200) { 46 | return { 47 | profilePhotos: [], 48 | profilePagination: {}, 49 | profileError: payload.meta.error_message 50 | } 51 | } 52 | 53 | return { 54 | profilePhotos: payload.data, 55 | profilePagination: payload.pagination, 56 | profileError: null 57 | } 58 | }); 59 | }; 60 | 61 | export const searchByTag = ({tag, token}) => { 62 | const url = `https://api.instagram.com/v1/tags/${tag}/media/recent?&access_token=${token}`; 63 | 64 | return $.ajax({url: url, dataType}).then(payload => { 65 | if (payload.meta.code !== 200) { 66 | return { 67 | deniedTag: true 68 | } 69 | } 70 | 71 | return { 72 | foundedPhotos: payload.data, 73 | searchPagination: payload.pagination, 74 | deniedTag: false 75 | } 76 | }); 77 | } 78 | 79 | export const getPopular = ({token}) => { 80 | const url = `https://api.instagram.com/v1/media/popular/?access_token=${token}`; 81 | return $.ajax({url, dataType}).then(payload => { 82 | return { 83 | foundedPhotos: payload.data 84 | }; 85 | }); 86 | } 87 | 88 | export const searchByUser = ({username, token}) => { 89 | const url = `https://api.instagram.com/v1/users/search?q=${username}&access_token=${token}`; 90 | 91 | return $.ajax({url: url, dataType}).then(payload => { 92 | return { 93 | foundedUsers: payload.data 94 | } 95 | }); 96 | } 97 | 98 | export const getTimeline = ({url, token}) => { 99 | const timelineUrl = `https://api.instagram.com/v1/users/self/feed?access_token=${token}`; 100 | return $.ajax({url: url || timelineUrl, dataType}); 101 | } 102 | -------------------------------------------------------------------------------- /src/app/constants/index.js: -------------------------------------------------------------------------------- 1 | export const GET_FOLLOWERS_REQUEST = 'GET_FOLLOWERS_REQUEST'; 2 | export const GET_FOLLOWERS_RESPONSE = 'GET_FOLLOWERS_RESPONSE'; 3 | export const UPDATE_FOLLOWERS_REQUEST = 'UPDATE_FOLLOWERS_REQUEST'; 4 | export const UPDATE_FOLLOWERS_RESPONSE = 'UPDATE_FOLLOWERS_RESPONSE'; 5 | 6 | export const GET_PROFILE_REQUEST = 'GET_PROFILE_REQUEST'; 7 | export const GET_PROFILE_RESPONSE = 'GET_PROFILE_RESPONSE'; 8 | export const UPDATE_PROFILE_PHOTOS_REQUEST = 'UPDATE_PROFILE_PHOTOS_REQUEST'; 9 | export const UPDATE_PROFILE_PHOTOS_RESPONSE = 'UPDATE_PROFILE_PHOTOS_RESPONSE'; 10 | 11 | export const GET_PROFILE_PHOTOS_REQUEST = 'GET_PROFILE_PHOTOS_REQUEST'; 12 | export const GET_PROFILE_PHOTOS_RESPONSE = 'GET_PROFILE_PHOTOS_RESPONSE'; 13 | 14 | export const SEARCH_BY_TAG_REQUEST = 'SEARCH_BY_TAG_REQUEST'; 15 | export const SEARCH_BY_TAG_RESPONSE = 'SEARCH_BY_TAG_RESPONSE'; 16 | 17 | export const GET_POPULAR_REQUEST = 'GET_POPULAR_REQUEST'; 18 | export const GET_POPULAR_RESPONSE = 'GET_POPULAR_RESPONSE'; 19 | 20 | export const SEARCH_BY_USER_REQUEST = 'SEARCH_BY_USER_REQUEST'; 21 | export const SEARCH_BY_USER_RESPONSE = 'SEARCH_BY_USER_RESPONSE'; 22 | 23 | export const GET_TIMELINE_REQUEST = 'GET_TIMELINE_REQUEST'; 24 | export const GET_TIMELINE_RESPONSE = 'GET_TIMELINE_RESPONSE'; 25 | export const UPDATE_TIMELINE_RESPONSE = 'UPDATE_TIMELINE_RESPONSE'; 26 | -------------------------------------------------------------------------------- /src/app/handlers/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | 4 | const userId = localStorage.userId; 5 | 6 | const App = ({routes, children}) => { 7 | const links = routes[0].childRoutes.slice(0, 4).map((link, i) => { 8 | return ( 9 |
  • 10 | 13 | {link.name} 14 | 15 |
  • 16 | ); 17 | }); 18 | 19 | return ( 20 |
    21 |
    22 |
      23 | {links} 24 |
    25 |
    26 |
    27 | {children} 28 |
    29 |
    30 |
      31 |
    • 32 | 33 |
    • 34 |
    • 35 | 36 |
    • 37 |
    • 38 | 39 |
    • 40 |
    • 41 | 42 |
    • 43 |
    44 |
    45 | © Anton Kuznetsov 46 | 47 | . Instagram App. All rights on left! 48 | 49 |
    50 |
    51 |
    52 | ); 53 | } 54 | 55 | export default App; 56 | -------------------------------------------------------------------------------- /src/app/handlers/Followers.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { Link } from 'react-router'; 3 | import { connect } from 'react-redux'; 4 | import { loadOnScrollBottom } from '../../helpers'; 5 | 6 | // Actions 7 | import { getFollowersAction, updateFollowersAction } from '../actions'; 8 | 9 | class Followers extends Component { 10 | componentDidMount () { 11 | const userId = this.props.params.id; 12 | const type = this.props.route.name; 13 | 14 | this.props.getFollowersAction({userId, type}); 15 | } 16 | 17 | render () { 18 | const followers = this.props.model.followers.map((follower, i) => { 19 | return ( 20 |
    21 | 22 | 23 | @{follower.username} 24 | 25 |
    26 | ); 27 | }); 28 | 29 | return ( 30 |
    31 |
    32 | {this.props.route.name === 'follows' && 'I Follow' || 'My Followers'} 33 |
    34 |
    35 | {followers} 36 |
    37 |
    38 | ); 39 | } 40 | } 41 | 42 | Followers.propTypes = { 43 | model: PropTypes.object.isRequired, 44 | }; 45 | 46 | export default connect(state => ({ 47 | model: { 48 | followers: state.followers, 49 | pagination: state.followersPagination 50 | } 51 | }), {getFollowersAction, updateFollowersAction})(Followers); 52 | -------------------------------------------------------------------------------- /src/app/handlers/PageNotFound.jsx: -------------------------------------------------------------------------------- 1 | export const PageNotFound = () => { 2 | return ( 3 |
    Page not found
    4 | ); 5 | } 6 | -------------------------------------------------------------------------------- /src/app/handlers/Profile.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { Link } from 'react-router'; 3 | import { connect } from 'react-redux'; 4 | import { loadOnScrollBottom } from '../../helpers'; 5 | 6 | // Actions 7 | import { getProfileDataAction, getProfilePhotosAction, updateProfilePhotosAction } from '../actions'; 8 | 9 | class Profile extends Component { 10 | 11 | static propTypes = { 12 | model: PropTypes.object.isRequired, 13 | dispatch: PropTypes.func.isRequired 14 | } 15 | 16 | componentDidMount () { 17 | const { dispatch } = this.props; 18 | const userId = this.props.params.id; 19 | 20 | dispatch(getProfileDataAction({userId})); 21 | dispatch(getProfilePhotosAction({userId})); 22 | 23 | loadOnScrollBottom({ 24 | dispatch, 25 | action: updateProfilePhotosAction, 26 | that: this, 27 | userId 28 | }); 29 | } 30 | 31 | componentWillUnmount () { 32 | console.log('PROFILE UNDMOUNTED'); 33 | $(window).off('scroll'); 34 | } 35 | 36 | render () { 37 | 38 | const { profile, counts, photos, pagination, error } = this.props.model; 39 | 40 | if (error) { 41 | return ( 42 |
    43 | {error} 44 |
    45 | ); 46 | } 47 | 48 | const photoList = photos.map((photo, i) => { 49 | return ( 50 |
    51 | 52 | 55 | 56 | Likes: {photo.likes.count} 57 |
    58 | ); 59 | }); 60 | 61 | return ( 62 |
    63 |
    64 |
    65 | {profile.username} 69 |
    70 |
    71 | {profile.username} 72 |
    73 |
      74 |
    • 75 | Photos
      76 | {counts.media} 77 |
    • 78 |
    • 79 | 80 | Followers
      81 | {counts.followed_by} 82 | 83 |
    • 84 |
    • 85 | 86 | Follow
      87 | {counts.follows} 88 | 89 |
    • 90 |
    91 | 100 |
    101 |
    102 | {photoList} 103 |
    104 |
    105 | ); 106 | } 107 | } 108 | 109 | export default connect(state => ({ 110 | model: { 111 | profile: state.profile, 112 | counts: state.counts, 113 | photos: state.profilePhotos, 114 | pagination: state.profilePagination, 115 | error: state.profileError 116 | } 117 | }))(Profile); 118 | -------------------------------------------------------------------------------- /src/app/handlers/SearchPhotos.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | // Actions 5 | import { searchByTagAction, getPopularAction } from '../actions'; 6 | 7 | class SearchPhotos extends Component { 8 | 9 | static propTypes = { 10 | model: PropTypes.object.isRequired, 11 | dispatch: PropTypes.func.isRequired 12 | } 13 | 14 | search (event) { 15 | event.preventDefault(); 16 | 17 | const { dispatch } = this.props; 18 | dispatch(searchByTagAction(this.refs.searchInput.value)); 19 | } 20 | 21 | deniedTag () { 22 | this.refs.searchInput.style.border = '2px solid #f00'; 23 | setTimeout(() => { 24 | this.refs.searchInput.style.border = 'none'; 25 | }, 2000); 26 | } 27 | 28 | componentDidMount () { 29 | this.props.dispatch(getPopularAction()); 30 | } 31 | 32 | render () { 33 | 34 | const { foundedPhotos, deniedTag } = this.props.model; 35 | 36 | let searchResultItems = foundedPhotos.map((photo, i) => { 37 | return ( 38 | 43 | 44 | 45 | ) 46 | }); 47 | 48 | if (deniedTag) { 49 | this.deniedTag(); 50 | 51 | searchResultItems = ( 52 |
    53 | Don't try to search {this.refs.searchInput.value} anymore.
    54 | This tag is disabled by instagram. 55 |
    56 | ); 57 | } 58 | 59 | return ( 60 |
    61 |
    62 | 68 |
    69 |
    70 | {searchResultItems} 71 |
    72 |
    73 | ); 74 | } 75 | } 76 | 77 | export default connect(state => ({ 78 | model: { 79 | foundedPhotos: state.foundedPhotos, 80 | pagination: state.searchPagination, 81 | deniedTag: state.deniedTag 82 | } 83 | }))(SearchPhotos); 84 | 85 | -------------------------------------------------------------------------------- /src/app/handlers/SearchUsers.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { Link } from 'react-router'; 3 | import { connect } from 'react-redux'; 4 | 5 | // Actions 6 | import { searchByUserAction } from '../actions'; 7 | 8 | class SearchUsers extends Component { 9 | 10 | static propTypes = { 11 | model: PropTypes.object.isRequired, 12 | dispatch: PropTypes.func.isRequired 13 | } 14 | 15 | search (event) { 16 | event.preventDefault(); 17 | 18 | const { dispatch } = this.props; 19 | dispatch(searchByUserAction(this.refs.searchInput.value)); 20 | } 21 | 22 | render () { 23 | const searchResultItems = this.props.model.users.map((photo, i) => { 24 | return ( 25 | 30 | 31 | 32 | ) 33 | }); 34 | 35 | return ( 36 |
    37 |
    38 | 44 |
    45 |
    46 | {searchResultItems} 47 |
    48 |
    49 | ); 50 | } 51 | } 52 | 53 | export default connect(state => ({ 54 | model: { 55 | users: state.foundedUsers 56 | } 57 | }))(SearchUsers); 58 | -------------------------------------------------------------------------------- /src/app/handlers/Timeline.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { loadOnScrollBottom } from '../../helpers'; 4 | 5 | // Actions 6 | import { getTimelineAction, updateTimelineAction } from '../actions'; 7 | 8 | const token = localStorage.accessToken; 9 | const userId = localStorage.userId; 10 | 11 | const CommentsItem = ({src, author, text}) => { 12 | return ( 13 |
  • 14 | 15 | {author}:  16 | {text} 17 |
  • 18 | ); 19 | } 20 | 21 | const TimelineUser = ({userId, avatar, username, likes, liked}) => { 22 | return ( 23 |
    24 | 25 | 26 | 27 | {username} 28 | 29 |
    30 | ); 31 | } 32 | 33 | const LikeHeart = ({liked, likes}) => { 34 | return ( 35 | 36 | 37 | {likes} 38 | 39 | ); 40 | } 41 | 42 | const TimelinePhoto = ({id, src}) => { 43 | return ( 44 | 48 | ); 49 | } 50 | 51 | const TimelineVideo = ({id, src}) => { 52 | return ( 53 | 56 | ); 57 | } 58 | 59 | const TimelineItem = ({element, id, type, user}) => { 60 | const timelineElement = type === 'video' ? 61 | () : 64 | (); 67 | 68 | const comments = element.comments.data.map((comment, i) => { 69 | return ( 70 | 76 | ); 77 | }); 78 | 79 | return ( 80 |
  • 81 | 88 |
    89 | {timelineElement} 90 |
      91 | {comments} 92 |
    93 |
    94 |
  • 95 | ); 96 | } 97 | 98 | class Timeline extends Component { 99 | 100 | static propTypes = { 101 | model: PropTypes.object.isRequired, 102 | dispatch: PropTypes.func.isRequired 103 | } 104 | 105 | componentDidMount () { 106 | const { dispatch } = this.props; 107 | 108 | // Init 109 | dispatch(getTimelineAction({})); 110 | 111 | loadOnScrollBottom({ 112 | dispatch, 113 | action: updateTimelineAction, 114 | that: this 115 | }); 116 | } 117 | 118 | componentWillUnmount () { 119 | $(window).off('scroll'); 120 | } 121 | 122 | render () { 123 | const items = this.props.model.timelineItems.map((picture, i) => { 124 | return ( 125 | 131 | ); 132 | }); 133 | 134 | return ( 135 |
    136 |
      137 | {items} 138 |
    139 |
    140 | ); 141 | } 142 | } 143 | 144 | export default connect(state => ({ 145 | model: { 146 | timelineItems: state.timelineItems, 147 | pagination: state.timelinePagination, 148 | timelineLoaded: state.timelineLoaded 149 | } 150 | }))(Timeline); 151 | -------------------------------------------------------------------------------- /src/app/reducers/followers.js: -------------------------------------------------------------------------------- 1 | import { 2 | GET_FOLLOWERS_REQUEST, 3 | GET_FOLLOWERS_RESPONSE, 4 | UPDATE_FOLLOWERS_RESPONSE 5 | } from '../constants'; 6 | 7 | export const followers = (state = [], action) => { 8 | switch (action.type) { 9 | case GET_FOLLOWERS_REQUEST: 10 | case GET_FOLLOWERS_RESPONSE: 11 | return action.payload.followers; 12 | case UPDATE_FOLLOWERS_RESPONSE: 13 | return action.payload.followers.concat(action.payload.followers); 14 | default: 15 | return state; 16 | } 17 | }; 18 | 19 | 20 | export const followersPagination = (state = {}, action) => { 21 | switch (action.type) { 22 | case GET_FOLLOWERS_REQUEST: 23 | case GET_FOLLOWERS_RESPONSE: 24 | case UPDATE_FOLLOWERS_RESPONSE: 25 | return action.payload.followersPagination; 26 | default: 27 | return state; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /src/app/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { timelineItems, timelinePagination, timelineLoaded } from './timeline'; 3 | import { 4 | profile, 5 | counts, 6 | profileLoaded, 7 | profilePhotos, 8 | profilePagination, 9 | profileError 10 | } from './profile'; 11 | import { foundedUsers } from './searchByUser'; 12 | import { 13 | foundedPhotos, 14 | searchPagination, 15 | deniedTag, 16 | popularPhotos, 17 | popularPagination 18 | } from './searchByTag'; 19 | import { followers, followersPagination } from './followers'; 20 | 21 | const rootReducer = combineReducers({ 22 | 23 | // Timeline 24 | timelineItems, 25 | timelinePagination, 26 | timelineLoaded, 27 | 28 | // Profile 29 | profile, 30 | counts, 31 | profileLoaded, 32 | profilePhotos, 33 | profilePagination, 34 | profileError, 35 | 36 | // Search by user 37 | foundedUsers, 38 | 39 | // Search by tag, 40 | foundedPhotos, 41 | searchPagination, 42 | deniedTag, 43 | 44 | // Popular 45 | popularPhotos, 46 | 47 | // Followers 48 | followers, 49 | followersPagination 50 | }); 51 | 52 | export default rootReducer; 53 | -------------------------------------------------------------------------------- /src/app/reducers/profile.js: -------------------------------------------------------------------------------- 1 | import { 2 | GET_PROFILE_REQUEST, 3 | GET_PROFILE_RESPONSE, 4 | UPDATE_PROFILE_PHOTOS_RESPONSE, 5 | GET_PROFILE_PHOTOS_REQUEST, 6 | GET_PROFILE_PHOTOS_RESPONSE 7 | } from '../constants'; 8 | 9 | const initialState = { 10 | profile: {}, 11 | counts: {}, 12 | profileLoaded: false, 13 | profilePhotos: [], 14 | profilePagination: {}, 15 | profileError: null 16 | }; 17 | 18 | export const profile = (state = initialState.profile, action) => { 19 | switch (action.type) { 20 | case GET_PROFILE_RESPONSE: 21 | return action.payload.profile || {}; 22 | case GET_PROFILE_REQUEST: 23 | default: 24 | return state; 25 | } 26 | }; 27 | 28 | export const counts = (state = initialState.counts, action) => { 29 | switch (action.type) { 30 | case GET_PROFILE_RESPONSE: 31 | return action.payload.counts; 32 | case GET_PROFILE_REQUEST: 33 | default: 34 | return state; 35 | } 36 | }; 37 | 38 | export const profileLoaded = (state = initialState.profileLoaded, action) => { 39 | switch (action.type) { 40 | case GET_PROFILE_RESPONSE: 41 | case GET_PROFILE_REQUEST: 42 | return action.payload.profileLoaded; 43 | default: 44 | return state; 45 | } 46 | }; 47 | 48 | export const profilePhotos = (state = initialState.profilePhotos, action) => { 49 | switch (action.type) { 50 | case UPDATE_PROFILE_PHOTOS_RESPONSE: 51 | return state.concat(action.payload.profilePhotos); 52 | case GET_PROFILE_PHOTOS_RESPONSE: 53 | return action.payload.profilePhotos; 54 | case GET_PROFILE_PHOTOS_REQUEST: 55 | return initialState.profilePhotos; 56 | default: 57 | return state; 58 | } 59 | }; 60 | 61 | export const profilePagination = (state = initialState.profilePagination, action) => { 62 | switch (action.type) { 63 | case GET_PROFILE_PHOTOS_RESPONSE: 64 | case UPDATE_PROFILE_PHOTOS_RESPONSE: 65 | return action.payload.profilePagination; 66 | case GET_PROFILE_PHOTOS_REQUEST: 67 | default: 68 | return state; 69 | } 70 | }; 71 | 72 | 73 | export const profileError = (state = initialState.profileError, action) => { 74 | switch (action.type) { 75 | case GET_PROFILE_PHOTOS_RESPONSE: 76 | case UPDATE_PROFILE_PHOTOS_RESPONSE: 77 | return action.payload.profileError; 78 | case GET_PROFILE_PHOTOS_REQUEST: 79 | default: 80 | return state; 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /src/app/reducers/searchByTag.js: -------------------------------------------------------------------------------- 1 | import { 2 | SEARCH_BY_TAG_REQUEST, 3 | SEARCH_BY_TAG_RESPONSE, 4 | GET_POPULAR_REQUEST, 5 | GET_POPULAR_RESPONSE 6 | } from '../constants'; 7 | 8 | const initialState = { 9 | foundedPhotos: [], 10 | searchPagination: {}, 11 | deniedTag: false 12 | }; 13 | 14 | export const foundedPhotos = (state = initialState.foundedPhotos, action) => { 15 | switch (action.type) { 16 | case SEARCH_BY_TAG_RESPONSE: 17 | case GET_POPULAR_RESPONSE: 18 | 19 | // If we try to find denied tag like: xxx, booty, etc 20 | // we will not get anything here 21 | // and we will simply return empty array 22 | return action.payload.foundedPhotos || []; 23 | case GET_POPULAR_REQUEST: 24 | case SEARCH_BY_TAG_REQUEST: 25 | default: 26 | return state; 27 | } 28 | }; 29 | 30 | 31 | export const searchPagination = (state = initialState.searchPagination, action) => { 32 | switch (action.type) { 33 | case SEARCH_BY_TAG_RESPONSE: 34 | 35 | // If we try to find denied tag like: xxx, booty, etc 36 | // we will not get anything here 37 | // and we will simply return empty array 38 | return action.payload.searchPagination || []; 39 | case SEARCH_BY_TAG_REQUEST: 40 | default: 41 | return state; 42 | } 43 | }; 44 | 45 | 46 | export const deniedTag = (state = initialState.deniedTag, action) => { 47 | switch (action.type) { 48 | case SEARCH_BY_TAG_RESPONSE: 49 | return action.payload.deniedTag; 50 | case SEARCH_BY_TAG_REQUEST: 51 | default: 52 | return state; 53 | } 54 | }; 55 | -------------------------------------------------------------------------------- /src/app/reducers/searchByUser.js: -------------------------------------------------------------------------------- 1 | import { 2 | SEARCH_BY_USER_REQUEST, 3 | SEARCH_BY_USER_RESPONSE 4 | } from '../constants'; 5 | 6 | export const foundedUsers = (state = [], action) => { 7 | switch (action.type) { 8 | case SEARCH_BY_USER_RESPONSE: 9 | return action.payload.foundedUsers; 10 | case SEARCH_BY_USER_REQUEST: 11 | default: 12 | return state; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /src/app/reducers/timeline.js: -------------------------------------------------------------------------------- 1 | import { 2 | GET_TIMELINE_REQUEST, 3 | GET_TIMELINE_RESPONSE, 4 | UPDATE_TIMELINE_RESPONSE 5 | } from '../constants'; 6 | 7 | const initialState = { 8 | timelineItems: [], 9 | timelinePagination: {}, 10 | timelineLoaded: false 11 | }; 12 | 13 | export const timelineItems = (state = initialState.timelineItems, action) => { 14 | switch (action.type) { 15 | case GET_TIMELINE_REQUEST: 16 | return state; 17 | case GET_TIMELINE_RESPONSE: 18 | case UPDATE_TIMELINE_RESPONSE: 19 | return state.concat(action.payload.timelineItems); 20 | default: 21 | return state; 22 | } 23 | }; 24 | 25 | export const timelinePagination = (state = initialState.timelinePagination, action) => { 26 | switch (action.type) { 27 | case GET_TIMELINE_REQUEST: 28 | return state; 29 | case GET_TIMELINE_RESPONSE: 30 | case UPDATE_TIMELINE_RESPONSE: 31 | return action.payload.pagination; 32 | default: 33 | return state; 34 | } 35 | }; 36 | 37 | export const timelineLoaded = (state = initialState.timelineLoaded, action) => { 38 | switch (action.type) { 39 | case GET_TIMELINE_REQUEST: 40 | case GET_TIMELINE_RESPONSE: 41 | return action.payload.timelineLoaded; 42 | default: 43 | return state; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /src/app/store/index.js: -------------------------------------------------------------------------------- 1 | import reducer from '../reducers'; 2 | import { createStore, applyMiddleware } from 'redux'; 3 | import logger from 'redux-logger'; 4 | import thunk from 'redux-thunk'; 5 | 6 | const middleware = process.env.NODE_ENV === 'production' ? [thunk] : [thunk, logger()]; 7 | const createStoreWithMiddleware = applyMiddleware(...middleware)(createStore); 8 | const store = createStoreWithMiddleware(reducer); 9 | 10 | export default store; 11 | -------------------------------------------------------------------------------- /src/helpers/index.js: -------------------------------------------------------------------------------- 1 | export const loadOnScrollBottom = ({dispatch, action, userId, that}) => { 2 | $(window).off('scroll'); 3 | $(window).on('scroll', function() { 4 | if($(this).scrollTop() + $(this).height() == $(document).height()) { 5 | dispatch(action({url: that.props.model.pagination.next_url, userId})); 6 | } 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /src/stylus/_about.styl: -------------------------------------------------------------------------------- 1 | .about 2 | text-align center 3 | padding-top 40px 4 | 5 | &__header 6 | color #fff 7 | text-shadow 0 1px 1px #333 8 | font bold 2em "Roboto Condensed", Arial, Tahoma 9 | 10 | &__text 11 | color #333 12 | text-shadow 0 1px 1px #fff 13 | 14 | a 15 | text-decoration none 16 | color #333 17 | border-bottom 1px dashed #27ae60 18 | -webkit-transition border-color 0.5s ease 19 | -moz-transition border-color 0.5s ease 20 | transition border-color 0.5s ease 21 | 22 | &:hover 23 | border-color #ff4c4b 24 | -------------------------------------------------------------------------------- /src/stylus/_column.styl: -------------------------------------------------------------------------------- 1 | [class*="column_xs-"] 2 | float left 3 | 4 | .column 5 | position relative 6 | min-height 1px 7 | padding-left 10px 8 | padding-right 10px 9 | 10 | setColumn(xs, 12) 11 | createOffset(xs, 12) -------------------------------------------------------------------------------- /src/stylus/_comments.styl: -------------------------------------------------------------------------------- 1 | .comments 2 | margin 10px 0 0 100px 3 | padding 0 4 | list-style none 5 | overflow hidden 6 | 7 | &__item 8 | display block 9 | margin 0 0 5px 0 10 | 11 | &__pic 12 | width 20px 13 | margin-right 5px 14 | float left 15 | 16 | &__username 17 | font-size 0.85em 18 | font-weight bold 19 | color #444444 20 | text-decoration none 21 | 22 | &:hover 23 | border-bottom 1px dashed #444 24 | 25 | &__text 26 | font-size 0.85em -------------------------------------------------------------------------------- /src/stylus/_feed.styl: -------------------------------------------------------------------------------- 1 | .feed 2 | margin 2% auto 0 3 | padding 0 4 | width 95% 5 | list-style none 6 | 7 | &__item 8 | display block 9 | width 76% 10 | min-height 400px 11 | margin 40px auto 0 -------------------------------------------------------------------------------- /src/stylus/_follow.styl: -------------------------------------------------------------------------------- 1 | .follow 2 | 3 | &__header 4 | color #fff 5 | text-shadow 0 1px 1px #333 6 | font-weight 700 7 | font-size 2em 8 | margin 20px 0 9 | text-align center 10 | 11 | &__list 12 | margin 0 13 | padding 0 14 | list-style none 15 | 16 | &__item 17 | float left 18 | width 100% 19 | height 100px 20 | vertical-align top 21 | margin 0 22 | background #fff 23 | border-bottom 1px solid #17b287 24 | border-right 1px solid #17b287 25 | border-left 1px solid #17b287 26 | 27 | &:first-child 28 | border-top 1px solid #17b287 29 | 30 | &:nth-child(4n) 31 | margin-right 0 32 | 33 | a 34 | text-decoration none 35 | color #333 36 | font-weight bold 37 | font-size 1.25em 38 | text-align center 39 | 40 | &__avatar 41 | display inline-block 42 | width 99px 43 | float left 44 | margin-right 10px 45 | 46 | &__username 47 | -webkit-transition color 0.5s ease 48 | -moz-transition color 0.5s ease 49 | transition color 0.5s ease 50 | overflow hidden 51 | position relative 52 | top 35px 53 | 54 | &:hover 55 | color #ff4c4b 56 | 57 | &__btn 58 | border 0 59 | padding 3px 10px 60 | box-shadow 2px 2px 2px 1px rgba(0,0,0,.5) 61 | background #ff4c4b 62 | color #fff 63 | float right 64 | margin 35px 10px 0 0 65 | 66 | &_read 67 | background #27ae60 68 | -------------------------------------------------------------------------------- /src/stylus/_fonts.styl: -------------------------------------------------------------------------------- 1 | /* Подключаемые шрифты */ 2 | @import url("http://fonts.googleapis.com/css?family=PT+Sans:400,700&subset=latin,cyrillic") 3 | @import url("../fonts/grand.css") -------------------------------------------------------------------------------- /src/stylus/_footer.styl: -------------------------------------------------------------------------------- 1 | .footer 2 | position absolute 3 | bottom 0 4 | width 100% 5 | height 89px 6 | background #444444 7 | border-top 1px solid #4f4f50 8 | border-bottom 1px solid #4f4f50 9 | 10 | &__copyright 11 | float right 12 | color #dddbdb 13 | font normal 0.75em "Tahoma", Arial, Verdana 14 | margin 38px 60px 0 0 -------------------------------------------------------------------------------- /src/stylus/_form.styl: -------------------------------------------------------------------------------- 1 | .form 2 | position relative 3 | width 605px 4 | 5 | &__field 6 | margin 0 7 | padding 0 8 | border 0 9 | 10 | &__label 11 | display block 12 | padding 5px 0 13 | 14 | &__label-title 15 | display inline-block 16 | width 200px 17 | vertical-align top 18 | 19 | &__input, &__select, &__textarea 20 | width 400px 21 | font-size (14/16)*1em 22 | outline none 23 | border 1px solid #a0a0a0 24 | 25 | &__input 26 | height 30px 27 | 28 | &__input, &__textarea 29 | padding 0 5px 30 | 31 | &:focus 32 | box-shadow 0 0 2px 2px rgb(255, 229, 0) 33 | 34 | &__select 35 | width 200px 36 | 37 | &__textarea 38 | padding 3px 5px 39 | resize vertical 40 | 41 | &__answer 42 | display inline-block 43 | width 400px 44 | 45 | &__radio-wrapper 46 | display block -------------------------------------------------------------------------------- /src/stylus/_globals.styl: -------------------------------------------------------------------------------- 1 | * 2 | -webkit-box-sizing border-box 3 | -moz-box-sizing border-box 4 | box-sizing border-box 5 | 6 | .g-clf:after, .g-clf:before 7 | clear both 8 | content "" 9 | display table -------------------------------------------------------------------------------- /src/stylus/_grid.styl: -------------------------------------------------------------------------------- 1 | .grid 2 | display block -------------------------------------------------------------------------------- /src/stylus/_header.styl: -------------------------------------------------------------------------------- 1 | /* Шапка */ 2 | .header 3 | width 100% 4 | height 50px 5 | background #17b287 6 | position fixed 7 | top 0 8 | left 0 9 | z-index 9999 10 | box-shadow 0 1px 1px 2px rgba(0,0,0,.5) -------------------------------------------------------------------------------- /src/stylus/_loader.styl: -------------------------------------------------------------------------------- 1 | @-moz-keyframes heartbeat-loader { 2 | 0% { 3 | -moz-transform: rotate(45deg) scale(1); 4 | transform: rotate(45deg) scale(1); 5 | } 6 | 14% { 7 | -moz-transform: rotate(45deg) scale(1.3); 8 | transform: rotate(45deg) scale(1.3); 9 | } 10 | 28% { 11 | -moz-transform: rotate(45deg) scale(1); 12 | transform: rotate(45deg) scale(1); 13 | } 14 | 42% { 15 | -moz-transform: rotate(45deg) scale(1.3); 16 | transform: rotate(45deg) scale(1.3); 17 | } 18 | 70% { 19 | -moz-transform: rotate(45deg) scale(1); 20 | transform: rotate(45deg) scale(1); 21 | } 22 | } 23 | @-webkit-keyframes heartbeat-loader { 24 | 0% { 25 | -webkit-transform: rotate(45deg) scale(1); 26 | transform: rotate(45deg) scale(1); 27 | } 28 | 14% { 29 | -webkit-transform: rotate(45deg) scale(1.3); 30 | transform: rotate(45deg) scale(1.3); 31 | } 32 | 28% { 33 | -webkit-transform: rotate(45deg) scale(1); 34 | transform: rotate(45deg) scale(1); 35 | } 36 | 42% { 37 | -webkit-transform: rotate(45deg) scale(1.3); 38 | transform: rotate(45deg) scale(1.3); 39 | } 40 | 70% { 41 | -webkit-transform: rotate(45deg) scale(1); 42 | transform: rotate(45deg) scale(1); 43 | } 44 | } 45 | @keyframes heartbeat-loader { 46 | 0% { 47 | -moz-transform: rotate(45deg) scale(1); 48 | -ms-transform: rotate(45deg) scale(1); 49 | -webkit-transform: rotate(45deg) scale(1); 50 | transform: rotate(45deg) scale(1); 51 | } 52 | 14% { 53 | -moz-transform: rotate(45deg) scale(1.3); 54 | -ms-transform: rotate(45deg) scale(1.3); 55 | -webkit-transform: rotate(45deg) scale(1.3); 56 | transform: rotate(45deg) scale(1.3); 57 | } 58 | 28% { 59 | -moz-transform: rotate(45deg) scale(1); 60 | -ms-transform: rotate(45deg) scale(1); 61 | -webkit-transform: rotate(45deg) scale(1); 62 | transform: rotate(45deg) scale(1); 63 | } 64 | 42% { 65 | -moz-transform: rotate(45deg) scale(1.3); 66 | -ms-transform: rotate(45deg) scale(1.3); 67 | -webkit-transform: rotate(45deg) scale(1.3); 68 | transform: rotate(45deg) scale(1.3); 69 | } 70 | 70% { 71 | -moz-transform: rotate(45deg) scale(1); 72 | -ms-transform: rotate(45deg) scale(1); 73 | -webkit-transform: rotate(45deg) scale(1); 74 | transform: rotate(45deg) scale(1); 75 | } 76 | } 77 | /* :not(:required) hides this rule from IE9 and below */ 78 | .heartbeat-loader:not(:required) { 79 | -moz-animation: heartbeat-loader 1300ms ease 0s infinite normal; 80 | -webkit-animation: heartbeat-loader 1300ms ease 0s infinite normal; 81 | animation: heartbeat-loader 1300ms ease 0s infinite normal; 82 | display: inline-block; 83 | position: relative; 84 | overflow: hidden; 85 | text-indent: -9999px; 86 | width: 36px; 87 | height: 36px; 88 | -moz-transform: rotate(45deg) scale(1); 89 | -ms-transform: rotate(45deg) scale(1); 90 | -webkit-transform: rotate(45deg) scale(1); 91 | transform: rotate(45deg) scale(1); 92 | -moz-transform-origin: 50% 50%; 93 | -ms-transform-origin: 50% 50%; 94 | -webkit-transform-origin: 50% 50%; 95 | transform-origin: 50% 50%; 96 | } 97 | .heartbeat-loader:not(:required):after, .heartbeat-loader:not(:required):before { 98 | position: absolute; 99 | content: ""; 100 | background: #e87; 101 | } 102 | .heartbeat-loader:not(:required):before { 103 | -moz-border-radius-topleft: 12px; 104 | -webkit-border-top-left-radius: 12px; 105 | border-top-left-radius: 12px; 106 | -moz-border-radius-bottomleft: 12px; 107 | -webkit-border-bottom-left-radius: 12px; 108 | border-bottom-left-radius: 12px; 109 | top: 12px; 110 | left: 0; 111 | width: 36px; 112 | height: 24px; 113 | } 114 | .heartbeat-loader:not(:required):after { 115 | -moz-border-radius-topleft: 12px; 116 | -webkit-border-top-left-radius: 12px; 117 | border-top-left-radius: 12px; 118 | -moz-border-radius-topright: 12px; 119 | -webkit-border-top-right-radius: 12px; 120 | border-top-right-radius: 12px; 121 | top: 0; 122 | left: 12px; 123 | width: 24px; 124 | height: 12px; 125 | } 126 | -------------------------------------------------------------------------------- /src/stylus/_main.styl: -------------------------------------------------------------------------------- 1 | .main 2 | margin 0 auto 3 | padding 50px 10px 115px -------------------------------------------------------------------------------- /src/stylus/_menu.styl: -------------------------------------------------------------------------------- 1 | .menu 2 | margin 0 3 | padding 14px 0 0 4 | list-style none 5 | text-align center 6 | 7 | &__item 8 | display inline-block 9 | margin-right 15px 10 | cursor pointer 11 | 12 | &:last-child 13 | margin-right 0 14 | 15 | &__link 16 | text-decoration none 17 | color #17b287 18 | background #f9f9f9 19 | padding 5px 20px 20 | -webkit-transition color 0.5s ease 21 | -moz-transition color 0.5s ease 22 | transition color 0.5s ease 23 | 24 | &:hover 25 | color #ff4c4b -------------------------------------------------------------------------------- /src/stylus/_mixins.styl: -------------------------------------------------------------------------------- 1 | box-shadow(arguments...) 2 | -webkit-box-shadow arguments 3 | -moz-box-shadow arguments 4 | box-shadow arguments 5 | 6 | gradient(arguments...) 7 | background -moz-linear-gradient(top, arguments) 8 | background -webkit-linear-gradient(top, arguments) 9 | background linear-gradient(to bottom, arguments) 10 | 11 | grid(ratio) 12 | width (100/12) * unit(ratio, '%') 13 | 14 | offset(ratio) 15 | margin-left (100/12) * unit(ratio, '%') 16 | 17 | setColumn(name, columns) 18 | 19 | for num in (1..columns) 20 | &_{name}-{num} 21 | grid num 22 | 23 | createOffset(name, columns) 24 | 25 | for num in (1..columns) 26 | &__offset_{name}-{num} 27 | offset num -------------------------------------------------------------------------------- /src/stylus/_normalize.styl: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.0 | MIT License | git.io/normalize */ 2 | 3 | html 4 | font-family sans-serif 5 | -ms-text-size-adjust 100% 6 | -webkit-text-size-adjust 100% 7 | 8 | body 9 | margin 0 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | main, 20 | nav, 21 | section, 22 | summary 23 | display block 24 | 25 | audio, 26 | canvas, 27 | progress, 28 | video 29 | display inline-block 30 | vertical-align baseline 31 | 32 | 33 | audio:not([controls]) 34 | display none 35 | height 0 36 | 37 | [hidden], 38 | template 39 | display none 40 | 41 | a 42 | background transparent 43 | 44 | 45 | a:active, 46 | a:hover 47 | outline 0 48 | 49 | abbr[title] 50 | border-bottom 1px dotted 51 | 52 | b, 53 | strong 54 | font-weight bold 55 | 56 | dfn 57 | font-style italic 58 | 59 | h1 60 | font-size 2em 61 | margin 0.67em 0 62 | 63 | mark 64 | background #ff0 65 | color #000 66 | 67 | small 68 | font-size 80% 69 | 70 | sub, 71 | sup 72 | font-size 75% 73 | line-height 0 74 | position relative 75 | vertical-align baseline 76 | 77 | 78 | sup 79 | top -0.5em 80 | 81 | 82 | sub 83 | bottom -0.25em 84 | 85 | img 86 | border 0 87 | 88 | svg:not(:root) 89 | overflow hidden 90 | 91 | figure 92 | margin 1em 40px 93 | 94 | hr 95 | -moz-box-sizing content-box 96 | box-sizing content-box 97 | height 0 98 | 99 | pre 100 | overflow auto 101 | 102 | code, 103 | kbd, 104 | pre, 105 | samp 106 | font-family monospace, monospace 107 | font-size 1em 108 | 109 | button, 110 | input, 111 | optgroup, 112 | select, 113 | textarea 114 | color inherit 115 | font inherit 116 | margin 0 117 | 118 | button 119 | overflow visible 120 | 121 | button, 122 | select 123 | text-transform none 124 | 125 | button, 126 | html input[type="button"], 127 | input[type="reset"], 128 | input[type="submit"] 129 | -webkit-appearance button 130 | cursor pointer 131 | 132 | button[disabled], 133 | html input[disabled] 134 | cursor default 135 | 136 | button::-moz-focus-inner, 137 | input::-moz-focus-inner 138 | border 0 139 | padding 0 140 | 141 | input 142 | line-height normal 143 | 144 | input[type="checkbox"], 145 | input[type="radio"] 146 | box-sizing border-box 147 | padding 0 148 | 149 | 150 | input[type="number"]::-webkit-inner-spin-button, 151 | input[type="number"]::-webkit-outer-spin-button 152 | height auto 153 | 154 | 155 | input[type="search"] 156 | -webkit-appearance textfield 157 | -moz-box-sizing content-box 158 | -webkit-box-sizing content-box 159 | box-sizing content-box 160 | 161 | 162 | input[type="search"]::-webkit-search-cancel-button, 163 | input[type="search"]::-webkit-search-decoration 164 | -webkit-appearance none 165 | 166 | 167 | fieldset 168 | border 1px solid #c0c0c0 169 | margin 0 2px 170 | padding 0.35em 0.625em 0.75em 171 | 172 | 173 | legend 174 | border 0 175 | padding 0 176 | 177 | textarea 178 | overflow auto 179 | 180 | 181 | optgroup 182 | font-weight bold 183 | 184 | table 185 | border-collapse collapse 186 | border-spacing 0 187 | 188 | 189 | td, 190 | th 191 | padding 0 192 | -------------------------------------------------------------------------------- /src/stylus/_page.styl: -------------------------------------------------------------------------------- 1 | /* Обвязка */ 2 | html, body 3 | height 100% 4 | font normal 16px "PT Sans", Verdana, Tahoma 5 | 6 | body 7 | background #bdc3c7 8 | 9 | &.welcome 10 | background url(../img/page/blur.jpg) no-repeat 0 0 11 | -webkit-background-size cover 12 | -moz-background-size cover 13 | -ms-background-size cover 14 | background-size cover 15 | 16 | .auth 17 | display block 18 | width 200px 19 | height 29px 20 | background url(../img/page/auth.png) no-repeat 0 0 21 | text-indent -9999px 22 | outline none 23 | position absolute 24 | top 50% 25 | left 50% 26 | margin-left -100px 27 | cursor pointer 28 | 29 | &:hover 30 | background url(../img/page/auth_h.png) no-repeat 0 0 31 | 32 | .page 33 | position relative 34 | min-height 100% 35 | margin 0 auto -------------------------------------------------------------------------------- /src/stylus/_photo-list.styl: -------------------------------------------------------------------------------- 1 | .photo-list 2 | margin 0 3 | padding 0 4 | list-style none 5 | 6 | &__item 7 | display inline-block 8 | width 20.5% 9 | margin 0 6% 6% 0 10 | cursor pointer 11 | 12 | &:nth-child(4n) 13 | margin-right 0 14 | 15 | img 16 | max-width 100% 17 | box-shadow 0px 0px 2px 3px rgba(0,0,0,.7) 18 | 19 | &__likes 20 | font-size 0.7em 21 | color #333 22 | float right 23 | 24 | &:hover 25 | text-decoration underline -------------------------------------------------------------------------------- /src/stylus/_photo.styl: -------------------------------------------------------------------------------- 1 | .photo 2 | overflow hidden 3 | 4 | &__pic 5 | display block 6 | width 500px 7 | max-width 100% 8 | margin-left 100px -------------------------------------------------------------------------------- /src/stylus/_popup.styl: -------------------------------------------------------------------------------- 1 | /* Всплывающие окна */ -------------------------------------------------------------------------------- /src/stylus/_profile.styl: -------------------------------------------------------------------------------- 1 | .profile 2 | margin 40px 0 0 3 | 4 | &__photo 5 | display block 6 | margin 0 auto 7 | width 150px 8 | height 150px 9 | 10 | &__username 11 | color #fff 12 | text-shadow 0 1px 2px #333 13 | text-align center 14 | line-height 20px 15 | margin 10px 0 0 16 | font bold 2em 17 | 18 | &__stats, &__info 19 | margin 20px 0 30px 20 | padding 0 21 | list-style none 22 | text-align center 23 | 24 | &__item 25 | display inline-block 26 | text-align center 27 | padding 0 20px 28 | font normal 1.25em 29 | color #fff 30 | text-shadow 0 1px 1px #333 31 | 32 | a 33 | text-decoration none 34 | color #fff 35 | text-shadow 0 1px 1px #333 36 | -webkit-transition color 0.5s ease 37 | -moz-transition color 0.5s ease 38 | transition color 0.5s ease 39 | 40 | &:hover 41 | color #17b287 42 | 43 | &__info 44 | 45 | .profile__item 46 | color #333 47 | text-shadow none 48 | display block 49 | text-align center -------------------------------------------------------------------------------- /src/stylus/_responsive.styl: -------------------------------------------------------------------------------- 1 | // Small devices (tablets, 768px and up) 2 | @media (min-width: 768px) 3 | 4 | [class*="column_sm-"] 5 | float left 6 | 7 | .column 8 | 9 | setColumn(sm, 12) 10 | 11 | createOffset(sm, 12) 12 | 13 | // Medium devices (desktops, 992px and up) 14 | @media (min-width: 992px) 15 | 16 | .page 17 | width 940px 18 | 19 | [class*="column_md-"] 20 | float left 21 | 22 | .column 23 | 24 | setColumn(md, 12) 25 | 26 | createOffset(md, 12) 27 | 28 | // Large devices (large desktops, 1200px and up) 29 | @media (min-width: 1170px) 30 | 31 | [class*="column_lg-"] 32 | float left 33 | 34 | .column 35 | 36 | setColumn(lg, 12) 37 | 38 | createOffset(lg, 12) -------------------------------------------------------------------------------- /src/stylus/_row.styl: -------------------------------------------------------------------------------- 1 | .row 2 | margin-bottom 15px -------------------------------------------------------------------------------- /src/stylus/_search.styl: -------------------------------------------------------------------------------- 1 | .search 2 | margin 40px 0 0 3 | 4 | &__form 5 | width 100% 6 | height 60px 7 | margin 0 auto 30px 8 | 9 | &__input 10 | display inline-block 11 | width 100% 12 | height 60px 13 | font normal 24px "Roboto Condensed" 14 | color #bdbab4 15 | outline none 16 | padding 0 14px 17 | border 0 -------------------------------------------------------------------------------- /src/stylus/_sidebar.styl: -------------------------------------------------------------------------------- 1 | /* Сайдбар */ -------------------------------------------------------------------------------- /src/stylus/_social.styl: -------------------------------------------------------------------------------- 1 | .social 2 | float left 3 | margin 32px 0 0 60px 4 | padding 0 5 | list-style none 6 | 7 | &__item 8 | display inline-block 9 | float left 10 | margin-left 15px 11 | 12 | &:first-child 13 | margin-left 0 14 | 15 | &__link 16 | color #dddbdb 17 | font normal 24px "Arial", Tahoma, Verdana 18 | text-decoration none 19 | -webkit-transition color 0.4s ease 20 | -moz-transition color 0.4s ease 21 | transition color 0.4s ease 22 | text-indent -9999px 23 | 24 | &:hover 25 | color #27ae60 -------------------------------------------------------------------------------- /src/stylus/_user.styl: -------------------------------------------------------------------------------- 1 | .user 2 | margin-bottom 10px 3 | 4 | &__pic 5 | width 100px 6 | height 100px 7 | float left 8 | margin-right 20px 9 | 10 | img 11 | width 100px 12 | border-radius 50% 13 | 14 | &__name 15 | color #333 16 | display block 17 | 18 | &__likes 19 | height 80px 20 | display block 21 | 22 | &__like 23 | width 80px 24 | height 80px 25 | display inline-block 26 | vertical-align middle 27 | background url("data:image/png;base64,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") no-repeat 0 0 28 | cursor pointer 29 | 30 | &:hover, &_liked 31 | background-position 0 -80px 32 | 33 | &__likes-count 34 | position relative 35 | font-size 2.5em 36 | display inline-block 37 | vertical-align middle 38 | 39 | &__video 40 | cursor pointer 41 | display block 42 | width 100px 43 | height 100px 44 | background url(../img/user/video-play.png) -------------------------------------------------------------------------------- /src/stylus/_vars.styl: -------------------------------------------------------------------------------- 1 | mobileBreakPoint = 768px 2 | tabletBreakPoint = 992px 3 | wideBreakPoint = 1170px -------------------------------------------------------------------------------- /src/stylus/style.styl: -------------------------------------------------------------------------------- 1 | @import "_vars" 2 | @import "_mixins" 3 | 4 | /* Шрифты */ 5 | @import "_fonts" 6 | 7 | /* Normalize */ 8 | @import "_normalize" 9 | 10 | /* Глобальные стили */ 11 | @import "_globals" 12 | 13 | /* Обвязка */ 14 | @import "_page" 15 | 16 | /* Шапка */ 17 | @import "_header" 18 | 19 | /* Menu */ 20 | @import "_menu" 21 | 22 | /* Основной контент */ 23 | @import "_main" 24 | 25 | /* Боковое меню */ 26 | @import "_sidebar" 27 | 28 | /* Подвал */ 29 | @import "_footer" 30 | 31 | /* Форма */ 32 | @import "_form" 33 | 34 | /* Сетка */ 35 | @import "_grid" 36 | 37 | /* Строка сетки */ 38 | @import "_row" 39 | 40 | /* Колонка сетки */ 41 | @import "_column" 42 | 43 | /* Profile */ 44 | @import "_profile" 45 | 46 | /* Popular */ 47 | @import "_search" 48 | 49 | /* Photo List */ 50 | @import "_photo-list" 51 | 52 | /* About page */ 53 | @import "_about" 54 | 55 | /* Social Icons */ 56 | @import "_social" 57 | 58 | /* Feed */ 59 | @import "_feed" 60 | 61 | /* User in Feed */ 62 | @import "_user" 63 | 64 | /* Photo in Feed */ 65 | @import "_photo" 66 | 67 | /* Comments in Feed */ 68 | @import "_comments" 69 | 70 | /* Followers and Follows */ 71 | @import "_follow" 72 | 73 | /* Всплывающие окна */ 74 | @import "_popup" 75 | 76 | /* Responsive */ 77 | @import "_responsive" 78 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | var path = require('path'); 3 | 4 | module.exports = { 5 | entry: './src/app/Root.jsx', 6 | output: { 7 | publicPath: "/", 8 | filename: 'bundle.js' 9 | }, 10 | context: __dirname, 11 | module: { 12 | loaders: [ 13 | { 14 | test: /\.jsx?$/, 15 | loader: 'babel', 16 | query: { 17 | presets: ['es2015', 'stage-0', 'react'] 18 | }, 19 | exclude: /node_modules/, 20 | include: path.resolve(__dirname, 'src') 21 | }, 22 | {test: /\.styl$/, loaders: ['style', 'css', 'stylus']} 23 | ] 24 | }, 25 | resolve: { 26 | extensions: ['', '.js', '.jsx'] 27 | } 28 | }; 29 | --------------------------------------------------------------------------------