com | http://flesler.blogspot.com
3 | * Licensed under MIT
4 | * @author Ariel Flesler
5 | * @version 2.1.0
6 | */
7 | ;(function(l){'use strict';l(['jquery'],function($){var k=$.scrollTo=function(a,b,c){return $(window).scrollTo(a,b,c)};k.defaults={axis:'xy',duration:0,limit:true};function isWin(a){return!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!==-1}$.fn.scrollTo=function(f,g,h){if(typeof g==='object'){h=g;g=0}if(typeof h==='function'){h={onAfter:h}}if(f==='max'){f=9e9}h=$.extend({},k.defaults,h);g=g||h.duration;var j=h.queue&&h.axis.length>1;if(j){g/=2}h.offset=both(h.offset);h.over=both(h.over);return this.each(function(){if(f===null)return;var d=isWin(this),elem=d?this.contentWindow||window:this,$elem=$(elem),targ=f,attr={},toff;switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=d?$(targ):$(targ,elem);if(!targ.length)return;case'object':if(targ.is||targ.style){toff=(targ=$(targ)).offset()}}var e=$.isFunction(h.offset)&&h.offset(elem,targ)||h.offset;$.each(h.axis.split(''),function(i,a){var b=a==='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,prev=$elem[key](),max=k.max(elem,a);if(toff){attr[key]=toff[pos]+(d?0:prev-$elem.offset()[pos]);if(h.margin){attr[key]-=parseInt(targ.css('margin'+b),10)||0;attr[key]-=parseInt(targ.css('border'+b+'Width'),10)||0}attr[key]+=e[pos]||0;if(h.over[pos]){attr[key]+=targ[a==='x'?'width':'height']()*h.over[pos]}}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)==='%'?parseFloat(c)/100*max:c}if(h.limit&&/^\d+$/.test(attr[key])){attr[key]=attr[key]<=0?0:Math.min(attr[key],max)}if(!i&&h.axis.length>1){if(prev===attr[key]){attr={}}else if(j){animate(h.onAfterFirst);attr={}}}});animate(h.onAfter);function animate(a){var b=$.extend({},h,{queue:true,duration:g,complete:a&&function(){a.call(elem,targ,h)}});$elem.animate(attr,b)}})};k.max=function(a,b){var c=b==='x'?'Width':'Height',scroll='scroll'+c;if(!isWin(a))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,doc=a.ownerDocument||a.document,html=doc.documentElement,body=doc.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}$.Tween.propHooks.scrollLeft=$.Tween.propHooks.scrollTop={get:function(t){return $(t.elem)[t.prop]()},set:function(t){var a=this.get(t);if(t.options.interrupt&&t._last&&t._last!==a){return $(t.elem).stop()}var b=Math.round(t.now);if(a!==b){$(t.elem)[t.prop](b);t._last=this.get(t)}}};return k})}(typeof define==='function'&&define.amd?define:function(a,b){'use strict';if(typeof module!=='undefined'&&module.exports){module.exports=b(require('jquery'))}else{b(jQuery)}}));
8 |
--------------------------------------------------------------------------------
/public/styles/all.css:
--------------------------------------------------------------------------------
1 | .info_page{font-size:14px}.info_page .hotkey_btn{display:inline-block;border:1px solid #ccc;border-radius:5px;background:#eee;padding:3px 8px;min-width:14px;text-align:center;color:#333}.info_page table tr td,.info_page table tr th{vertical-align:top}.info_page .btable tr td:nth-child(2),.info_page .btable tr td:nth-child(3){text-align:center}.info_page h1{margin-bottom:.7em;letter-spacing:-1px;font:23px/100% Verdana,sans-serif}.info_page h2{clear:left;padding-top:.5em;color:#ff6000;font-family:Arial,sans-serif;font-size:18px;font-weight:400}.info_page h2>a,.info_page h2>a:hover,.info_page h2>a:visited{color:#ff6000}.info_page p{margin:1em 0;line-height:1.54em}.info_page p:first-child{margin-top:0}.info_page ol{margin-top:1em;padding:0}.info_page li{margin-bottom:.5em;line-height:1.54em}.info_page ul{margin:1em 0 1.5em 2.65em;list-style:disc;line-height:1.54em;padding:0}.info_page .block-semi{margin-bottom:1em}.madskillz_page abbr{border-bottom:.1em dotted;cursor:help}.madskillz_page blockquote{clear:both;margin:.83em 0;border-left:2px solid #bbb;padding-left:15px}.madskillz_page table{clear:both;margin:1.5em 0;border:1px solid #ccc;border-collapse:collapse;width:100%}.madskillz_page table caption{text-align:left;text-indent:1em}.madskillz_page table td,.madskillz_page table th{border:1px solid #ccc;padding:.3em;word-break:break-word}.madskillz_page table td img,.madskillz_page table th img{max-width:630px!important}.madskillz_page code,.madskillz_page pre code{font-family:Menlo,Monaco,'Courier New',monospace}.madskillz_page code{border:1px solid #e1e1e8;border-radius:3px;background-color:#f7f7f9;padding:1px 4px;white-space:normal;color:#222}.madskillz_page pre .hljs,.madskillz_page pre .nohighlight{display:block;overflow-x:auto}.madskillz_page pre{word-break:break-all;overflow-y:hidden;overflow-x:auto}.madskillz_page pre code{background:#f8f8f8;padding:1em;white-space:pre-wrap;color:#333}.madskillz_page .spoiler{overflow:hidden}.madskillz_page .spoiler:before{display:block;float:left;margin-top:2px;border:0 solid red;background:url(https://habracdn.net/habr/images/1486388270/spoiler.icon.png) no-repeat left top;width:16px;height:16px;content:' '}.madskillz_page .spoiler .spoiler_title{border-bottom:1px dashed;cursor:pointer;color:#6da3bd;font-weight:400}.madskillz_page .spoiler .spoiler_text{display:none;margin-top:10px;border:1px solid #eee;background:#f9f9f9;padding:10px;overflow:hidden}.madskillz_page .block-semi{margin-bottom:0}.madskillz_page img[align=left]{margin-top:5px;margin-right:30px;margin-bottom:5px}.habr-badge{display:inline-block;border:1px solid;border-radius:5px;padding:5px 15px;width:100%;vertical-align:top;color:#000;box-sizing:border-box}.habr-badge__desc,.habr-badge__info,.habr-badge__title{padding-bottom:25px}.habr-badge__desc{padding-left:20px;box-sizing:border-box}
2 |
--------------------------------------------------------------------------------
/public/styles/forms.css:
--------------------------------------------------------------------------------
1 | input,select,textarea{font-family:Arial,'Helvetica Neue',Helvetica,sans-serif;font-size:12px}textarea{resize:none}form #company_specializm,form #user_specializm,form .item,form .spoiler_help{position:relative;margin-bottom:25px}form .spoiler_help .text{margin-top:15px;font-size:13px}form .spoiler_help .text ol{padding-left:30px;list-style:decimal}form .item.userformat{margin-top:25px}form .item .count{position:absolute;top:0;right:0;font-size:11px;color:#999;text-align:right}form .item:last-child{margin-bottom:0}form .item>label{display:block;margin-bottom:7px;font-family:Arial,'Helvetica Neue',Helvetica,sans-serif;font-size:13px;font-weight:700;line-height:13px;color:#424242}form .item>label .required_field{color:#ff7058}form .item input[type=email],form .item input[type=password],form .item input[type=text]{display:block;width:100%;height:34px;padding:0 10px;margin:0;font-size:14px;line-height:34px;color:#3b3b3b;border:1px solid #d9d9d9;box-sizing:border-box}form .item input[type=email]:focus,form .item input[type=password]:focus,form .item input[type=text]:focus,form .item textarea:focus{border:1px solid #a2bfd2;outline:0;box-shadow:none;-webkit-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}form .item input.form-control_datepicker,form .item input.form-control_timepicker{display:inline-block;vertical-align:baseline;width:auto;margin-left:13px}form .item textarea{width:99%;height:200px}form .item select,form .item select option{line-height:27px}form .item input[type=email]:disabled,form .item input[type=password]:disabled,form .item input[type=text]:disabled,form .item textarea:disabled{color:#bbb;background:#eee;border:1px solid #d9d9d9}form .item input[type=checkbox]{margin:3px}form .item .error{display:block;margin-top:5px;font-size:11px;line-height:13px;color:#ff7058}form .item .description{margin-top:5px;font-size:11px;line-height:15px;color:#999}form .item .checkbox_list{margin-top:10px;overflow:hidden}form .item .checkbox_list label{display:block;float:left;width:50%;font-weight:400}form .item.one_column .checkbox_list label{float:none;width:auto;margin-bottom:10px}form .item .radio_list{margin-top:10px}form .item .radio_list label{font-weight:400}form .item .radio_list.custom{color:#3f3f3f}form .item .radio_list.custom label{display:inline-block;margin:5px 10px;color:#3a7ca2;cursor:pointer;border-bottom:1px dashed}form .item .radio_list.custom label:first-child{margin-left:5px}form .item .radio_list.custom label.checked{padding:5px;margin:0 5px;color:#53513f;background:#eeecd8;border-bottom:0;border-radius:6px}form .item .radio_list.custom label.checked:first-child{margin-left:0}form .item .radio_list.custom label input{display:none}form .item .checkbox_single{margin-bottom:10px}form .item .checkbox_single label{display:inline-block;margin:0;font-weight:400}form .item .checkbox_in_label label{display:inline;font-weight:400}form .item .checkbox_in_label .label{font-weight:700}form .item .iframe_uploader{overflow:hidden;border:0}form .item .iframe_uploader_preview,form .item.habracaptcha{overflow:hidden}form .item .iframe_uploader_preview .image{position:relative;float:left;max-width:70%;min-width:48px;min-height:48px;margin-bottom:10px}form .item .iframe_uploader_preview .image .delete{position:absolute;top:2px;right:2px;display:none;float:right;padding:5px;font-size:10px;line-height:10px;color:#fff;text-transform:uppercase;cursor:pointer;background:#666;opacity:.9}form .item .iframe_uploader_preview .image .delete:hover{background:#8b0000}form .item .iframe_uploader_preview .image:hover .delete{display:block}form .item .iframe_uploader_preview .image img{display:block;max-width:100%;min-width:30px;padding:0;margin:0}form .item.habracaptcha .captcha_image{margin-bottom:20px;font-size:11px}form .item.habracaptcha img{width:166px;height:75px;margin-right:10px;vertical-align:middle}form .item.habracaptcha a{font-size:14px;text-decoration:none}form .item.habracaptcha a span{font-size:11px;border-bottom:1px dashed}.company_description_form #company_specializm,.company_description_form #user_specializm,.profile_settings_form #company_specializm,.profile_settings_form #user_specializm{position:relative;padding:17px 0 8px;margin:0;box-sizing:border-box}.company_description_form #company_specializm .item,.company_description_form #user_specializm .item,.profile_settings_form #company_specializm .item,.profile_settings_form #user_specializm .item{padding:0}.company_description_form #company_specializm .item .count,.company_description_form #user_specializm .item .count,.profile_settings_form #company_specializm .item .count,.profile_settings_form #user_specializm .item .count{top:0}.company_description_form .item,.profile_settings_form .item{padding:17px 0 8px;margin:0;box-sizing:border-box}.company_description_form .item:first-child,.profile_settings_form .item:first-child{padding-top:0}.company_description_form .item.avatar,.company_description_form .item.stages,.profile_settings_form .item.avatar,.profile_settings_form .item.stages{padding-bottom:25px;box-sizing:border-box}.company_description_form .item .count,.profile_settings_form .item .count{top:0}.form-field-medium .item{width:60%}.form-field-small .item{width:30%}.editor{position:relative}.editor .panel{background:#f5f5f5;border:1px solid #e0e0e0;border-bottom:0}.editor .panel .wysiwyg_wrapper:after{clear:both;content:"";display:table}.editor .panel .wysiwyg_wrapper .with-title{display:block;float:left;padding:0;margin:1px 15px 0 0}.editor .panel .wysiwyg_wrapper .btn{float:left;width:32px;height:32px;line-height:32px;color:#6da3bd;text-align:center;vertical-align:middle;border-right:1px solid #dcdcdc}.editor .panel .wysiwyg_wrapper .btn:hover{color:#4d7285;background:#dcdcdc}.editor .panel .wysiwyg_wrapper .btn .g-icon{display:inline-block;vertical-align:middle}.editor .panel .wysiwyg_wrapper .btn.btn-dropdown{position:relative;overflow:hidden}.editor .panel .wysiwyg_wrapper .btn.btn-dropdown select{position:absolute;top:0;left:0;height:32px;font-size:14px;line-height:32px;border:0;-moz-opacity:0;-khtml-opacity:0;opacity:0;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);-moz-appearance:none}.editor .panel .wysiwyg_wrapper .can_use_html{float:right;height:32px;padding:0 10px;font-size:10px;line-height:32px;color:#666;text-align:center;vertical-align:middle;border-left:1px solid #dcdcdc}.editor .panel .help_holder .close_html a,.editor .panel .wysiwyg_wrapper .can_use_html a{text-decoration:none;border-bottom:1px dashed}.editor .panel .wysiwyg_wrapper .help_holder{padding:10px;clear:both;border-top:1px solid #dcdcdc}.editor .panel .wysiwyg_wrapper .help_holder h4{margin-top:20px;margin-bottom:10px;font-size:12px;font-weight:700;color:#666}.editor .panel .wysiwyg_wrapper .help_holder h4:first-child{padding-top:10px;margin-top:0;clear:both;font-size:16px}.editor .panel .wysiwyg_wrapper .help_holder dl{margin-bottom:10px;font-size:11px}.autocomplete strong,.editor .panel .wysiwyg_wrapper .help_holder dl dt{font-weight:700;color:#000}.editor .panel .wysiwyg_wrapper .help_holder dl dd{color:#666}.editor .editor__footer{height:32px;padding-left:15px;line-height:32px;background-color:#f5f5f5;border:1px solid #e0e0e0;border-top:0}.editor .editor__footer .markdown_checkbox{display:inline-block;font-family:Arial,'Helvetica Neue',Helvetica,sans-serif;font-size:13px;font-weight:400;line-height:normal;color:#464646;vertical-align:baseline}.editor .editor__footer .markdown_checkbox input[type=checkbox]{margin:0 5px 0 0}.editor .text-holder{padding:0;background:#fff;border:1px solid #dcdcdc;box-sizing:border-box}.editor .text-holder textarea{width:100%;height:120px;padding:4px;margin:0;font-size:14px;vertical-align:top;border:0;outline:none;box-sizing:border-box}.editor .panel .help_holder .close_html{font-size:10px;text-align:right}.feedback_page .editor .text-holder textarea{resize:vertical}.img_uploader{width:300px;height:60px;padding:5px;overflow:hidden;text-align:center;border:1px solid #efefef}.img_uploader img{display:block;margin:0 auto 5px}.img_uploader a.upload_again{font-size:10px;line-height:20px;text-decoration:none;border-bottom:1px dashed}.upload_form{width:278px;height:40px;padding:10px;text-align:left;background:#fff;border:0 solid red}.upload_form .progress{height:5px;margin-top:5px;border:1px solid #eee}.upload_form .progress .bar{width:0%;height:5px;background:#aaa;background:url(https://habracdn.net/habr/images/1487064702/form/loader_button.gif) repeat-x 0 0}.upload_form .state{font-size:9px;color:#666}.preview_placeholder{padding:10px;margin-bottom:20px;font-size:12px;border:4px solid #eee}.buttons .description{padding-top:10px;clear:both;font-size:11px;color:#999}.buttons .text,.dropdown-menu li a img{display:inline-block;vertical-align:middle}.buttons .text{padding-top:1px;margin-left:10px;font-size:12px}.blue_buttons_panel{padding:20px;margin-bottom:15px;background:#e0edf8}.blue_buttons_panel input{margin-right:15px}.blue_buttons_panel input.big{margin-right:30px}.dropdown-menu{overflow:hidden;background-color:#f2f2f2;border-radius:4px;padding:0;margin:0;list-style:none}.dropdown-menu li{padding:5px;font-size:12px;text-align:left;border-top:1px solid #e5e5e5}.dropdown-menu li a{color:#000}.dropdown-menu li a img{width:20px;height:20px;border-radius:20px}.dropdown-menu li a span.name{display:inline-block;margin-left:5px;vertical-align:middle}.dropdown-menu li:first-child{border-top:none}.dropdown-menu .active,.dropdown-menu li:active,.dropdown-menu li:hover{background-color:#e5e5e5}.dropdown-menu a:hover{text-decoration:none;cursor:pointer}.autocomplete-w1{position:absolute;top:5px;left:0}.autocomplete{max-height:350px;overflow:auto;font-size:12px;text-align:left;cursor:default;background:#fff;border:1px solid #999}.autocomplete .selected{background:#f0f0f0}.autocomplete div{padding:2px 5px;overflow:hidden;color:#333;white-space:nowrap}.form{display:block;font-family:Arial,'Helvetica Neue',Helvetica,sans-serif}.form.hidden{display:none}.form_admin-causes{padding:20px 15px;border:1px solid #d5e7e4;position:relative;z-index:2;margin-top:-1px}.form__fieldset{margin:0;padding:0}.form__fieldset_admin-causes{margin-bottom:20px;border:0}.form__legend{display:block;font-weight:700;color:#484848;font-size:14px;margin:0;padding:0 0 16px}.form__label_datetime{font-size:0}.form__label_block{display:block;width:100%;line-height:28px}.form__label_block:hover .form__label-text{color:#4d80aa}.form__label-text{font-size:13px;color:#484848}.form__input:checked+.form__label-text{font-weight:700;color:#4d80aa}.form-control{font-size:14px}
2 |
--------------------------------------------------------------------------------
/public/styles/posts.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";@font-face{font-family:'hgm_icons';src:url(https://habracdn.net/habr/fonts/1487064702/icons/new/hgm_icons.eot);src:url(https://habracdn.net/habr/fonts/1487064702/icons/new/hgm_icons.eot#iefix) format("embedded-opentype"),url(https://habracdn.net/habr/fonts/1487064702/icons/new/hgm_icons.ttf) format("truetype"),url(https://habracdn.net/habr/fonts/1487064702/icons/new/hgm_icons.woff) format("woff"),url(https://habracdn.net/habr/fonts/1487064702/icons/new/hgm_icons.svg#hgm_icons) format("svg");font-weight:400;font-style:normal}.icon_cog:before,.icon_logo_freelansim:before,.icon_logo_mk:before,.icon_select_arrows:before{vertical-align:text-top}.icon_cog:before,.icon_logo_freelansim:before,.icon_logo_mk:before,.icon_select_arrows:before,.post__title .icon_check:before,.post__title .icon_edit:before,.post__title .icon_lock:before{font-family:'hgm_icons';speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon_cog:after,.icon_select_arrows:after,.post .hubs:before,.title_anchor:before{vertical-align:text-top}.icon_cog:after,.icon_logo_freelansim:after,.icon_logo_mk:after,.icon_select_arrows:after,.post .hubs:after,.post .hubs:before,.post__title .icon_check:after,.post__title .icon_edit:after,.post__title .icon_lock:after,.title_anchor:after,.title_anchor:before{font-family:'hgm_icons';speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon_logo_freelansim:after,.post .hubs:after,.post__title .icon_check:after,.post__title .icon_edit:after,.post__title .icon_lock:after,.title_anchor:after{vertical-align:text-top}.article__button-more{box-shadow:none;cursor:pointer;background-color:transparent}.article__button-more::-moz-focus-inner{padding:0;border:0}.article__button-more:focus,.article__button-more:hover{outline:0;box-shadow:none}.article__button-more:disabled{cursor:not-allowed}.icon_down:before{content:"\e602"}.icon_up:before{content:"\e60c"}.icon_eye:before{content:"\e603"}.icon_comment:before{content:"\e600"}.icon_fav:before{content:"\e909"}.icon_abuse:before{content:"\e606"}.icon_podcast:before{content:"\e608"}.icon_translate:before{content:"\e60a"}.icon_rss:before{content:"\e609"}.icon_pocket:before{content:"\e607"}.icon_twitter:before{content:"\e60b"}.icon_vk:before{content:"\e60e"}.icon_facebook:before{content:"\e604"}.icon_user:before{content:"\e60d"}.icon_comp:before{content:"\e901"}.icon_hub:before{content:"\e902"}.icon_cross:before{content:"\e601"}.icon_asterisk:before{content:"\e903"}.icon_mail:before{content:"\e900"}.icon_answers:before{content:"\e904"}.icon_lock:before{content:"\e905"}.icon_briefcase2:before,.post .hubs:before{content:"\e906"}.icon_edit:before{content:"\e907"}.icon_edit_msg:before{content:"\e90f"}.icon_check:before{content:"\e908"}.icon_hash:before{content:"\e90a"}.icon_edit_end:after{content:"\e913"}.icon_tree:before{content:"\e90b"}.icon_up_thin:before{content:"\2b06"}.icon_slug:before{content:"\e90d"}.icon_company_pic:before{content:"\e90e"}.icon_search:before{content:"\2b91"}.icon_share:before{content:"\e90c"}.icon_rating:before{content:"\e914"}.icon_cap:before{content:"\e916"}.icon_anchor-link:after,.title_anchor:after{content:"\e915"}.icon_select_arrows{position:absolute;right:10px;top:0;z-index:2;pointer-events:none}.icon_cog:before,.icon_select_arrows:before{content:"\e915";color:#aeaeae;font-size:13px;position:relative;top:2px}.icon_cog:before{font-size:18px;text-align:center;content:"\e910";top:-1px}.icon_cog.btn_outline_grey:hover:before,.open .icon_cog:before{color:#73abdf}.open .icon_cog{background-color:#fff}.icon_logo_mk:after{font-size:20px;content:"\e911";color:#666;position:relative;vertical-align:middle}.icon_logo_freelansim:after{font-size:20px;content:"\e912";color:#666;position:relative}.post_cp{margin-top:6px;margin-bottom:20px;padding:20px;background:#d3f2c0;color:#333;position:relative}.post_cp form{display:inline-block}.i-am-your-father-luke{display:block;clear:both;border:none;font:40px/110% Arial,sans-serif;color:#cc9;letter-spacing:-2px}.i-am-your-father-luke a{color:#cc9;border-bottom:2px solid #cc9;text-decoration:none;padding-bottom:2px}.i-am-your-father-luke a:visited{color:#cc9}.i-am-your-father-luke a:hover{color:#6da3bd;border-bottom:none;text-decoration:none}.ufo-was-here{margin-bottom:20px;font:16px/110% Verdana,sans-serif;color:#666}.posts .post{margin-bottom:40px}.posts .i-am-your-father-luke{margin:0 0 40px}.posts .ufo-was-here{margin-bottom:20px}.post_show{margin-top:5px}.post__time_published{display:inline-block;vertical-align:baseline;color:#7e7e7e;font-size:11px;margin-bottom:2px}.post__time_published_md:after{content:'MD';position:relative;padding:0 10px;background:#ff0;color:#000}.post__flow,.post__title,.post__title-arrow,.post__title_link{font-family:Arial,'Helvetica Neue',Helvetica,sans-serif;font-weight:700}.post__flow,.post__title,.post__title_link{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;line-height:34px;font-size:28px}.fonts-loaded .post__flow,.fonts-loaded .post__title,.fonts-loaded .post__title-arrow,.fonts-loaded .post__title_link{font-family:'Fira Sans',sans-serif;font-weight:500}.post__title-arrow{font-size:24px;line-height:1}.post__flow{color:#5d8fa8}.post__flow:visited{color:#5f9db5}.post__flow:hover{color:#47738d}.post__title,.post__title_link{color:#555}.post__title{padding:0;margin:0 0 5px}.post__title_link:hover,.post__title_link:visited{color:#888}.post__body{padding-bottom:20px}.post__body h1:hover .title_anchor,.post__body h2:hover .title_anchor,.post__body h3:hover .title_anchor,.post__body h4:hover .title_anchor,.post__body h5:hover .title_anchor,.post__body h6:hover .title_anchor{visibility:visible}.post__tags{font-family:Verdana,sans-serif;font-size:12px;padding:0;color:#000;margin-top:10px}.post__title .icon_lock:before{color:#6da3bd}.post__title .icon_check,.post__title .icon_edit{letter-spacing:normal}.post__title .icon_check:before,.post__title .icon_edit:before,.post__title .icon_lock:before{font-size:20px;vertical-align:baseline!important}.icon_check{margin-left:-4px}.icon_check:before{color:#76a758}.icon_delayed,.post .hubs a{display:inline-block;vertical-align:baseline;color:#89a16e}.icon_delayed .icon-svg{width:22px;height:20px;color:inherit}.post.special_post{border-left:4px solid #ffe237;padding:0 20px;margin-bottom:40px}.post.special_post .content>.habracut{padding-bottom:0}.post .searched-item{background:#fffacd;font-style:normal}.post .hubs,.post .published{color:#7e7e7e;font-size:11px;margin-bottom:2px}.post h1.title{margin-bottom:8px}.post h1.title a.blog_title.corporative{color:#8277a3}.post h1.title a.blog_title.corporative:hover{color:#aba4c2}.post h1.title a.post_title,.post ul.tags li a{color:#666}.post h1.title a.post_title:visited{color:#b5b5b5}.post h1.title a.post_title:hover,.post ul.tags li a:hover{color:#a3a3a3}.post div.habracut{padding-top:20px}.post .hubs{color:#999;margin-bottom:15px;position:relative;padding:0 0 0 20px}.post .hubs:before{color:#9bbcc6;font-size:15px;margin-right:5px;position:absolute;left:0;top:1px}.post .hubs.special_hubs{background:0 0;padding-left:0}.post .hubs a{color:#999;vertical-align:middle}.post .hubs a.subscribed{color:#6c9471}.post .hubs .profiled_hub{cursor:help}.post .content{font-size:14px;line-height:160%;font-family:Verdana,sans-serif;overflow:hidden}.post .content>.habracut{padding-top:20px;padding-bottom:10px}.post .content a:visited:not(.habracut){color:#909}.post .content img{max-width:100%}.post ul.tags{font-family:Verdana,sans-serif;font-size:10px;padding:2px 0}.post ul.tags.icon_tag:before{font-size:15px}.post ul.tags li{display:inline;color:#999}.post ul.tags li.fav a{color:#390}.post ul.tags li.fav a:hover{color:#85c266}.post ul.tags li.favourites_edit_tags{margin-left:10px}.post ul.tags li.favourites_edit_tags a{color:#ccc}.post ul.tags li.favourites_edit_tags a:hover{color:#666}.post .polling{margin:20px 0}.post .polling .poll{margin-bottom:20px}.post .polling .poll:last-child{margin-bottom:0}.post .poll .poll_title{font-size:14px}.post .poll table.answer{width:auto;border:0;margin:10px 0 17px}.post .poll table.answer tr,.post .poll table.result tr{border:0}.post .poll table.answer tr td{border:0;padding:8px 0;vertical-align:top}.post .poll table.answer tr td input[type=checkbox],.post .poll table.answer tr td input[type=radio]{margin:3px}.post .poll table.answer tr td.label{padding-left:5px;font-size:13px;line-height:15px}.post .poll table.result{width:100%;font-size:12px;border:0;margin:10px 0 0}.post .poll table.result tr td{border:0;padding:2px 0;vertical-align:baseline;line-height:normal}.post .poll table.result tr td.percent{width:1%;color:#ccc;text-align:right;word-wrap:normal;word-break:normal;padding-right:10px}.post .poll .poll_title,.post .poll table.result tr td strong{font-weight:700;color:#404040}.post .poll table.result tr td .bar{height:5px;margin-top:5px;background:#dadacd}.post .poll table.result tr td .bar.winner{background:#7fa0b0}.post .poll .total{color:#999;font-size:11px;padding-top:10px;font-style:italic}.abuse_wrapper,.post .abuse_form{display:inline-block;vertical-align:middle;position:relative}.abuse_wrapper{height:16px;margin-left:5px;width:16px}.post .abuse_form{width:90%;font-family:Arial,sans-serif;font-size:11px;border:1px solid #e5e5e5;padding:0}.habralenta_settings #show_habralenta_settings.hide,.post .abuse_form.hidden{display:none}.post .abuse_form .input{margin-right:100px}.post .abuse_form .input input.text{display:inline-block;vertical-align:top;font-size:14px;margin:0;width:100%;background:0 0;box-sizing:border-box;border:0 solid #d9d9d9;padding:0;color:#3b3b3b;line-height:29px;height:29px;text-indent:8px}.post .abuse_form .buttons{position:absolute;right:2px;top:2px;display:inline-block}.post div.tags{margin-bottom:15px;font-family:Verdana,sans-serif;font-size:12px;padding:2px 0;color:#000}#edit_tags_form{font-size:12px;padding:10px;border-radius:5px;background:#eee;margin-bottom:10px}#edit_tags_form label{display:block;margin-bottom:10px}#edit_tags_form input.tags_string{width:99%}#edit_tags_form .description{font-size:10px;color:#666;margin-top:5px;margin-bottom:10px}#edit_tags_form a.close{text-decoration:none;color:green;border-bottom:1px dashed}.post_inner_banner{margin-top:40px;position:relative}.post_inner_banner a,.post_inner_banner a:hover{text-decoration:none}.post_inner_banner .left,.post_inner_banner .right{width:50%;text-align:center;vertical-align:middle;line-height:68px}.post_inner_banner .left{float:left;border-left:1px solid #e7e7e7;-webkit-border-top-left-radius:15px;-webkit-border-bottom-left-radius:15px;-moz-border-radius-topleft:15px;-moz-border-radius-bottomleft:15px;border-top-left-radius:15px;border-bottom-left-radius:15px;height:68px;border-top:1px solid #e7e7e7;border-bottom:1px solid #e7e7e7}.post_inner_banner .left .text,.post_inner_banner .right .text{display:inline-block;height:45px;font-size:14px;line-height:20px;border:0 solid red;text-align:left;vertical-align:middle}.post_inner_banner .left .text{background:url(https://habracdn.net/habr/images/1487064702/posts/inner_post_banner/hp/hp.png) no-repeat left center;padding-left:60px;color:#333}.post_inner_banner .right{position:absolute;right:0;top:0;bottom:0;border-right:1px solid #7fcaea;border-top:1px solid #7fcaea;border-bottom:1px solid #7fcaea;-webkit-border-top-right-radius:15px;-webkit-border-bottom-right-radius:15px;-moz-border-radius-topright:15px;-moz-border-radius-bottomright:15px;border-top-right-radius:15px;border-bottom-right-radius:15px;background:url(https://habracdn.net/habr/images/1487064702/posts/inner_post_banner/hp/arrow.png) no-repeat left center}.post_inner_banner .right .text{background:url(https://habracdn.net/habr/images/1487064702/posts/inner_post_banner/hp/icon.png) no-repeat left center;padding-left:43px;color:#0096d6}.habralenta_settings{margin-top:5px}.habralenta_settings p{font-size:13px;color:#666;font-weight:700;margin-bottom:15px}.habralenta_settings .category-list{margin-bottom:20px}.habralenta_settings .category-list .category,.habralenta_settings .category-list .category_all{font-size:133%;overflow:hidden;margin-bottom:10px;position:relative}.habralenta_settings .category-list .category_all .checkbox{position:absolute;top:0;left:0;cursor:pointer;width:14px;height:14px;margin-top:.2em;background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat -25px 0}.habralenta_settings .category-list .category .hubs .hub.subscription .checkbox,.habralenta_settings .category-list .category.full .checkbox,.habralenta_settings .category-list .category_all.selected .checkbox{background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat 0 0}.habralenta_settings .category-list .category_all .title{margin-left:24px;cursor:pointer;border-bottom:1px dashed;color:green}.habralenta_settings .category-list .category_all .lenta-tip{color:#666;cursor:help}.habralenta_settings .category-list .category:last-child{margin-bottom:0}.habralenta_settings .category-list .category .checkbox{float:left;position:absolute;top:0;left:0;cursor:pointer;width:14px;height:14px;margin-top:.2em;background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat -25px 0}.habralenta_settings .category-list .category.part .checkbox{background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat -50px 0}.habralenta_settings .category-list .category.disabled .checkbox,.habralenta_settings .category-list .category.disabled .hubs .hub .checkbox{cursor:default;background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat -25px -75px}.habralenta_settings .category-list .category.disabled .hubs .hub.subscription .checkbox,.habralenta_settings .category-list .category.disabled.full .checkbox{background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat 0 -75px}.habralenta_settings .category-list .category.disabled.part .checkbox{background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat -50px -75px}.habralenta_settings .category-list .category.disabled .count,.habralenta_settings .category-list .category.disabled .title{color:#aaa}.habralenta_settings .category-list .category.disabled .title a,.habralenta_settings .category-list .category.disabled .title a:hover{color:#aaa;border-bottom:1px dashed #aaa;cursor:default}.habralenta_settings .category-list .category .title{float:left;display:block;margin-left:24px;margin-bottom:1px;color:#aaa}.habralenta_settings .category-list .category .title a,.habralenta_settings a#hide_habralenta_settings,.habralenta_settings a#show_habralenta_settings{text-decoration:none;border-bottom:1px dashed #6da3bd}.habralenta_settings .category-list .category .title a:hover,.habralenta_settings a:hover#hide_habralenta_settings,.habralenta_settings a:hover#show_habralenta_settings{border-bottom:1px dashed #4d7285}.habralenta_settings .category-list .category .count{color:#999}.habralenta_settings .category-list .category .new{color:green;font-size:11px;vertical-align:top}.habralenta_settings .category-list .category .hubs{clear:both;padding-left:22px;display:none;padding-top:.8em}.habralenta_settings .category-list .category .hubs.show{display:block}.habralenta_settings .category-list .category .hubs .hub{font-size:85%;overflow:hidden;margin-bottom:.6em;position:relative}.habralenta_settings .category-list .category .hubs .hub:last-child{margin-bottom:0}.habralenta_settings .category-list .category .hubs .hub .checkbox{float:left;position:absolute;top:0;left:0;cursor:pointer;width:14px;height:14px;margin-top:.1em;background:url(https://habracdn.net/habr/images/1487064702/form/checkbox.png) no-repeat -25px 0}.habralenta_settings .category-list .category.disabled .hubs .hub a{color:#aaa;cursor:default}.habralenta_settings .category-list .category .hubs .hub a{float:left;display:block;margin-left:24px}.habralenta_settings .category-list .category .hubs .hub .new{color:green;font-size:11px;vertical-align:top;float:left;display:block;margin-left:4px}.habralenta_settings .category-list .category .hubs .description{font-size:85%;color:#999;margin-bottom:.6em}.habralenta_settings img.ajax_loader{display:inline;margin-left:5px;vertical-align:top}.habralenta_settings .category-list img.ajax_loader{margin-top:3px;vertical-align:top}.habralenta_settings #save_success{color:green;display:none;margin-left:10px}.habralenta_settings #save_success.show{display:inline}.habralenta_settings #form_habralenta_settings .btn,.habralenta_settings .or{margin-right:5px}.habralenta_settings #form_habralenta_settings .btn.loading{background:url(https://habracdn.net/habr/images/1487064702/form/loader_button.gif)}.habralenta_settings hr.mail-stripe{height:2px;width:300px;margin-left:-20px;border:none;background:url(https://habracdn.net/habr/images/1487064702/mail-stripe.png)}#lenta_notifications .inner_notice{margin-bottom:20px;padding:20px;background:#d3f2c0;color:#333;position:relative}#lenta_notifications a.close{position:absolute;right:10px;top:5px;text-align:right;text-decoration:none;border-bottom:1px dashed;font-size:10px}.post-additionals+div{margin-top:15px}.block_after_post{margin-top:20px}section.post-footer{padding:10px 0 20px!important}.reject_form{margin:20px 0;padding:20px;border:1px solid red;max-width:600px}.article__body{padding:30px;border-left:1px solid #ebeaea;border-right:1px solid #ebeaea;box-sizing:border-box}.article__body-text{color:#353535;font-size:14px;line-height:24px;font-weight:400;margin-bottom:25px}.article__button-more{border:2px solid #606f8c;font-size:14px;font-weight:700;height:45px;line-height:41px;padding:0 20px;display:inline-block;vertical-align:top;color:#606f8c;box-sizing:border-box;border-radius:4px}.article__button-more:hover{text-decoration:none;color:#fff;background-color:#606f8c;-webkit-transition:all .1s ease-in;transition:all .1s ease-in}.article__button-more_habr{border-color:#99c2cd;color:#99c2cd}.article__button-more_habr:hover{background-color:#99c2cd}.article__button-more_gt{border-color:#8293b6;color:#8293b6}.article__button-more_gt:hover{background-color:#8293b6}.article__button-more_mm{border-color:#7eb9df;color:#8293b6}.article__button-more_mm:hover{background-color:#7eb9df}.title_anchor{position:relative;visibility:hidden}.title_anchor:after{position:relative;top:2px;color:#b5b5b5;margin-left:7px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.list{margin:0;padding:0;list-style:none}.list__item,.list__item-link{color:#fff;font-size:14px}.article__tags .list__item,.article__tags .list__item-link{color:#87878d;font-size:13px}.megapost-cover_light .list__item,.megapost-cover_light .list__item-link{color:#fff}.megapost-cover_dark .list__item,.megapost-cover_dark .list__item-link{color:#000}.list__item-link{text-decoration:underline}.list__item-link.link_dotted{text-decoration:none;border-bottom:1px dotted}.article__tags .list__item-link:hover{color:#87878d}.list__item-link:hover,.megapost-cover_light .list__item-link:hover{color:rgba(255,255,255,.8)}.megapost-cover_dark .list__item-link:hover{color:rgba(0,0,0,.8)}.list_inline .list__item{display:inline-block;vertical-align:middle}.megapost-head__meta .list__item{margin-right:30px}.megapost-head__meta .list__item:last-child{margin:0}.article__tags .list__item,.megapost-head__hubs .list__item{white-space:nowrap;line-height:1.5em}.article__tags .list__item:after,.megapost-head__hubs .list__item:after{content:',\00a0'}.article__tags .list__item:last-child:after,.megapost-head__hubs .list__item:last-child:after{content:''}.megapost-cover__img{height:600px;background-repeat:none;background-position:center;background-size:cover;background-color:#ccc}.megapost-cover_short .megapost-cover__img{height:500px}.megapost-cover__img_darken{position:relative}.megapost-cover__img_darken:before{content:'';position:absolute;top:0;bottom:0;left:0;right:0;background-color:rgba(0,0,0,.55);z-index:0}.megapost-cover__company-blog{position:absolute;top:0;left:auto;width:100%}.megapost-cover_short .megapost-cover__company-blog{top:30px;left:0}.megapost-cover__grid-link{position:absolute;right:0;top:0;height:40px;line-height:40px;white-space:nowrap;padding:0 30px;box-sizing:border-box}.megapost-cover__inner{position:relative;z-index:2;height:100%}.megapost-cover_short .megapost-cover__inner{padding:30px;box-sizing:border-box}.megapost-head{position:relative;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.megapost-head__blog-link{color:#fff;font-size:12px;font-weight:700;text-transform:uppercase;white-space:nowrap;padding:0;display:inline-block;vertical-align:top;box-sizing:border-box;margin-bottom:10px}.megapost-cover_light .icon_briefcase:before,.megapost-cover_light .megapost-head__title,.megapost-cover_light .megapost-head__title-link,.megapost-cover_light .megapost-head__title-link:hover,.megapost-head__blog-link:hover{color:#fff}.megapost-head__title,.megapost-head__title-link{font-size:34px;font-weight:700;color:#fff;line-height:1.5em;text-indent:-3px}.megapost-cover_dark .icon_briefcase:before,.megapost-cover_dark .megapost-head__title,.megapost-cover_dark .megapost-head__title-link,.megapost-cover_dark .megapost-head__title-link:hover{color:#000}.megapost-head__title-link:hover{color:#fff;text-decoration:none}.megapost-head__title{margin:0 0 18px;max-width:580px;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}.megapost-head__title .searched-item{color:#353535}.megapost-head__meta{position:absolute;bottom:0;left:auto;margin-bottom:30px}@font-face{font-family:'icons_megapost';src:url(https://habracdn.net/habr/fonts/1487064702/megapost_icons/icons.eot);src:url(https://habracdn.net/habr/fonts/1487064702/megapost_icons/icons.eot#iefix) format("embedded-opentype"),url(https://habracdn.net/habr/fonts/1487064702/megapost_icons/icons.ttf) format("truetype"),url(https://habracdn.net/habr/fonts/1487064702/megapost_icons/icons.woff) format("woff"),url(https://habracdn.net/habr/fonts/1487064702/megapost_icons/icons.svg#icons) format("svg");font-weight:400;font-style:normal}@font-face{font-family:"gt-icons";src:url(https://habracdn.net/habr/fonts/1487064702/gt-icons/gt-icons.eot);src:url(https://habracdn.net/habr/fonts/1487064702/gt-icons/gt-icons.eot#iefix) format("embedded-opentype"),url(https://habracdn.net/habr/fonts/1487064702/gt-icons/gt-icons.woff) format("woff"),url(https://habracdn.net/habr/fonts/1487064702/gt-icons/gt-icons.ttf) format("truetype"),url(https://habracdn.net/habr/fonts/1487064702/gt-icons/gt-icons.svg#gt-icons) format("svg");font-weight:400;font-style:normal}.icon,.icon_briefcase:before,.icon_tag:before{font-family:"icons_megapost";speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:inline-block;vertical-align:text-top}.icon_briefcase{position:relative;padding-left:25px;box-sizing:border-box}.icon_briefcase:before{content:"\e801";font-size:17px;color:#fff;margin-right:5px;position:absolute;left:0;top:2px}.icon_tag:before{content:"\e800";font-size:17px;color:#bac8cc;margin-right:5px}.g-icon{font-family:"gt-icons";speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.g-icon-bold:before{content:"\e613"}.g-icon-italic:before{content:"\e614"}.g-icon-underline:before{content:"\e615"}.g-icon-strike:before{content:"\e616"}.g-icon-users:before{content:"\e617"}.g-icon-cut:before{content:"\e618"}.g-icon-paragraph:before{content:"\e619"}.g-icon-video:before{content:"\e61a"}.g-icon-images:before{content:"\e61b"}.g-icon-quote:before{content:"\e61c"}.g-icon-link:before{content:"\e61d"}.g-icon-more:before{content:"\e621"}.g-icon-list:before{content:"\e60e"}.g-icon-code:before{content:"\e61e"}.g-icon-spoiler:before{content:"\e620"}
2 |
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Link } from 'react-router'
3 | import Helmet from 'react-helmet'
4 |
5 | import { ga } from '../utils'
6 |
7 | import MainNavBar from './MainNavBar'
8 | import UserMenu from './UserMenu'
9 | import DefaultPageHeader from './DefaultPageHeader'
10 |
11 | class App extends Component {
12 | componentDidUpdate() {
13 | // ReactDOM.findDOMNode(this).scrollIntoView()
14 | // window.scrollTo(0, 0)
15 | }
16 |
17 | componentWillMount() {
18 | document.body.style.display = 'none'
19 | }
20 |
21 | componentDidMount() {
22 | // HACK стили подключаются в Helmet после рендеринга страницы
23 | setTimeout(() => (document.body.style.display = 'block'), 100)
24 | }
25 |
26 | render() {
27 | const title = this.props.children.props.route.title
28 | return (
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | {/* TODO на некоторых страницах замечено добавление css-класса js-sticky-wrapper */}
37 | {/* убрал css-класс column-wrapper_content - нигде не используется */}
38 |
39 | {/* TODO на некоторых страницах замечено добавление css-класса js-content_left */}
40 | {!!title && }
41 | {this.props.children}
42 |
43 |
44 |
45 |
46 |
189 |
196 |
207 |
208 |
209 | )
210 | }
211 | }
212 |
213 | export default App
214 |
--------------------------------------------------------------------------------
/src/components/AuthorInfo.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | import { ga, plural } from '../utils'
5 |
6 | const AuthorInfo = ({ author: { id , nick, name, avatar, specialization, contacts, votingCounter, karma, rating } }) => {
7 |
8 | const karmaVote = () => {
9 | // TODO реализовать userKarmaVote
10 | alert('голосование за карму')
11 | }
12 |
13 | const karmaVotePlus = (event) => {
14 | karmaVote(event, id, 1, 1)
15 | ga('author_info_bottom', 'vote_plus', nick)
16 | }
17 |
18 | const karmaVoteMinus = (event) => {
19 | karmaVote(event, id, 1, -1)
20 | ga('author_info_bottom', 'vote_minus', nick)
21 | }
22 |
23 | return (
24 |
25 |
26 |

27 |
28 |
{/* убрал css-класс js-user_${id} */}
29 |
30 |
{name}
31 |
32 |
{`@${nick}`}
33 |
34 |
37 |
38 |
карма
39 |
{karma.toFixed(1)}
40 |
41 |
44 |
45 |
46 | рейтинг
47 | {rating.toFixed(1)}
48 |
49 |
50 | Написать
51 |
52 |
53 | { !!specialization &&
{specialization}
}
54 | { !!contacts && contacts.length > 0 &&
55 |
56 | { contacts.map(contact => - {contact.type}
) }
57 |
58 | }
59 |
60 |
61 | )
62 | }
63 |
64 | export default AuthorInfo
65 |
--------------------------------------------------------------------------------
/src/components/AuthorInfoByCompany.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | const AuthorInfoByCompany = ({ company: { id, nick, name, avatar, specialization, contacts, rating }}) => (
5 |
6 |
7 |

8 |
9 |
10 |
11 |
{name}
12 |
13 | рейтинг
14 | {rating}
15 |
16 |
17 |
18 |
19 |
20 |
21 | { !!specialization &&
{specialization}
}
22 | { !!contacts && contacts.length > 0 &&
23 |
24 | { contacts.map(contact => - {contact.type}
) }
25 |
26 | }
27 |
28 |
29 | )
30 |
31 | export default AuthorInfoByCompany
32 |
--------------------------------------------------------------------------------
/src/components/DefaultPageHeader.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const DefaultPageHeader = ({ title }) => (
4 |
5 |
{title}
6 |
7 | )
8 |
9 | export default DefaultPageHeader
10 |
--------------------------------------------------------------------------------
/src/components/Feedback.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Feedback = () => (
4 | Feedback
5 | )
6 |
7 | export default Feedback
8 |
--------------------------------------------------------------------------------
/src/components/FormAdminCauses.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const FormAdminCauses = ({ userNick, postId }) => (
4 |
51 | )
52 |
53 | export default FormAdminCauses
54 |
--------------------------------------------------------------------------------
/src/components/InfoAbout.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
Добро пожаловать на Хабрахабр, крупнейший в Европе ресурс для IT-специалистов, созданный компанией «ТМ» в 2006-м
7 | году. Со временем «Хабр» вырос из небольшого отраслевого сайта в глобальную профессиональную площадку, которую в месяц посещают более 10 миллионов пользователей.
8 |
«Хабрахабр» одинаково интересен программистам и разработчикам, администраторам и тестировщикам, дизайнерам и верстальщикам, аналитикам и копирайтерам, а также
9 | всем тем, для кого IT — это не просто две буквы алфавита.
10 |
Расширение тематики «Хабра» дало начало сайту-спутнику — Geektimes, на который переехали непрофильные хабы
11 | и значительная часть контента, не имеющего непосредственного отношения к разработке и программированию.
12 |
Благодарности
13 |
14 | - Спасибо Юрию Баландину, Сергею Коровкину и Павлу Батурину за участие;
15 | - Спасибо Turbomilk за иконки;
16 | - Спасибо Qrator за защиту от DDoS-атак;
17 | - Спасибо CleverPumpkin за удобные мобильные приложения для наших проектов;
18 | - Спасибо АйТи-Лекс за юридическое сопровождение.
19 | - И нам тоже, конечно же, спасибо. За то, что смогли всё это сделать.
20 |
21 |
Обратная связь
22 |
У меня есть вопрос по сайту
23 |
Прежде чем задать вопрос, попробуйте посетить справочный раздел — в нём опубликованы ответы на большинство часто
24 | задаваемых вопросов.
25 |
У меня проблемы. Что делать?
26 |
Мы не сможем решить всех проблем, но если на «Хабре» что-то работает не так, мы стараемся реагировать оперативно — исправляем, дополняем, объясняем. Если вы нашли
27 | ошибку, напишите в нашу службу поддержки.
28 |
У меня есть идея. Как поделиться?
29 |
Если вы знаете, как сделать «Хабр» лучше, напишите в службу поддержки.
30 |
31 | )
32 |
--------------------------------------------------------------------------------
/src/components/InfoHelp.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
7 | - Правила
8 | - Регистрация и приглашения
9 | - Хабрацентр
10 | - Карма и рейтинг
11 | - Настройки
12 | - Хабы
13 | - Лента
14 | - Публикации
15 | - Трекер
16 | - Хабрапочта
17 | - Компании
18 | - Разное
19 |
20 |
21 | )
22 |
--------------------------------------------------------------------------------
/src/components/InfoHelpHabracentre.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 | // TODO React ругается на аттрибуты таблицы: colspan, border, align, valign
4 | export default () => (
5 |
6 |
Это страница вида habrahabr.ru/users/имя_пользователя, которая содержит:
7 |
8 |
9 | - Аватар пользователя, его никнейм и (если указано) настоящее имя.
10 | - Значения кармы и рейтинга, а также занимаемое на текущий момент место в рейтинге.
11 | - Значки пользователя, которые он заработал благодаря своей активности на ресурсе.
12 | - Ссылки на социальные аккаунты, мессенджеры, личные сайты.
13 | - Даты регистрации на ресурсе, получения приглашения и последнего посещения сайта.
14 | - Список хабов, на которые подписан пользователь.
15 | - Иная информация «О себе», которую он пожелал указать.
16 |
17 |
18 |
Ряд информации из профиля выводится на специально созданной плашке автора, которая отображается под каждой публикацией пользователя. Чтобы выбрать, что именно отображать в своей плашке, нужно отметить соответствующие контакты чекбоксом на странице настроек профиля.
19 |
20 |
Как изменить информацию о себе?
21 |
22 |
Очень просто. Авторизируйтесь — ссылка на страницу настроек будет видна в левом меню.
23 |
24 |
Что такое значки?
25 |
26 |
За время своего пребывания пользователи зарабатывают различные значки, которые потом отображаются в хабрацентре. Значки зависят от поведения пользователя, отношения к нему сообщества и его активности на сайте.
27 |
28 |
Некоторые значки являются артефактами и дают своим владельцам дополнительные возможности:
29 |
30 |
31 |
32 | Захабренный |
33 | Пользователь с положительной кармой (больше 0). В зависимости от величины кармы может размещать публикации в различные хабы, писать комментарии и голосовать. Может использовать в комментариях HTML-теги. |
34 |
35 |
36 | Отхабренный |
37 | Пользователь с отрицательной кармой (меньше 0). В зависимости от «глубины погружения» начинает испытывать трудности с комментированием. Более того, не может размещать публикации, голосовать и использовать HTML-теги в комментариях. |
38 |
39 |
40 | Комментатор |
41 | Пользователь, на счету которого имеется более 5 очень полезных или удачных комментариев (с рейтингом более +50 каждый). |
42 |
43 |
44 | Переводчик |
45 | Пользователь, на счету которого имеется более 5 публикаций-переводов (с рейтингом более +50 каждый). По праву гордится своим значком. |
46 |
47 |
48 | Старожил |
49 | Пользователь, зарегистрированный более 3 лет назад и имеющий карму +50 и выше. Может участвовать в ППА. Вес положительного голоса за публикацию равен +2. |
50 |
51 |
52 | Автор |
53 | Пользователь, на счету которого от 10 публикаций, тепло встреченных хабрасообществом (от +50 голосов за каждый). Имеет карму +50 и выше, может участвовать в ППА и получает ещё одно особо секретное преимущество. Вес положительного голоса за публикацию равен +2. |
54 |
55 |
56 | Звезда |
57 | Карандашик подлиннее выдаётся за карму от +50 и 20+ публикаций с рейтингом от +50 баллов каждый. Может всё то же самое, что и «Автор». Вес положительного голоса за публикацию равен +2. |
58 |
59 |
60 | Легенда |
61 | Усовершенствованная версия «Звезды». Самый длинный карандаш, даётся за карму от +50 при 30+ публикациях с рейтингом от +50 каждый. Может всё то же самое, что и «Автор». Вес положительного голоса за публикацию равен +3. |
62 |
63 |
64 | Значки «Автор», «Звезда» и «Легенда» поглощают друг друга в процессе самосовершенствования Автора. |
65 |
66 |
67 | Тролль |
68 | С таким значком на сайте особо нечего делать — он даётся за падение на дно кармической бездны (-100 и ниже). Один шанс стать белым и пушистым всё же есть, но если им вовремя не воспользоваться, то аккаунт может быть заблокирован НЛО без каких-либо уведомлений. Троллем быть фуфуфу, заметите их — не кормите. |
69 |
70 |
71 |
72 | )
73 |
--------------------------------------------------------------------------------
/src/components/InfoHelpHubs.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
7 |
Это разделы, в которых размещены публикации на определённую тематику. Помогают не только удобно структурировать всю информацию на сайте, но и формировать ленту пользователя — подписываться только на те хабы, которые интересны.
8 |
9 |
Как подписаться на хаб
10 |
11 |
Подписаться на хаб (добавить его в свою ленту) можно в центре подписки или на странице со списком всех хабов, нажав на кнопку «Подписаться», которая появляется при наведении на его название. Или же с помощью кнопки «Присоединиться», которая есть в правой верхней части страницы каждого хаба.
12 |
13 |
Кстати, при успешной подписке эта кнопка сменится на «Покинуть» — так можно отписаться от хаба.
14 |
15 |
Есть два основных вида хабов.
16 |
17 |
18 | -
19 | Тематические.
Их тематика наиболее тесно связана с IT. Самые полезные хабы, поэтому их больше всего. Полезны не только читателям в силу своей интересности, но и авторам публикаций — именно написанные в эти хабы публикации могут принести автору добавочное приглашение, поднять рейтинг, а также поправить материальное положение благодаря Программе Поощрения Авторов (ППА).
20 |
21 | Подразделяются на:
22 |
23 | - профильные. Непосредственно связаны с IT. Порог минимальной кармы для создания публикации — от 0 и выше. Хабы отмечены иконкой шестерёнки в общем списке хабов и звездочкой в ниспадающем меню выбора хаба при создании публикации. К участию в ППА принимаются публикации только из этих хабов.
24 | - непрофильные. Не так тесно связаны с IT, поэтому не участвуют в ППА, а минимальный порог кармы — от +5 и выше.
25 |
26 |
27 |
28 | -
29 | Оффтопики.
Связь с тематикой сайта — на грани, но всё же есть. Минимальный порог кармы — от +5 и выше, в случае с хабом «Я пиарюсь» — от +20 и выше.
30 |
31 | В связи с этим у данных хабов есть ряд особенностей:
32 |
33 | - не приносят автору приглашений, рейтинга, не участвуют в ППА;
34 | - не индексируются поисковиками.
35 | - не попадают в раздел «Лучшее»;
36 | - не транслируются в наши сообщества в социальных сетях.
37 |
38 |
39 |
40 |
41 |
Из чего состоят хабы?
42 |
43 |
В каждом тематическом хабе есть подразделы (в виде вкладок) для фильтрации контента:
44 |
45 | - Интересное. Записи, получившие положительную оценку (рейтинг ≥-4) пользователей. Хорошенькое и интересненькое.
46 | - Всё подряд. Все записи хаба (в хронологическом порядке).
47 | - Лучшее. Лучшие публикации хаба (с рейтингом > 50).
48 |
49 |
50 |
Невероятно, но факт: у каждого подраздела каждого раздела каждого хаба есть свой отдельный RSS-фид!
51 |
52 |
Как создать новый хаб?
53 |
54 |
Если вы считаете, что на сайте не хватает какого-то хаба, то предложите его через форму обратной связи. В сопроводительном письме укажите не менее 10 ссылок на публикации, которые на данный момент расположены «не там».
55 |
Как узнать о появлении нового хаба? Через центр подписки на главной странице.
56 |
57 |
Кстати, а кто такие лидеры хаба?
58 |
59 |
В правой части каждого тематического хаба есть специальный блок, в котором выводится список из 10 пользователей. Как несложно догадаться, это те пользователи, которые внесли в развитие хаба наибольший вклад в виде публикаций. Эти пользователи — большие молодцы.
60 |
61 | )
62 |
--------------------------------------------------------------------------------
/src/components/InfoHelpKarma.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 | // TODO React ругается на аттрибуты таблицы: bgcolor
4 |
5 | export default () => (
6 |
7 |
Что такое карма?
8 |
9 |
Карма — это один из механизмов ресурса, позволяющий наделять пользователей правами (или ограничивать их). Чем больше ваша карма — тем больше у вас прав (голосование за комментарии, публикации и карму других пользователей, возможность писать в хаб «Я пиарюсь», и не только), чем меньше карма — тем сильнее на вашем аккаунте будут сказываться некоторые ограничения (невозможность голосовать, писать публикации и комментарии). Подробную зависимость прав аккаунта от значений кармы можно увидеть в таблице ниже.
10 |
11 |
Помните главное: карма — это субъективное отношение каждого, кто за нее проголосовал, к вашему аккаунту. Оно никак не связано с оценкой ваших комментариев или публикаций (их могут оценивать положительно, при этом карму — отрицательно).
12 |
13 |
Положительная карма
14 |
15 |
16 |
17 | Карма |
18 | Действие |
19 |
20 |
21 | ≥ 0 |
22 | Создавать публикации в профильные хабы (только для полноценных аккаунтов) |
23 |
24 |
25 | ≥ 5 |
26 | Создавать публикации в тематические хабы и голосовать за публикации, комментарии, а также за карму других пользователей |
27 |
28 |
29 | ≥ 20 |
30 | Доступна возможность публиковать публикации в «Я пиарюсь» |
31 |
32 |
33 | > 50 |
34 | Начисление одного приглашения (единовременно) |
35 |
36 |
37 |
38 |
Отрицательная карма
39 |
40 |
41 |
42 | Карма |
43 | Действие |
44 |
45 |
46 | От −1 до −10 |
47 | Можно комментировать лишь 1 раз в 5 минут |
48 |
49 |
50 | От −11 до −30 |
51 | 1 комментарий в час |
52 |
53 |
54 | От −31 до −100 |
55 | 1 комментарий в день |
56 |
57 |
58 | От −100 и ниже |
59 | 1 комментарий в неделю и значок «Тролль» |
60 |
61 |
62 |
63 |
От величины кармы напрямую зависит количество ваших голосов за карму, публикации и комментарии других участников сообщества.
64 |
1 единица кармы = 1 голос, который вы можете отдать за карму или публикацию пользователя, и 2 голоса за комментарии.
65 | К примеру, вы не нарушали правила и были интересным автором либо комментатором, что позволило набрать вам +200 единиц кармы (200 человек с кармой ≥5 зашли в ваш профиль и повысили её).
66 |
67 |
Значит, в сутки у вас будет 200 голосов за карму, публикации и 400 голосов за комментарии. Если вы потратите весь заряд за одни сутки, то через 24 часа он восстановится.
68 |
Для некоторых пользователей существуют особые правила — вес их голоса при оценке публикаций отличается от веса голоса остальных членов сообщества.
69 |
70 | Обладатели значков «Автор», «Старожил», «Звезда» в случае положительной оценки публикации добавляют ей +2 пункта рейтинга.
71 |
72 | Обладатели же значка «Легенда» одним голосом добавляют +3 пункта рейтинга.
73 |
74 | Данное правило распространяется только на голосование за публикации и не распространяется на голосование в минус: такой голос за публикацию отнимает −1 пункт рейтинга.
75 |
Помните, что даже написав сотню самых полезных публикаций и искромётных комментариев, набрав +300 кармы, к примеру, вы можете потерять всё это с помощью одного глупого комментария не по теме или ещё какой гадости. Поэтому берегите себя и свою карму.
76 |
77 |
Что такое рейтинг?
78 |
79 |
Еще один параметр, определяющий вес пользователя на ресурсе.
80 |
81 |
Чем больше рейтинг участника, тем выше он находится в общем списке пользователей.
82 |
83 |
Рейтинг - это динамичный показатель, зависящий от активности пользователя на сайте: все плюсы и минусы к публикациям и комментариям прямым образом влияют на величину рейтинга (но не влияют на карму, как отмечалось выше). Если кто-то положительно оценивает ваши публикации и комментарии, то рейтинг будет расти (справедливо и обратное), но если бездействовать, то со временем рейтинг примет нулевое значение.
84 |
85 |
Впрочем, даже если проявлять активность, рейтинг всё равно будет падать: за былые заслуги. Иногда он начинает жить своей жизнью, и это нормально.
86 |
87 |
Наглядный пример. Допустим, вы написали публикацию с рейтингом +100 — это добавило к вашему персональному рейтингу величину Х. Через несколько десятков дней этот самый Х вычтется, тем самым вернув вас на прежнее место.
88 |
89 |
Это явление называется пессимизацией рейтинга и создано для того, чтобы общий рейтинг пользователей был максимально объективным — возглавить его может даже только что пришедший новичок. Вывод простой: чтобы удерживать позицию лидера, нужно постоянно публиковать интересные статьи (которые будут набирать высокий рейтинг).
90 |
91 |
Голосование
92 |
93 |
Выше приведён перечень возможностей в зависимости от кармы — если она у вас будет положительная, то вы сможете голосовать (как когда-то кто-то голосовал за вас). Технически всё просто — в футере каждой публикации есть стрелочки «Вверх» и «Вниз», повышающие и понижающие рейтинг публикации на 1 единицу. У комментариев и ответов стрелки голосования находятся в правой части. Везде можно проголосовать лишь однажды, изменив рейтинг лишь на 1 единицу.
94 |
95 |
Для голосования за карму пользователя нужно либо пройти в его профиль, либо проголосовать со страницы публикации пользователя (показатели пользователя размещены в шапке его публикаций), либо при наведении на никнейм пользователя в комментариях, с помощью всплывающей плашки автора.
96 |
97 |
Стрелки изменения кармы находятся по обе стороны от числа, показывающего нынешний уровень кармы. Карму каждого пользователя можно также изменять лишь на 1 единицу («Вверх» или «Вниз»), но сам полюс оценки можно со временем поменять. То есть, однажды повысив карму кому-то из пользователей, вы сможете потом изменить её на противоположную (если вдруг появится такая необходимость). Само собой, голосовать за свою карму нельзя.
98 |
99 |
Как восстановить аккаунт?
100 |
101 |
Если так получилось, что ваша карма стала отрицательной и вам хотелось бы это исправить — такая возможность есть.
102 |
103 |
Как известно, бороться надо с причиной, а не со следствием. Скорее всего, отрицательная карма является следствием некорректного поведения на сайте, так что комплексный анализ ошибок позволит не наступать на одни и те же грабли в дальнейшем.
104 |
105 |
Ну а потом есть несколько вариантов:
106 |
107 |
108 | - Recovery mode. У пользователей с отрицательной кармой (до −30 включительно) есть шанс вернуться в ряды захабренных — раз в неделю есть возможность написать публикацию или перевод в любой профильный хаб. У таких публикаций будет пометка «Recovery Mode» — если повезёт, то сообщество оценит старания и вытащит пользователя из кармаямы.
109 |
110 | - Reset. Эта опция находится в хабрацентре и позволяет обнулить любую (как положительную, так и сильно отрицательную) карму. Крайняя мера на тот случай, когда уже ничто другое не помогает, или хочется начать «с чистого листа». Но имейте в виду, что воспользоваться этой опцией можно только один раз за всё время регистрации на сайте. Мы даём второй шанс, но только однажды.
111 |
112 |
113 |
Ещё можно попытаться писать восхитительные комментарии, но это вряд ли поможет оперативно выйти из большого минуса.
114 |
115 |
Другие рейтинги
116 |
117 |
Раз уж мы заговорили о рейтингах, то огласим сразу весь список:
118 |
119 | - Рейтинг публикаций
120 | - Рейтинг компаний
121 | - Рейтинг хабов
122 | - Рейтинг людей
123 |
124 |
125 |
В общем и целом принцип работы везде один: чем выше активность, тем выше рейтинг.
126 |
127 | )
128 |
--------------------------------------------------------------------------------
/src/components/InfoHelpLenta.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
Лента — это поток публикаций, настроенный в соответствии с вашими интересами. Собственно, все хабы, на которые вы подписаны — это и есть то, что формирует вашу ленту (если вы залогинены на ресурсе). Настроить ленту под себя за пару минут можно тут.
7 |
8 |
Если же вы любите читать сайт как гость, то по умолчанию вам будет выдаваться лента «Интересное» — это те публикации, которые по оценкам пользователей получили такой статус (их рейтинг больше или равен +5). При этом вы можете переключиться на «Всё подряд» (выводятся по дате публикации) или «Лучшее за сутки / неделю / месяц / все время».
9 |
10 |
Обратите внимание — в таком случае вам показываются публикации из всех существующих хабов, фильтрация ленты работает только для авторизованных пользователей.
11 |
12 |
RSS
13 |
14 |
У каждой из этих лент, включая вашу собственную, есть RSS. Как и у каждого хаба. Ссылку на RSS можно найти в исходном коде страницы ленты. Например:
15 | https://habrahabr.ru/rss/feed/posts/6266e7ec4301addaf92d10eb212b4546
16 |
17 |
Кроме этого, вы можете использовать ключи ?with_hubs=true: и ?with_tags=true:, если вам хочется видеть в RSS еще и хабы и теги публикации соответственно.
18 |
19 | )
20 |
--------------------------------------------------------------------------------
/src/components/InfoHelpOther.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
7 |
8 |
Уж чего-чего, а вот фидов у нас на сайте... в общем, много. Настолько много, что мы даже не стали выносить иконку для каждого из мест. Тем не менее, вы должны знать, что они у нас есть.
9 |
10 |
Самый главный фид (он уникален) — у вашей ленты: https://habrahabr.ru/rss/feed/posts/9714fef01241b028fe113f5f1a700566
11 |
12 |
В остальных местах ссылки на фиды не уникальные — просто знайте, что они у нас есть у:
13 |
14 | - каждого тематического хаба
15 | - каждого раздела хаба (всё/публикации/q&a)
16 | - каждого подраздела хаба (захабренные/новые/отхабренные)
17 | - раздела лучших публикаций (за сутки/неделю/месяц/всё время)
18 | - раздела публикации (тематические и корпоративные)
19 | - каждого результата поиска
20 | - каждого корпоративного блога
21 | - каждого тега к статье
22 | - каждой публикации
23 |
24 |
25 |
26 |
Горячие клавиши
27 |
Для тех, кто привык осуществлять навигацию по сайтам с помощью клавиатуры, мы прописали ряд сочетаний. Если они вам мешают, вы можете отключить их в настройках профиля.
28 |
29 |
Страницы со списком публикаций поиска и так далее
30 |
31 |
32 | - j — переход к следующему элементу списка
33 | - k — переход к предыдущему элементу списка
34 | - h — прокрутка в самый верх страницы
35 | - l — прокрутка в самый низ страницы
36 | - o — открыть выбранную публикацию
37 |
38 |
39 |
Страница публикации:
40 |
41 |
42 | - c — написание нового комментария: прокрутка к форме написания комментария с установкой фокуса в неё
43 | - r — обновление/подгрузка комментариев
44 | - t — отслеживать новые комментарии в трекере
45 | - m — присылать уведомления о новых комментариях на почту
46 | - f — переход к следующему непрочитанному комментарию (с пометкой комментария как прочитанный)
47 | - k — переход к предыдущему непрочитанному комментарию
48 | - j — переход к следующему непрочитанному комментарию
49 |
50 |
51 |
Вообще все страницы
52 |
53 |
54 | - CTRL/ALT + Enter — отправка данных из формы, в которой находится курсор (поле комментариев, поиск и так далее)
55 | - / — прокрутка к полю поиска с установкой фокуса на него
56 | - ESC — закрытие левой навигационной панели
57 |
58 |
59 |
А ниже просто идёт всякая всячина, которую кто-то когда-то придумал.
60 |
61 |
Кодекс авторов «Хабрахабра»
62 |
63 |
Это не документ, которого нужно строго придерживаться. Это вообще не документ. Это правила, которые соблюдают некоторые авторы на ресурсе.
64 |
65 | - Я стремлюсь создавать авторские материалы и уходить от перепечатки с других сайтов.
66 | - Публикуя материалы других авторов (графику, текст), я всегда привожу ссылки на источники.
67 | - Я не создаю глупых комментариев с содержанием «+1», «ф топку», «афтар жжот».
68 | - Я отказываюсь от употребления матерных слов и оскорблений на страницах ресурса.
69 | - Я прикладываю максимум усилий для того, чтобы мои тексты были написаны без ошибок.
70 | - Я уважаю администрацию и пользователей ресурса, не унижаю и не оскорбляю их — я здесь не для этого.
71 | - При споре с кем-либо на страницах ресурса я стараюсь не раздувать конфликт, а самостоятельно по внутренней переписке решить проблему.
72 | - Если мне не удалось разрешить какой-либо конфликт, я не призываю пользователей к активному противодействию и не произвожу его самостоятельно.
73 | - Я сам решаю, публиковать или не публиковать материалы на ресурсе, и не требую за это денег.
74 | - В случае необходимости я помогаю новичкам на ресурсе.
75 | - Я пользуюсь поиском для уточнения, был ли подготовленный мной материал опубликован на ресурсе ранее. Если это произошло, я дополняю его в комментариях.
76 | - Каждым своим действием на ресурсе я стремлюсь добавить порядка, а не внести хаоса.
77 | - Своими действиями я не собираюсь способствовать разрушению сообщества или его дискредитации.
78 | - Я не клянчу карму, я отношусь к изменениям рейтинга спокойно, но вместе с тем стараюсь учесть конструктивную критику и пожелания.
79 | - Я — позитивен. Даже когда вокруг всё плохо, я найду выход из сложившейся ситуации и сделаю лучше.
80 | - Я понимаю, что Хабрахабр является сообществом людей с различными интересами, и если какая-то тема мне не интересна, я не мешаю другим ее обсуждать.
81 | - Я действую в согласии с настоящим кодексом и считаю, что только при соответствии настоящему кодексу ресурс будет настоящим социальным новостным сайтом, растущим и развивающимся.
82 |
83 |
84 |
Хабраэтикет
85 |
86 |
Это не рекомендации для обязательного выполнения, это — правила этикета, придерживаться которых совсем несложно.
87 |
88 | - Сетевой этикет — он и на Хабре сетевой этикет.
89 | - Уважайте мнение других. Оно не обязано совпадать с вашим.
90 | - Откажитесь от постинга сообщений, направленных лишь на увеличение Хабрасилы. Стремитесь просто писать интереснее и лучше.
91 | - Аргументированная публикация, даже если она противоположна вашему мнению, не должна получать минус. Человек не обязан подстраиваться под ваши вкусы.
92 | - Если схожие темы неоднократно поднимаются под разными предлогами, это не значит, что надо ставить минус. Это лишь значит, что проблема до сих пор не решена.
93 | - Каждый автор имеет свою индивидуальность, потому если вы уже где-то видели подобную статью, это не значит, что в сообщении нет ничего нового и интересного. Вчитайтесь и вдумайтесь — поймите авторское мнение.
94 | - Изменения кармы несёт гораздо большую ответственность, чем выставление оценки комментарию. 1-2 комментария не должны становиться причиной для занижения кармы.
95 | - Не злоупотребляйте своей возможностью голосования. Необходимо понимать, что минус сильно отличается от плюса — минус угнетает человека, а не развивает его. Ставьте плюсы, когда вам что-то нравится, но подумайте, прежде чем ставить минус, если что-то не понравилось.
96 | - Первый комментарий — это не единственный комментарий в теме. Прежде чем ставить ему оценку, прочитайте ещё парочку.
97 | - Минус — это не аргумент, и, тем более, не контраргумент.
98 | - Не стоит делать того, что не принято в цивилизованном обществе, противоречит законам, морали и этике.
99 | - Не делай другим то, что не хочешь получить от них сам. Поставьте себя на место человека, с которым общаетесь. Отстаивайте свою точку зрения, но не оскорбляйте окружающих.
100 | - Помогайте другим там, где вы это можете делать.
101 |
102 |
103 |
Хабразависимость
104 |
105 |
Хабразависимость — тяжёлая форма психического расстройства, начинающаяся с регистрации на Хабрахабре.
106 |
107 |
Симптомы:
108 |
109 | - Неудержимое желание посещать Хабрахабр;
110 | - Перепады настроения прямо пропорциональны изменению кармы;
111 | - Ежедневное посещение страницы рейтинга;
112 | - Появление эйфории при попадании публикации на главную;
113 | - Поиск стрелочек вверх и вниз на комментариях в ЖЖ;
114 | - Стойкое ощущение, что за тобой следит НЛО.
115 |
116 |
(Список не полон и может расширяться)
117 |
118 |
Лечение: на данный момент эффективные методы лечения науке неизвестны.
119 |
120 |
Хабраэффект
121 |
122 |
Хабраэффект — резкое увеличение посещаемости сайта после того, как ссылка на данный ресурс появилась на Хабрахабре.
123 |
124 |
Бяка данного эффекта заключается в том, что из-за резкого повышения посещаемости сайта генерируется огромный трафик, превращаясь в неумышленную, но тем не менее небезобидную DoS-атаку.
125 |
126 |
Хабраэффект чаще всего наблюдается в течение нескольких десятков минут, но может затянуться и до нескольких часов. Наплыв пользователей может не проходить и в течение дня — двух, пока новость с адресом ресурса не пропадёт с главной страницы Хабра.
127 |
128 |
Бытует мнение, что хабраэффекту подвержены только новые и не раскрученные сайты с малыми мощностями, но это не так. В своё время хабраэффект смог «положить на лопатки» немало крупных проектов — обо всех случаях можно узнать из несложного поискового запроса на Хабре.
129 |
130 |
131 |
API
132 |
133 |
У «Хабрахабра» есть непубличный API, доступ к которому предоставляется только по запросу через форму обратной связи.
134 |
135 |
136 | )
137 |
--------------------------------------------------------------------------------
/src/components/InfoHelpPosts.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 | import styled from 'styled-components'
4 |
5 | const InfoHelpPosts = () => (
6 |
7 |
Самое важное, что есть на сайте — это публикации. Создавать их могут пользователи с полноценными аккаунтами и положительной кармой (для ряда хабов входной порог по карме может отличаться).
8 |
9 |
Создание публикации
10 |
11 |
Сам процесс создания публикации довольно прост:
12 |
13 | - кликните по иконке карандаша в левом меню — {window.location.origin}/topic/add/;
14 | - выберите поток, в который будет размещена публикация;
15 | - выберите хаб, лучше всего подходящий по тематике (или нескольких хабов);
16 | - если ваша публикация является обучающей, уроком или how-to — отметьте чекбокс «Обучающий материал», это поможет визуально выделить ее среди прочих;
17 | - дайте публикации понятный заголовок, заполните тело публикации, используя нужные теги или markdown-разметку для форматирования текста, и не забудьте указать метки;
18 | - при желании — добавьте опрос с вариантами ответа;
19 | - c помощью кнопки «Предпросмотр» оцените то, что у вас получилось (возможно, где-то не закрыт тег, не вставилась картинка или еще что-то);
20 | - если всё в порядке — нажмите зеленую кнопку «Опубликовать»;
21 | - если захочется внести в публикацию какие-то изменения — воспользуйтесь иконкой карандаша справа от её заголовка, это позволит отредактировать ее или убрать ее в черновики.
22 |
23 |
24 |
Черновики видны только вам (о статусе черновика говорит иконка замка слева от заголовка публикации).
25 |
26 |
Перевод
27 |
28 |
Если нажать на слово «Публикацию» во фразе «Хочу опубликовать публикацию», то ниспадающее меню предложит вам выбрать второй доступный для создания вид записи — «Перевод». Механизм создания тот же, что и у публикации, но есть два дополнительных поля — «Автор оригинала» (тут надо указать имя автора оригинального текста) и «Ссылка на оригинал» (здесь — URL страницы оригинала).
29 |
30 |
Признаки хорошей и плохой публикации
31 |
Хорошая публикация:
32 |
- Содержит авторский контент;
33 | - Удобна для чтения, разбита на абзацы и в целом хорошо отформатирована. Картинки залиты на Habrastorage;
34 | - Написана максимально грамотным для индивида русским языком;
35 | - Не содержит того, что есть в плохих публикациях.
36 |
37 |
38 |
Плохая публикация:
39 |
- Имеет кричащий заголовок вида «Шок! ВИДЕО! ВИРУСЫ В МАКАХ!»;
40 | - Переполнена грамматическими и орфографическими ошибками, игнорирует правила русского языка в общем;
41 | - Содержит слова из «падонкаффского» сленга и прочую нечисть;
42 | - Содержит изображения с нестабильных фотохостингов;
43 | - Состоит из информации с других ресурсов;
44 | - Является жалобой на что-либо;
45 | - Содержит реферальные ссылки на что угодно;
46 | - Содержит запрещённый или просто нелицеприятный контент;
47 | - Является рекламой своего или чужого проекта, сервиса, приложения, сайта, etc.
48 |
49 |
50 |
51 |
При написании публикаций и комментариев можно использовать следующие html- и не совсем html-теги:
52 |
53 |
54 |
55 |
Стандартные
56 |
57 |
58 | Тег |
59 | Описание |
60 |
61 |
62 |
63 | <h1></h1>...<h4></h4>
64 | |
65 |
66 | Заголовки разного уровня.
67 | <h1>Заголовок первого уровня</h1>...<h4>Заголовок четвертого уровня</h4>
68 | |
69 |
70 |
71 |
72 | <img/> |
73 |
74 | Вставка изображения, в атрибуте src нужно указывать полный путь к изображению. Возможно выравнивание картинки атрибутом align .
75 | <img src="" alt="image alt" align="left" />
76 | |
77 |
78 |
79 |
80 | <a></a> |
81 |
82 | Вставка ссылки, в атрибуте href указывается желаемый интернет-адрес или якорь (anchor) для навигации по странице.
83 | <a to="http://your_link_path.ru">Текст ссылки</a>
84 | |
85 |
86 |
87 |
88 | <anchor></anchor> |
89 |
90 | Тег для указания якоря. Для вызова используйте тег вставки ссылок.
91 | <a to="#example">Example</a>
92 | |
93 |
94 |
95 |
96 | <strong></strong> |
97 |
98 | Выделение важного текста, на странице выделяется жирным начертанием. Также возможно использование альтернативного тега <b></b>
99 | <strong>Жирное начертание</strong>
100 | |
101 |
102 |
103 |
104 | <em></em> |
105 |
106 | Выделение важного текста, на странице выделяется курсивом. Также возможно использование альтернативного тега <i></i>
107 | <em>Курсивное начертание</em>
108 | |
109 |
110 |
111 |
112 | <strike></strike> |
113 |
114 | Текст между этими тегами будет отображаться как зачеркнутый. Также возможно использование альтернативного тега <s></s>
115 | <strike>Зачеркнутый текст</strike>
116 | |
117 |
118 |
119 |
120 | <u></u> |
121 |
122 | Текст между этими тегами будет отображаться как подчеркнутый.
123 | <u>Подчеркнутый текст</u>
124 | |
125 |
126 |
127 |
128 | <hr/> |
129 |
130 | Тег для вставки горизонтальной линии.
131 | <hr/>
132 | |
133 |
134 |
135 |
136 | <blockquote></blockquote> |
137 |
138 | Используйте этот тег для выделения цитат.
139 | <blockquote>Текст цитаты</blockquote>
140 | |
141 |
142 |
143 |
144 |
145 | <table></table>
146 | |
147 |
148 | Набор тегов для создания таблицы. Тег <td> обозначает ячейку таблицы, тег <th> - ячейку в заголовке, <tr> - строчку таблицы. Все содержимое таблицы помещайте в тег <table> .
149 |
150 | <table> <tr> <th>Колонка 1</th> <th>Колонка 2</th> <th>Колонка 3</th> </tr> <tr> <td>Ячейка 1</td> <td>Ячейка 2</td> <td>Ячейка 3</td> </tr> <tr> <td>Ячейка 1</td> <td>Ячейка 2</td> <td>Ячейка 3</td> </tr> </table>
151 | |
152 |
153 |
154 |
155 | <sup></sup> , <sub></sub> |
156 |
157 | Текст, заключенный в тег <sup> отображается в виде надстрочного, <sub> - в виде подстрочного.
158 | <sup>надстрочный</sup>, <sub>подстрочный</sub>
159 | |
160 |
161 |
162 |
163 | <abbr></abbr>
|
164 |
165 | Тегом <abbr> выделяется аббревиатура, в атрибуте title="" указывайте её расшифровку. Используйте тег <acronym> для устоявшихся аббревиатур.
166 | <abbr title="ABBR">Рашифровка аббревиатуры</abbr>
167 | <acronym title="Accronym">Рашифровка аббревиатуры</acronym>
168 | |
169 |
170 |
171 |
172 | <pre></pre> |
173 |
174 | Текст в теге <pre> не форматируется автоматически.
175 | <pre>Неформатированный текст</pre>
176 | |
177 |
178 |
179 |
180 | <nobr></nobr> |
181 |
182 | Текст, помещенный в тег <nobr> , не переносится на странице; для принудительного переноса текста используйте тег <br/> ; для аккуратного выравнивания изображений используйте атрибут clear="all|left||right" в теге <br /> .
183 | <nobr>Текст без переносов</nobr>, <br clear="all|left||right" />
184 | |
185 |
186 |
187 |
188 |
189 |
190 | <ul></ul>
191 |
192 | |
193 |
194 | Ненумерованный список; каждый элемент списка задается тегом <li> , набор элементов списка помещайте в тег <ul> .
195 | <ul> <li>Пункт 1</li> <li>Пункт 2</li> <li>Пункт 3</li> </ul>
196 | |
197 |
198 |
199 |
200 |
201 | <ol></ol>
202 | |
203 |
204 | Нумерованный список; каждый элемент списка задается тегом <li>, набор элементов списка помещайте в тег <ol>.
205 | <ol> <li>Пункт 1</li> <li>Пункт 2</li> <li>Пункт 3</li> </ol>
206 | |
207 |
208 |
209 |
210 |
Теги Хабрахабра
211 |
212 |
213 | Тег |
214 | Описание |
215 |
216 |
217 | <cut/>
218 |
219 | |
220 | Используется только в текстах публикаций, скрывает под кат часть текста, следующую за тегом (появится кнопка с текстом «Читать дальше»). Чтобы изменить текст в кнопке, используйте аттрибут text="..."
221 | <cut/>, <cut text="Ваш текст"/>
222 | |
223 |
224 |
225 |
226 | <source></source>
227 | |
228 | Подсвечивает исходный код. Для поддержки конккретного синтаксиса, используйте аттрибут lang=""
229 | <source lang="javascript">Исходный код</source>
230 | |
231 |
232 |
233 |
234 | <oembed></oembed> |
235 |
236 | Вставка интерактивного слайд-шоу. Пока поддерживается только сервис Slideshare.net и Scribd.com.
237 | <oembed>http://slideshare.net/</oembed>
238 | |
239 |
240 |
241 |
242 | <spoiler></spoiler> |
243 |
244 | Вставка спойлера (разворачиваемый блок информации). Чтобы изменить текст заголовка спойлера используйте аттрибут title="…"
245 | <spoiler title="Заголовок спойлера">Содержимое спойлера</spoiler>
246 | |
247 |
248 |
249 |
250 | @username |
251 |
252 | Выводит имя пользователя в тексте и отправляет пользователю уведомление о том, что его упомянули в публикации/комментарии. Вы можете использовать конструкцию @username , где username — это имя пользователя.
253 | @username
254 | |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
Вы также можете добавлять в свои публикации математические формулы, используя язык разметки LaTeX.
262 |
Для отрисовки формул на странице мы используем библиотеку MathJax.
263 |
264 |
Чтобы добавить формулу нажмите на иконку Σ
в тулбаре. В появившемся модальном окне выберите строчный или блочный тип формулы.
265 |
266 | - cтрочная формула используется для вставки формулы в абзац текста
267 | - блочная формула используется для вставки формулы с новой строки
268 |
269 |
270 |
После составления формулы нажмите на кнопку «Добавить формулу» и она появится в тексте публикации.
271 |
272 |
ППА
273 |
Аббревиатура «ППА» на Хабрахабре расшифровывается как Программа Поощрения Авторов. Помимо признания аудитории, авторы могут получать денежное вознаграждение за хорошие публикации — очевидно же!
274 |
275 |
В программе могут принимать участие пользователи, обладающие хотя бы одним из значков: «Автор», «Звезда», «Легенда» и «Старожил». А дальше, всё, что надо — просто размещать интересные публикации или переводы в профильные хабы, не более того. Более подробно узнать о ППА можно на отдельной странице.
276 |
277 |
278 |
279 |
280 | )
281 |
282 | export default styled(InfoHelpPosts)`
283 | .table{
284 | table-layout: fixed;
285 | }
286 | .table__head th{
287 | background-color: #eaecea!important;
288 | }
289 | .table__column_html{
290 | width: 25%;
291 | }
292 | .table__column_desc{
293 | width: 75%;
294 | }
295 | `
296 |
--------------------------------------------------------------------------------
/src/components/InfoHelpRegistration.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
Для регистрации на ресурсе используется единый аккаунт TM ID. Зарегистрировавшись, вы сможете входить на «Хабрахабр», Geektimes, «Тостер», «Фрилансим» в 1 клик по кнопке «Войти с TM ID». На ресурсах общие никнейм и почта, поэтому учтите, что просьба изменить никнейм или почту приведет к их смене на всех этих сайтах, кроме «Фрилансим».
7 |
8 |
Это же касается и удаления аккаунта — при запросе на удаление с «Хабрахабра», Geektimes или «Тостера» аккаунт будет удален со всех этих ресурсов.
9 |
10 |
Права
11 |
12 |
Права вашего аккаунта зависят от цели вашего пребывания на ресурсе.
13 |
14 |
15 | - ReadOnly — базовый аккаунт, доступен сразу после регистрации. Позволяет читать материалы, опубликованные на сайте, добавлять их в «Избранное», формировать собственную ленту по интересам. Голосовать за что-либо, писать с него личные сообщения или публикации сразу на сайт нельзя — только в Песочницу.
16 | ReadOnly-аккаунт имеет возможность писать комментарии к статьям в течение 10 дней с момента их публикации.
17 | Комментарии попадают на модерацию к авторам публикаций и модераторам сайта. Как только один из ваших комментариев будет одобрен, аккаунт автоматически переводится в статус Read&Comment.
18 |
19 | - Read&Comment — тип аккаунта, обозначающий, что у вас уже есть как минимум один опубликованный комментарий. Профиль пользователя выглядит как и у полноценного аккаунта — есть рейтинг и карма, за которую другие пользователи могут голосовать с некоторым ограничением: карма пользователя не имеющего публикации на сайте не может подняться выше +4. Появляется возможность писать личные сообщения другим участникам сообщества.
20 | Комментарии начинают появляться на сайте сразу, без модерации, как только пользователь получает 10 одобрений от 10 разных авторов или модераторов.
21 | Голосование на данном этапе еще не доступно, а публикации по-прежнему можно публиковать только в Песочницу.
22 |
23 | - Полноценный аккаунт — получен с помощью приглашения и позволяет писать публикации напрямую на сайт. До тех пор, пока у вас нет ни одной публикации на сайте ваша карма не может подняться выше +4. Данное ограничение снимается сразу после написания первой публикации.
24 |
25 |
26 |
Приглашение
27 |
28 |
Получить приглашение не так сложно, как кажется. Достаточно сделать что-то из следующего:
29 |
30 |
31 | - написать публикацию в Песочницу. Если она пройдет проверку модератором на соответствие тематике сайта, то или сразу получит приглашение от модераторов, или окажется в общей Песочнице, которую читают пользователи. И кто-то вполне сможет выдать вам приглашение, после чего аккаунт станет полноценным.
32 |
33 | - быть сотрудником компании, которая ведет на «Хабре» корпоративный блог, и писать для него. В таких случаях администратор блога может использовать приглашения компании для перевода вашего аккаунта в полноценный.
34 |
35 | - быть другом пользователя, у которого есть приглашение. Такой пользователь может самостоятельно использовать своё приглашения для вашего аккаунта, будь то ReadOnly или Read&Comment (только если ваш аккаунт в ReadOnly не потому, что вы нарушали правила).
36 |
37 | - выиграть приглашение в конкурсах, временами проводимых в наших официальных группах ВКонтакте, Twitter или Facebook.
38 |
39 |
40 |
41 |
Некоторые сомнительные ресурсы предлагают продажу приглашений на «Хабр», но этим стоит пользоваться только в случаях, если хочется и заплатить кому-то, и всё равно остаться без аккаунта. Будьте бдительны.
42 |
43 |
А вот способы заработать приглашение для друга (или просто про запас), если у вас уже есть полноценный аккаунт:
44 |
45 |
46 | - набрать 50 единиц кармы (даётся 1 приглашение единовременно, даже если карму после этого понизят — приглашение остаётся на балансе аккаунта);
47 |
48 | - написать публикацию, которая после окончания срока голосования получит рейтинг выше +50. За каждую такую публикацию, если это не хаб-оффтопик, выдаётся 1 приглашение.
49 |
50 |
51 |
Песочница
52 |
53 |
Раздел, куда попадают публикации от желающих получить приглашение. Перед попаданием в общую Песочницу каждая публикация проходит проверку модератором на соответствие правилам, тематике и общую адекватность.
54 |
55 |
Вот что можно сразу не писать в Песочницу, чтобы сэкономить время:
56 |
57 |
58 | - публикации, которые не имеют отношения к тематике сайта;
59 | - уже где-то опубликованные тексты;
60 | - публикации, нарушающие общие правила сайта;
61 | - новости и анонсы;
62 | - статьи рекламного характера и PR-тексты;
63 | - вопросы и просьбы о помощи (ведь есть toster.ru).
64 |
65 |
66 |
Проверка модератором может длиться долгое время (но вы можете написать в Песочницу более одной публикации). Даже очень долгое время. После проверки вам на почту придет письмо о вердикте.
67 |
68 |
Вердиктов может быть три:
69 |
70 |
71 | - модератору понравилась публикация и он сам выдал за неё приглашение;
72 | - модератор счел публикацию подходящей и просто пропустил в общую Песочницу, оставив решение о выдаче приглашения за пользователями сайта;
73 | - модератор отклонил публикацию и сообщил, почему. Или не сообщил, тут уж как повезет.
74 |
75 |
76 |
Обратите внимание — если публикация отклоняется совсем, мы более не храним у себя её текст, поэтому заранее дублируйте важные сведения у себя.
77 |
78 |
Как видите, Песочница не так страшна, как вам могли рассказывать.
79 |
80 |
Приятный бонус — если вы успешно проходите Песочницу на «Хабре», то получаете ещё и приглашение на Geektimes. Песочница же на Geektimes приносит приглашения только на Geektimes.
81 |
82 | )
83 |
--------------------------------------------------------------------------------
/src/components/InfoHelpRules.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default () => (
4 |
5 |
Последнее редактирование — 16 мая 2016.
6 |
7 |
Обычно IT-специалисты и интересующиеся данной сферой — это люди культурные, уважающие не только себя, но и собеседников и читателей. Для того чтобы ресурс оставался площадкой для общения таких людей, существуют правила, за нарушение которых модераторы могут понизить права аккаунта до ReadOnly.
8 |
9 |
Вот список того, чего на ресурсе делать не следует
10 |
11 |
12 | - Рекламировать собственные ресурсы в обход правил. Для самопиара или официального продвижения своих продуктов и сервисов в потоке «Разное» у нас есть специальный хаб «Я пиарюсь» и корпоративные блоги. Попытки поместить такую рекламу вне указанных разделов влекут за собой понижение прав аккаунта. На первый раз — временно.
13 | Для рекламы и анонсов событий или мероприятий следует использовать возможности корпоративных блогов.
14 | Обратите внимание — не имеет значения, рекламируете ли вы платный продукт или бесплатный. Если это OpenSource-решение, достаточно ссылки на GitHub, ссылка же на собственный сайт проекта — это уже реклама. Для продвижения youtube-каналов и групп в соцсетях следует также использовать «Я пиарюсь».
15 | Однако, в настройках профиля пользователя или компании вы можете указать несколько ссылок на собственные ресурсы и социальные аккаунты, которые будут отображаться в вашем профиле, а также в блоке с информацией об авторе после текста публикации.
16 |
17 | - Заниматься копипастом и кросспостом. Мы всячески приветствуем интересный и полезный сообществу контент, но только если он оригинальный. Поэтому не следует копипастить на «Хабр» тексты, которые ранее были опубликованы на других ресурсах (даже если вы — автор такого текста).
18 |
19 | - Путать «Хабр» с Твиттером. Односложные публикации вида «Смотрите, какую я нашел ссылку», «Chrome обновился, вот тут чейнджлог» и подобное не приветствуются.
20 | Даже если новость изначально короткая, постарайтесь сопроводить её развёрнутым комментарием.
21 |
22 | - Путать «Хабр» с жалобной книгой. Если у вас проблемы с сотовым оператором, с провайдером интернета или хостинга, или с чем-то ещё, всегда можно связаться со службой поддержки нужного вам ресурса. Или с компетентными органами. Но не следует использовать «Хабр» как рупор, дабы рассказать всем о постигшей вас ситуации.
23 |
24 | - Инициировать политические дискуссии и участвовать в них. Тематика нашего ресурса определена довольно чётко. Для рассуждений о политике есть куда более подходящие сайты. Но не «Хабр».
25 |
26 | - Пытаться собирать средства на проекты. Здесь тоже всё просто — для сбора средств существуют специально созданные для этого площадки.
27 |
28 | - Постоянно использовать смайлики, коверкать слова, игнорировать правила русского языка. Даже если русский язык был не самым вашим любимым предметом в школе или не является родным — проверка орфографии в браузере у вас наверняка есть, не стоит ею пренебрегать. Это сохранит как вашу карму от минусов, так и ваш аккаунт.
29 |
30 | - Оскорблять других пользователей, не следить за эмоциями. Мат, оскорбления, переходы на личности, эвфемизмы, троллинг — хорошие способы быстро и надежно сменить текущий статус аккаунта на ReadOnly.
31 |
32 | - Создавать виртуалов. Всегда приятно поговорить с умным человеком, но создавать для этого добавочные аккаунты и накручивать с них карму и голоса за публикации не стоит.
33 |
34 |
35 |
Список нарушений остаётся открытым, потому что всегда можно придумать что-то, не описанное выше. В таких случаях модераторы руководствуются здравым смыслом и собственным чувством прекрасного. Обсуждать их решения и создавать на эту темы агитационные публикации не стоит — если они кого-то забанили, значит, у них была довольно веская причина.
36 |
37 |
Как видите, ничего сложного в правилах нет, и мы будем рады, если вы будете их соблюдать.
38 |
39 | );
40 |
--------------------------------------------------------------------------------
/src/components/InfoHelpSettings.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | export default () => (
5 |
6 |
Настроить у нас можно вот что:
7 |
8 |
Профиль
9 |
Именно эта страница поможет установить аватар, задать отображаемое имя, написать «О себе» и указать контакты в социальных сетях. Тут же настраиваются ссылки, которые будут отображаться в вашей панели автора публикаций.
10 |
Никнейм самостоятельно не меняется, для этого нужно обратиться в службу поддержки с темой «Смена данных»
11 |
12 |
Аккаунт
13 |
По клику на эту вкладку произойдет редирект на https://id.tmtm.ru/settings/ — так и задумано. Здесь можно сменить свой пароль для TM ID, указать новую почту или привязать к аккаунту профили социальных сетей для авторизации в 1 клик.
14 |
15 |
Приватность
16 |
Если вы хотите, чтобы вам в личные сообщения могли писать только те, на кого вы подписаны, а не все подряд — вам помогут настройки с этой вкладки. Также здесь можно настроить, кому именно показывать вашу активность на ресурсе в трекере и указанные в профиле контакты.
17 |
18 |
Уведомления
19 |
Всё, что связано с уведомлениями, которые сайт посылает вам на почту или в трекер.
20 | Обратите внимание, настройка дайджеста интересных публикаций по вашим тегам находится на этой же странице.
21 |
22 |
Приложения
23 |
Отображает список приложений, в которых выполнен вход, используя логин на сайте TM ID.
Также выводит список ваших приложений и их ключей, для которых есть доступ к API сайта habr/ahabr/.
24 |
25 |
Разные
26 |
У нас есть горячие клавиши и панель обновления комментариев, пользоваться ими или нет — можно решить на этой вкладке. Здесь же пользователи со значками «Легенда» могут отключить отображение рекламы на ресурсе.
27 |
28 | )
29 |
--------------------------------------------------------------------------------
/src/components/MainNavBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router'
3 | import SearchForm from './SearchForm';
4 | import UserNavBar from './UserNavBar';
5 |
6 | const MainNavBar = () => (
7 |
8 |
9 |
10 |
16 |
17 |
18 | -
19 | Публикации
20 |
21 | -
22 | Хабы
23 |
24 | -
25 | Компании
26 |
27 | -
28 | Пользователи
29 |
30 | -
31 | Песочница
32 |
33 |
34 |
35 |
36 |
37 |
38 | );
39 |
40 | export default MainNavBar;
41 |
--------------------------------------------------------------------------------
/src/components/NotFound.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { Link } from 'react-router'
3 | import Helmet from 'react-helmet'
4 |
5 | class NotFound extends Component {
6 | componentWillMount() {
7 | document.body.style.display = 'none'
8 | }
9 |
10 | componentDidMount() {
11 | // HACK стили подключаются в Helmet после рендеринга страницы
12 | // TODO: https://habrahabr.ru/post/322084/#comment_10266132
13 | setTimeout(() => (document.body.style.display = 'block'), 100)
14 | }
15 |
16 | render() {
17 | return (
18 |
19 |
23 |
24 |
25 |
26 |

27 |
28 |
29 |
30 |
Страница не найдена
31 |
Страница устарела, была удалена или не существовала вовсе
32 |
33 |
34 | Вернуться на главную
35 |
36 |
37 |
38 | )
39 | }
40 | }
41 |
42 | export default NotFound
43 |
--------------------------------------------------------------------------------
/src/components/PostFull.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 | import { connect } from 'react-redux'
4 | import { createSelector } from 'reselect'
5 |
6 | import { urlencode } from '../utils'
7 |
8 | import PostHeader from './PostHeader'
9 | import PostInfoPanel from './PostInfoPanel'
10 | import FormAdminCauses from './FormAdminCauses'
11 | import PostType from './PostType'
12 | import AuthorInfoByCompany from './AuthorInfoByCompany'
13 | import AuthorInfo from './AuthorInfo'
14 |
15 | const PostFull = ({ id, published, flow, hubs, title, author, company, tags, content, viewsCount, favoritesCount }) => (
16 |
17 |
{/* TODO убрать, добавил для отступа, пока не реализован PageHeader */}
18 |
19 |
20 |
21 |
22 |
{content}
23 | { !!tags && tags.length > 0 &&
24 |
25 |
26 | { tags.map(tag => - {tag}
)}
27 |
28 |
29 | }
30 |
31 |
32 |
33 |
34 |
35 |
36 | { !!company ?
:
}
37 |
38 |
39 |
40 | )
41 |
42 | const getPostId = (state, props) =>
43 | parseInt(props.params.postId, 10)
44 |
45 | const getPosts = (state) =>
46 | state.posts
47 |
48 | const getPost = createSelector(
49 | [getPosts, getPostId],
50 | (posts, postId) =>
51 | posts.find(element =>
52 | element.id === postId)
53 | )
54 |
55 | const mapStateToProps = (state, ownProps) => {
56 | const post = getPost(state, ownProps)
57 | return {...post}
58 | }
59 |
60 | const mapDispatchToProps = (dispatch) => {
61 | return {}
62 | }
63 |
64 | export default connect(mapStateToProps, mapDispatchToProps)(PostFull)
65 |
--------------------------------------------------------------------------------
/src/components/PostHeader.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | import { ga, formatDateTime } from '../utils'
5 |
6 | // TODO получать flow в props, как объект (нужна нормализация данных)
7 | // TODO хаб "Блок компании Рога и копыта" для собственнных хабов компании
8 | // TODO флажки к названию: Tutorial, Recovery mode, Из песочницы, Перевод
9 | // TODO кнопка редактирования для собственных статей
10 |
11 | const PostHeader = ({ isTeaser, id, title, published, flow, hubs }) => (
12 |
13 |
{formatDateTime(published)}
14 |
15 | { isTeaser ?
{flow.name} → {title}
: {title} }
16 |
17 |
{/* TODO добавить запятые между элементами списка посредством CSS */}
18 | {/* TODO обернуть каждый хаб в
для отображения .profiled_hub */}
19 | {/* hub.isProfiled && * */}
20 | {hubs.map(hub =>
21 | {hub.name}
22 | )}
23 |
24 |
25 | )
26 |
27 | export default PostHeader
28 |
--------------------------------------------------------------------------------
/src/components/PostInfoPanel.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | import { ga } from '../utils'
5 |
6 | // TODO через трое суток вводится запрет на голосование и отображаются результаты
7 |
8 | // TODO format viewsCount & favoritesCount
9 |
10 | // TODO исправить выравнивание "-" между стрелочек голосования за статью
11 |
12 | const PostInfoPanel = ({ id, author, viewsCount, favoritesCount, isTeaser }) => {
13 |
14 | const postsAddToFavorites = (event) => {
15 | // TODO posts_add_to_favorite}(this, '2', id)
16 | alert('postsAddToFavorite')
17 | }
18 |
19 | const postsVotePlus = (event) => {
20 | // TODO posts_vote(this, id, '2', 1)
21 | alert('postsVotePlus')
22 | ga('voting_location', 'plus', window.location.href)
23 | }
24 |
25 | const postsVoteMinus = (event) => {
26 | // TODO posts_vote(this, id, '2', -1)
27 | alert('postsVoteMinus')
28 | ga('voting_location', 'minus', window.location.href)
29 | }
30 |
31 | const postsVoteZero = (event) => {
32 | // TODO posts_vote(this, id, '2', 0)
33 | alert('postsVoteZero')
34 | ga('voting_location', 'zero', window.location.href)
35 | }
36 |
37 | return (
38 |
{/* убрал js-user_ */}
39 |
40 | -
41 |
42 |
45 |
46 |
47 |
48 |
51 |
52 |
53 | -
54 |
{viewsCount}
55 |
56 | -
57 |
58 |
61 | {favoritesCount}
62 |
63 |
64 | {isTeaser &&
65 | -
66 |
67 | {!!author.avatar ?
: }@{author.nick}
68 |
69 |
70 | }
71 | {isTeaser &&
72 | -
73 |
74 |
75 | Комментировать
76 |
77 |
78 |
79 | }
80 | -
81 | {!isTeaser &&
82 |
{/* TODO реализовать шеринг в соцсети, пока удалил код из якорей */}
83 | -
84 |
85 |
86 | -
87 |
88 |
89 | -
90 |
91 |
92 | -
93 |
94 |
95 |
96 | }
97 |
98 |
99 |
100 | )
101 | }
102 |
103 | export default PostInfoPanel
104 |
--------------------------------------------------------------------------------
/src/components/PostTeaser.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 | import PostHeader from './PostHeader'
4 | import PostInfoPanel from './PostInfoPanel'
5 |
6 | const PostTeaser = ({ id, published, flow, hubs, title, content, author, viewsCount, favoritesCount }) => (
7 |
8 |
9 |
10 |
{content}
11 |
12 | {/* TODO изменяемое название для habracut */}
13 | Читать дальше →
14 |
15 |
16 |
19 |
20 | )
21 |
22 | export default PostTeaser
23 |
--------------------------------------------------------------------------------
/src/components/PostTeaserList.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | // import { Link } from 'react-router'
4 | import { createSelector } from 'reselect'
5 |
6 | import PostTeaser from './PostTeaser'
7 |
8 | // TODO при скролировании страницы, зачем-то присваивается класс focus для
9 |
10 | /*
11 |
12 | {Object.keys(flows).map(key =>
13 | -
14 | {flows[key].name}
15 |
16 | )}
17 |
18 | */
19 |
20 | const PostTeaserList = ({ postTeaserList, flows }) => (
21 |
{/* TODO может перенести сюда родительский className="content_left"? */}
22 |
23 |
24 |
25 | {postTeaserList.map((postTeaser) => (
26 |
27 | ))}
28 |
29 |
30 |
31 | )
32 |
33 | const getSelectedFlow = (state, props) =>
34 | props.params.selectedFlow
35 |
36 | const getPostTeaserList = (state) =>
37 | state.posts
38 |
39 | const filteredPostTeaserList = createSelector(
40 | [getPostTeaserList, getSelectedFlow],
41 | (posts, selectedFlow) => {
42 | if (selectedFlow) {
43 | return posts.filter(element =>
44 | element.flow.id === selectedFlow)
45 | } else {
46 | return posts
47 | }
48 | }
49 | )
50 |
51 | const mapStateToProps = (state, ownProps) => {
52 | return {
53 | postTeaserList: filteredPostTeaserList(state, ownProps),
54 | flows: state.flows
55 | }
56 | }
57 |
58 | const mapDispatchToProps = (dispatch) => {
59 | return {}
60 | }
61 |
62 | export default connect(mapStateToProps, mapDispatchToProps)(PostTeaserList)
63 |
--------------------------------------------------------------------------------
/src/components/PostType.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | const PostType = ({ author: { nick, name } }) => (
5 |
6 |
7 | Автор:
8 | {`@${nick}`}
9 |
10 |
11 | )
12 |
13 | export default PostType
14 |
--------------------------------------------------------------------------------
/src/components/SearchForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const SearchForm = () => (
4 |
22 | )
23 |
24 | export default SearchForm
25 |
--------------------------------------------------------------------------------
/src/components/TopicAdd.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { connect } from 'react-redux'
3 | import { bindActionCreators } from 'redux'
4 | import { actions as editPostActions } from '../ducks/editPost'
5 |
6 | // TODO понимание PureComponent
7 | // https://www.youtube.com/watch?v=Pc3RKELjB-0
8 |
9 | // TODO как сделать PureComponent из функционального компонента?
10 | // https://github.com/facebook/react/issues/5677#issuecomment-280295107
11 |
12 | const TITLE_MAX_LENGTH = 120
13 |
14 | const TopicAdd = ({ post: { title }, inputTitle, sendToServer, router: { push } }) => {
15 |
16 | let textareaContent = null
17 |
18 | const doSubmit = (event) => {
19 | event.preventDefault()
20 | sendToServer({ title, content: textareaContent.value })
21 | push('/')
22 | }
23 |
24 | const doInputTitle = (event) => {
25 | inputTitle(event.target.value)
26 | }
27 |
28 | return (
29 |
45 | )
46 | }
47 |
48 | const mapStateToProps = (state) => ({
49 | post: state.editPost
50 | })
51 |
52 | const mapDispatchToProps = (dispatch) => {
53 | return bindActionCreators(editPostActions, dispatch)
54 | }
55 |
56 | export default connect(mapStateToProps, mapDispatchToProps)(TopicAdd)
57 |
--------------------------------------------------------------------------------
/src/components/TrackerButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | const TrackerButton = () => (
5 |
6 |
11 |
12 | )
13 |
14 | export default TrackerButton
15 |
--------------------------------------------------------------------------------
/src/components/UserDropdown.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | const UserDropdown = () => (
5 |
6 |
10 |
11 |
12 |
comerc
13 |
14 |
Профиль
15 |
16 |
17 |
У вас 8 голосов за карму и публикации, и еще 16 за комментарии
18 |
19 | -
20 | Публикации
21 |
22 | -
23 | Комментарии
24 |
25 | -
26 | Диалоги
27 |
28 | -
29 | Избранное
30 |
31 | -
32 | Настройки
33 |
34 | -
35 | Выйти
36 |
37 |
38 |
39 |
40 | )
41 |
42 | export default UserDropdown
43 |
--------------------------------------------------------------------------------
/src/components/UserMenu.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | const UserMenu = () => (
5 |
6 | - comerc
7 | - Лента
8 | - Трекер
9 | - Написать
10 | - Диалоги
11 | - Настройки
12 | - ППА
13 |
14 | )
15 |
16 | export default UserMenu
17 |
--------------------------------------------------------------------------------
/src/components/UserNavBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import TrackerButton from './TrackerButton'
3 | import WriteTopicButton from './WriteTopicButton'
4 | import UserDropdown from './UserDropdown'
5 |
6 | const UserNavBar = () => (
7 |
8 |
9 |
10 |
11 |
12 | )
13 |
14 | export default UserNavBar
15 |
--------------------------------------------------------------------------------
/src/components/WriteTopicButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Link } from 'react-router'
3 |
4 | const WriteTopicButton = () => (
5 |
6 |
Написать
7 |
11 |
12 | )
13 |
14 | export default WriteTopicButton
15 |
--------------------------------------------------------------------------------
/src/ducks/app.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | }
3 |
4 | export default ( state = initialState, action ) => {
5 | return state
6 | }
7 |
--------------------------------------------------------------------------------
/src/ducks/editPost.js:
--------------------------------------------------------------------------------
1 | import { createAction, createReducer } from 'redux-act'
2 |
3 | export const actions = {
4 | inputTitle: createAction('@@edit_post/INPUT_TITLE', title => ({ title })),
5 | submit: createAction('@@edit_post/SUBMIT', post => post),
6 | sendToServer: post => dispatch => {
7 | //...
8 | console.log('SEND')
9 | dispatch(actions.submit(post))
10 | }
11 | }
12 |
13 | const initialState = {
14 | flow: '',
15 | title: '',
16 | content: ''
17 | }
18 |
19 | const reducer = createReducer({
20 | [actions.inputTitle]: (state, { title }) => ({...state, title}),
21 | [actions.submit]: (state, post) => ({...state, ...post})
22 | }, initialState)
23 |
24 | export default reducer
25 |
--------------------------------------------------------------------------------
/src/ducks/flows.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | 'develop': { name: 'Разработка' },
3 | 'management': { name: 'Управление' },
4 | 'admin': { name: 'Администрирование' }
5 | }
6 |
7 | export default (state = initialState, action) => {
8 | return state
9 | }
10 |
--------------------------------------------------------------------------------
/src/ducks/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import { routerReducer } from 'react-router-redux'
3 |
4 | import app from './app'
5 | import flows from './flows'
6 | import posts from './posts'
7 | import editPost from './editPost'
8 |
9 | export default combineReducers({
10 | routing: routerReducer,
11 | app,
12 | flows,
13 | posts,
14 | editPost
15 | })
16 |
--------------------------------------------------------------------------------
/src/ducks/posts.js:
--------------------------------------------------------------------------------
1 | const initialState = [
2 | {
3 | id: 1741,
4 | published: '1 сентября 2006 в 14:05',
5 | viewsCount: 95700,
6 | favoritesCount: 18,
7 | author: {
8 | id: 3678,
9 | nick: 'alizar',
10 | name: 'Анатолий Ализар',
11 | avatar: '//habrastorage.org/getpro/habr/avatars/b23/82c/caa/b2382ccaa0679cd72813ba9f6a207133.jpg',
12 | specialization: 'Пользователь',
13 | contacts: [
14 | { type: 'Facebook', url: 'http://facebook.com/anatol.alizar' },
15 | { type: 'Twitter', url: 'http://twitter.com/alizar1' },
16 | { type: 'Google+', url: 'https://plus.google.com/109929493370452160902' },
17 | { type: 'Skype', url: 'skype:aalizar' },
18 | ],
19 | votingCounter: 3472,
20 | karma: 752.5,
21 | rating: 87.8
22 | },
23 | flow: { id: 'develop', name: 'Разработка' },
24 | hubs: [{ id: 'gamedev', name: 'Разработка игр' }],
25 | title: 'Крупнейшая афера в истории виртуальных миров',
26 | content: 'В виртуальном мире EVE Online была провернута грандиозная афера, в результате которой мошенник завладел игровой валютой на сумму $170.000. Вероятно, он останется безнаказанным и сможет свободно обменять украденную валюту на реальные доллары.',
27 | },
28 | {
29 | id: 308228,
30 | published: '22 августа 2016 в 17:14',
31 | viewsCount: 9000,
32 | favoritesCount: 55,
33 | author: {
34 | id: 3678,
35 | nick: 'comerc',
36 | name: 'comerc',
37 | avatar: '//habrastorage.org/getpro/habr/avatars/29a/d0a/09c/29ad0a09c3fa9790266c746e43635ca7.jpg',
38 | specialization: 'Пользователь',
39 | contacts: [
40 | { type: 'GitHub', url: 'https://github.com/comerc' }
41 | ],
42 | votingCounter: 50,
43 | karma: 8.0,
44 | rating: -2.35
45 | },
46 | flow: { id: 'develop', name: 'Разработка' },
47 | hubs: [{ id: 'funcprog', name: 'Функциональное программирование' }],
48 | title: 'Как Clojure помогает ускорить написание Selenium-тестов',
49 | content: 'Привет, читатель! Если доводилось писать Selenuim-тесты чуть сложнее чем на пару полей ввода и одну кнопку, то эта статья может пригодиться.',
50 | },
51 | {
52 | id: 321894,
53 | published: '15 февраля в 15:19',
54 | viewsCount: 3200,
55 | favoritesCount: 47,
56 | author: {
57 | avatar: 'https://habrastorage.org/getpro/habr/avatars/11d/cd5/156/11dcd5156965ea37622a22ddadcc12eb.jpg',
58 | nick: 'Talik0507',
59 | name: 'Talik',
60 | votingCounter: 5,
61 | karma: 5.0,
62 | rating: 12.0
63 | },
64 | company: {
65 | id: 3349,
66 | nick: 'at_consulting',
67 | name: 'AT Consulting',
68 | avatar: '//habrastorage.org/getpro/habr/company/df6/980/676/df6980676ad0cfc3224ee7a6629d996b.jpg',
69 | specialization: '',
70 | contacts: [
71 | { type: 'Facebook', url: 'http://facebook.com/atconsulting.ru' },
72 | { type: 'Вконтакте', url: 'http://vk.com/atconsulting_ru' }
73 | ],
74 | rating: 90.165
75 | },
76 | flow: { id: 'admin', name: 'Администрирование' },
77 | hubs: [{ id: 'db_admins', name: 'Администрирование баз данных' }],
78 | title: 'Zabbix-мониторинг данных в БД Oracle без unixODBC',
79 | content: 'Была поставлена задача: реализовать мониторинг БД Oracle средствами Zabbix, а именно — отслеживать параметры табличных пространств на определенном инстансе. Раз задача поставлена, значит делаем. Как известно, Zabbix предоставляет возможность через предопределенный тип данных осуществлять запросы к базам данным и получать результат запроса.'
80 | },
81 | // {
82 | // id: 321564,
83 | // published: 'сегодня в 12:00',
84 | // viewsCount: 10400,
85 | // favoritesCount: 61,
86 | // author: {
87 | // avatar: 'https://hsto.org/getpro/habr/avatars/f89/cd2/7e9/f89cd27e95dc7b8c1e3db4d56c77309b.png',
88 | // nick: 'Halt',
89 | // name: 'Дмитрий Каши́цын',
90 | // },
91 | // flow: { id: 'develop', name: 'Разработка' },
92 | // hubs: [{ id: 'webdev', name: 'Разработка веб-сайтов' }],
93 | // title: 'Процедурные макросы в Rust 1.15',
94 | // content: 'Ребята, свершилось! После долгих шести недель ожидания наконец вышла версия Rust 1.15 с блекджеком и процедурными макросами.'
95 | // },
96 | // {
97 | // id: 321560,
98 | // published: '10 февраля в 20:02',
99 | // viewsCount: 12300,
100 | // favoritesCount: 163,
101 | // author: {
102 | // avatar: 'https://habrastorage.org/getpro/habr/avatars/45f/298/67b/45f29867be422cdd754bd2c1a413028a.png',
103 | // nick: 'TM_content',
104 | // name: 'Контент-студия',
105 | // },
106 | // flow: { id: 'develop', name: 'Разработка' },
107 | // hubs: [{ id: 'webdev', name: 'Разработка веб-сайтов' }],
108 | // title: 'Сравнение решений по балансировке высоконагруженных систем',
109 | // content: 'И вновь мы публикуем расшифровки выступлений с конференции HighLoad++, которая прошла в подмосковном Сколково 7—8 ноября 2016 года. Сегодня Евгений Пивень знакомит нас с решениями балансировки в облаках.'
110 | // },
111 | // {
112 | // id: 321606,
113 | // published: '10 февраля в 18:21',
114 | // viewsCount: 11700,
115 | // favoritesCount: 168,
116 | // author: {
117 | // avatar: 'https://habrastorage.org/getpro/habr/avatars/10c/966/59f/10c96659ff7013592cdf926e17e2195f.jpg',
118 | // nick: 'conspiratus',
119 | // name: 'Константин',
120 | // specialization: 'PM, Analyst, Developer, AVR Developer.',
121 | // votingCounter: 7,
122 | // karma: 7.0,
123 | // rating: 21.6
124 | // },
125 | // flow: { id: 'develop', name: 'Разработка' },
126 | // hubs: [{ id: 'webdev', name: 'Разработка веб-сайтов' }],
127 | // title: 'Home Assistant или еще один «мозг» для проекта типа «Умный Дом»',
128 | // content: 'Добрый день, уважаемый читатель.'
129 | // },
130 | {
131 | id: 321622,
132 | published: '11 февраля в 12:18',
133 | viewsCount: 3100,
134 | favoritesCount: 24,
135 | author: {
136 | nick: 'GoTech-vc',
137 | votingCounter: 7,
138 | karma: 1.0,
139 | rating: 10.9
140 | },
141 | company: {
142 | id: 4276,
143 | avatar: 'https://habrastorage.org/getpro/megamozg/company/f56/5c9/167/f565c9167c57d06069e63e0fd461ccbc.png',
144 | name: 'GoTech.vc',
145 | specialization: 'GoTech – занимаемся поиском и развитием технологий',
146 | rating: 40.01,
147 | contacts: [
148 | { type: 'Сайт', url: 'http://www.gotech.vc/' }
149 | ]
150 | },
151 | flow: { id: 'management', name: 'Управление' },
152 | hubs: [{ id: 'webdev', name: 'Разработка веб-сайтов' }],
153 | title: 'Корпорации и стартапы: модели успешного сотрудничества',
154 | content: 'Фонд развития инноваций GoTech продолжает рассказывать о том, каким образом корпорации видят успешное сотрудничество со стартапами в российском и международном масштабе.'
155 | },
156 | ]
157 |
158 | export default (state = initialState, action) => {
159 | return state
160 | }
161 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import { Provider } from 'react-redux'
4 | import { createStore, applyMiddleware } from 'redux'
5 | import { composeWithDevTools } from 'redux-devtools-extension'
6 | import thunk from 'redux-thunk'
7 | import { Router, browserHistory, applyRouterMiddleware } from 'react-router'
8 | import { syncHistoryWithStore } from 'react-router-redux'
9 | import createLogger from 'redux-logger'
10 | import { useScroll } from 'react-router-scroll'
11 |
12 | import reducer from './ducks'
13 | import routes from './routes'
14 |
15 | const logger = createLogger()
16 | const store = createStore(reducer, composeWithDevTools(applyMiddleware(thunk, logger)))
17 | const history = syncHistoryWithStore(browserHistory, store)
18 | const render = applyRouterMiddleware(useScroll())
19 |
20 | ReactDOM.render(
21 |
22 |
23 | ,
24 | document.getElementById('root')
25 | )
26 |
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Route, IndexRoute, Redirect } from 'react-router'
3 |
4 | import App from './components/App'
5 | import PostTeaserList from './components/PostTeaserList'
6 | import PostFull from './components/PostFull'
7 | import Feedback from './components/Feedback'
8 | import TopicAdd from './components/TopicAdd'
9 | import NotFound from './components/NotFound'
10 | import InfoHelp from './components/InfoHelp'
11 | import InfoAbout from './components/InfoAbout'
12 | import InfoHelpRules from './components/InfoHelpRules'
13 | import InfoHelpOther from './components/InfoHelpOther'
14 | import InfoHelpRegistration from './components/InfoHelpRegistration'
15 | import InfoHelpHabracentre from './components/InfoHelpHabracentre'
16 | import InfoHelpKarma from './components/InfoHelpKarma'
17 | import InfoHelpSettings from './components/InfoHelpSettings'
18 | import InfoHelpHubs from './components/InfoHelpHubs'
19 | import InfoHelpLenta from './components/InfoHelpLenta'
20 | import InfoHelpPosts from './components/InfoHelpPosts'
21 |
22 | export default (
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | )
54 |
55 | // TODO при переходе на страницу поста по хештегам #habracut или #comments, происходит редирект с вырезанием этого хештега (чтобы дальше поделиться правильным URL)
56 |
57 | // TODO react-router/examples/huge-apps - Partial App Loading
58 |
59 | // TODO /help/... > page-header__title > `Помощь -> ${title}` со ссылкой
60 |
61 | // TODO /topic/add/ > page-header__title > "Хочу разместить публикацию"
62 |
63 | // TODO настроить редирект url без оконечного / на уровне насторек сервера nginx
64 |
65 | // TODO редирект, если блог компании: `/post/${id}/` > `/company/${nick}/blog/${id}/`
66 |
67 | // TODO подключить https://github.com/taion/react-router-scroll
68 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | import memoize from 'lodash.memoize'
2 |
3 | export const ga = (eventCategory, eventAction, eventLabel) => memoize(() => {
4 | if (typeof window.ga === 'function') {
5 | window.ga('send', 'event', eventCategory, eventAction, eventLabel)
6 | }
7 | })
8 |
9 | export const plural = (value, form1, form2, form3) => {
10 | // TODO реализовать plural
11 | return value
12 | }
13 |
14 | export const urlencode = (s) => {
15 | // TODO реализовать urlencode
16 | return 'dummy'
17 | }
18 |
19 | export const formatDateTime = (dateTime) => {
20 | // TODO реализовать formatDateTime
21 | return dateTime + ''
22 | }
23 |
--------------------------------------------------------------------------------