Этот коммит содержится в:
Igor V Belousov 2017-01-26 05:21:02 +03:00
родитель a52e24ae45
Коммит b6f7196aa5
21 изменённых файлов: 681 добавлений и 12 удалений

Просмотреть файл

@ -10,6 +10,30 @@ module.exports = function(grunt) {
}
},
spriteGenerator: {
"sprite": {
src: [
'images/sprite/*.png'
],
spritePath: 'images/sprite.png',
stylesheetPath: 'css/sprite.styl',
compositor:'gm',
stylesheet: 'stylus',
stylesheetOptions:{
prefix:'sprite_',
spritePath:'/image/sprite.png',
pixelRatio:2
},
layout:'packed',
layoutOptions:{
padding:8
},
compositorOptions:{
compressionLevel:9
}
}
},
stylus: {
compile: {
options:{
@ -28,8 +52,19 @@ module.exports = function(grunt) {
'../public/css/style.css':'../public/css/style.raw.css'
}
}
},
imagemin: {
static: {
options: {
optimizationLevel: 7
},
files: {
'../public/image/sprite.png': 'images/sprite.png'
}
}
}
});
@ -38,6 +73,8 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-internal');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('node-sprite-generator');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-csso');
grunt.loadNpmTasks('grunt-contrib-stylus');
@ -46,5 +83,5 @@ module.exports = function(grunt) {
grunt.registerTask('js',['uglify']);
grunt.registerTask('default', ['css']);
grunt.registerTask('full',['css','js'])
grunt.registerTask('full',['spriteGenerator','css','imagemin','js'])
};

37
grunt/css/sprite.styl Обычный файл
Просмотреть файл

@ -0,0 +1,37 @@
sprite_account-x = -2px
sprite_account-y = -2px
sprite_account-width = 24px
sprite_account-height = 24px
sprite_account = sprite_account-x sprite_account-y sprite_account-width sprite_account-height
sprite_calendar-x = -30px
sprite_calendar-y = -2px
sprite_calendar-width = 24px
sprite_calendar-height = 24px
sprite_calendar = sprite_calendar-x sprite_calendar-y sprite_calendar-width sprite_calendar-height
sprite_email-x = -2px
sprite_email-y = -30px
sprite_email-width = 24px
sprite_email-height = 24px
sprite_email = sprite_email-x sprite_email-y sprite_email-width sprite_email-height
sprite_web-x = -30px
sprite_web-y = -30px
sprite_web-width = 24px
sprite_web-height = 24px
sprite_web = sprite_web-x sprite_web-y sprite_web-width sprite_web-height
sprite_sprite-image()
background-image url('/image/sprite.png')
sprite_sprite-size()
background-size 56px 56px
sprite_sprite-position($sprite)
background-position $sprite[0] $sprite[1]
sprite_sprite-width($sprite)
width $sprite[2]
sprite_sprite-height($sprite)
height $sprite[3]
sprite_sprite($sprite)
sprite_sprite-image()
sprite_sprite-size()
sprite_sprite-position($sprite)
sprite_sprite-width($sprite)
sprite_sprite-height($sprite)

Просмотреть файл

@ -1,11 +1,14 @@
@import "ShortCSS/ShortCSS.styl"
@import "normalize/normalize.styl"
/** sprite */
@import "sprite.styl"
/** ptest css */
body
-ff _ffv
-fs 16
-wmin 320
$link_color = #0063ff
$link_color_border = alpha($link_color,.3)
@ -28,12 +31,30 @@ a
-c $link_hover_color
-brbc $link_hover_color_border
&.to-front
-brb 0 none
-d block
-mt -5
-mb 2em
line-height 1
&:visited
-c $link_color
&:hover
&:visited:hover
-c $link_hover_color
.page
&__container
-wmax 800
-m 0 auto
+media('max-width:829px')
-wmax auto
-w 100%
.header
-p 30
-bg #ffcc56
@ -46,6 +67,14 @@ a
-mb 60
-ta center
+media('max-width:829px')
bx-shadow none
-mt 0
+media('max-width:500px')
-p 20
-mb 36
&__title
line-height 1
-m 0
@ -54,18 +83,128 @@ a
-ts 1 1 1 #a76f19
-fs 52
+media('max-width:500px')
-fs 32
.page-title
-pb 35
+media('max-width:500px')
-fs 1.35em
.content
-pb 76
+media('max-width:829px')
-w 90%
-m auto
p
-m 26 0
-lh 24
.sort
-d table-row
+media('max-width:424px')
-ml -9
&__cell
-d table-cell
&:first-child
+media('max-width:424px')
-d none
&:nth-child(2)
+media('max-width:424px')
-pl 0
&+&
-pl 9
&>a
-brb 0 none
line-height 1
&:visited
-c $link_color
&:hover
&:visited:hover
-c $link_hover_color
article
&+article
-mt 64
header
h2+span
+media('max-width:500px')
-d block
.pager
-mt 50
-ff _ffa
-lh 40
-fs 20
+media('max-width:559px')
-fs 16
-lh 36
&__page
-d inline-block
&--current
cursor default
&>a
-brb none
-c black
-p 8 12
b-radius 35
+media('max-width:559px')
-p 5 8
&:hover
-c black
-bgc $link_hover_color_border
&>span
-bgc alpha(#dead6f,.5)
-p 8 12
b-radius 35
+media('max-width:559px')
-p 5 8
&--string
&:first-child
-mr 10
+media('max-width:559px')
-mr 0
&:last-child
-ml 9
+media('max-width:559px')
-ml 0
&>a
-p 8 0
+media('max-width:559px')
-p 8 0
&:hover
//-c black
-bgc transparent
.footer
-brt 1 solid #dead6f
-pt 24
-fs 85%
-c #232425
-pb 40
+media('max-width:829px')
-pl 5%
#CAPTCHA
& > img
@ -77,6 +216,9 @@ a
form
-w 320
+media('max-width:374px')
-w 100%
.form-element
-m 0 -8 10 -8
-p 6 8
@ -103,3 +245,35 @@ form
&:focus
-brb 2 solid $link_hover_color_border
.i-user
sprite_sprite(sprite_account)
-mb -6
-d inline-block
-mr 5
-ml 1em
+media('max-width:500px')
-ml 0
.i-homepage
sprite_sprite(sprite_web)
-mb -6
-d inline-block
-mr 5
.i-date
sprite_sprite(sprite_calendar)
-mb -6
-d inline-block
-mr 5
.i-email
sprite_sprite(sprite_email)
-mb -6
-d inline-block
-mr 5
apply_media_cache()

Двоичные данные
grunt/images/sprite.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Двоичные данные
grunt/images/sprite/account.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 444 B

Двоичные данные
grunt/images/sprite/calendar.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 353 B

Двоичные данные
grunt/images/sprite/email.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 456 B

Двоичные данные
grunt/images/sprite/web.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 980 B

Просмотреть файл

@ -7,6 +7,8 @@
"grunt-contrib-stylus": "~1.2.0",
"grunt-contrib-jshint": "~1.0.0",
"grunt-contrib-internal": "~1.2.2",
"grunt-contrib-uglify": "~2.0.0"
"grunt-contrib-uglify": "~2.0.0",
"node-sprite-generator": "~0.10.2",
"grunt-contrib-imagemin": "~1.0.1"
}
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -195,10 +195,12 @@ template {
[hidden] {
display: none;
}
/** sprite */
/** ptest css */
body {
font-family: Verdana, "Geneva CY", "DejaVu Sans", sans-serif;
font-size: 16px;
min-width: 320px;
}
a {
color: #0063ff;
@ -214,6 +216,20 @@ a:visited:hover {
color: #ff475d;
border-bottom-color: rgba(255,71,93,0.24);
}
a.to-front {
border-bottom: 0 none;
display: block;
margin-top: -5px;
margin-bottom: 2em;
line-height: 1;
}
a.to-front:visited {
color: #0063ff;
}
a.to-front:hover,
a.to-front:visited:hover {
color: #ff475d;
}
.page__container {
max-width: 800px;
margin: 0 auto;
@ -251,6 +267,82 @@ a:visited:hover {
.content {
padding-bottom: 76px;
}
.content p {
margin: 26px 0;
line-height: 24px;
}
.sort {
display: table-row;
}
.sort__cell {
display: table-cell;
}
.sort__cell+.sort__cell {
padding-left: 9px;
}
.sort__cell>a {
border-bottom: 0 none;
line-height: 1;
}
.sort__cell>a:visited {
color: #0063ff;
}
.sort__cell>a:hover,
.sort__cell>a:visited:hover {
color: #ff475d;
}
article+article {
margin-top: 64px;
}
.pager {
margin-top: 50px;
font-family: Arial, "Helvetica CY", "Nimbus Sans L", sans-serif;
line-height: 40px;
font-size: 20px;
}
.pager__page {
display: inline-block;
}
.pager__page--current {
cursor: default;
}
.pager__page>a {
border-bottom: none;
color: #000;
padding: 8px 12px;
-webkit-border-radius: 35px;
-moz-border-radius: 35px;
-o-border-radius: 35px;
-ms-border-radius: 35px;
-khtml-border-radius: 35px;
border-radius: 35px;
}
.pager__page>a:hover {
color: #000;
background-color: rgba(255,71,93,0.24);
}
.pager__page>span {
background-color: rgba(222,173,111,0.5);
padding: 8px 12px;
-webkit-border-radius: 35px;
-moz-border-radius: 35px;
-o-border-radius: 35px;
-ms-border-radius: 35px;
-khtml-border-radius: 35px;
border-radius: 35px;
}
.pager__page--string:first-child {
margin-right: 10px;
}
.pager__page--string:last-child {
margin-left: 9px;
}
.pager__page--string>a {
padding: 8px 0;
}
.pager__page--string>a:hover {
background-color: transparent;
}
.footer {
border-top: 1px solid #dead6f;
padding-top: 24px;
@ -298,3 +390,118 @@ form {
.form-element__textarea:focus {
border-bottom: 2px solid rgba(255,71,93,0.24);
}
.i-user {
background-image: url("/image/sprite.png");
background-size: 56px 56px;
background-position: -2px -2px;
width: 24px;
height: 24px;
margin-bottom: -6px;
display: inline-block;
margin-right: 5px;
margin-left: 1em;
}
.i-homepage {
background-image: url("/image/sprite.png");
background-size: 56px 56px;
background-position: -30px -30px;
width: 24px;
height: 24px;
margin-bottom: -6px;
display: inline-block;
margin-right: 5px;
}
.i-date {
background-image: url("/image/sprite.png");
background-size: 56px 56px;
background-position: -30px -2px;
width: 24px;
height: 24px;
margin-bottom: -6px;
display: inline-block;
margin-right: 5px;
}
.i-email {
background-image: url("/image/sprite.png");
background-size: 56px 56px;
background-position: -2px -30px;
width: 24px;
height: 24px;
margin-bottom: -6px;
display: inline-block;
margin-right: 5px;
}
@media only screen and (max-width: 829px) {
.page__container {
max-width: auto;
width: 100%;
}
.header {
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
margin-top: 0;
}
.content {
width: 90%;
margin: auto;
}
.footer {
padding-left: 5%;
}
}
@media only screen and (max-width: 500px) {
.header {
padding: 20px;
margin-bottom: 36px;
}
.header__title {
font-size: 32px;
}
.page-title {
font-size: 1.35em;
}
article header h2+span {
display: block;
}
.i-user {
margin-left: 0;
}
}
@media only screen and (max-width: 424px) {
.sort {
margin-left: -9px;
}
.sort__cell:first-child {
display: none;
}
.sort__cell:nth-child(2) {
padding-left: 0;
}
}
@media only screen and (max-width: 559px) {
.pager {
font-size: 16px;
line-height: 36px;
}
.pager__page>a {
padding: 5px 8px;
}
.pager__page>span {
padding: 5px 8px;
}
.pager__page--string:first-child {
margin-right: 0;
}
.pager__page--string:last-child {
margin-left: 0;
}
.pager__page--string>a {
padding: 8px 0;
}
}
@media only screen and (max-width: 374px) {
form {
width: 100%;
}
}

Двоичные данные
public/image/sprite.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Просмотреть файл

@ -16,14 +16,44 @@ use PTEST\M\CAPTCHAModel;
class IndexController extends Controller {
public function indexAction() {
public function indexAction( $number=1 ) {
$view = new View('index');
$view->page_title = "Доска объявлений";
$model = new Model();
$view->pages_count = $model->countPages();
$view->current_page = $number;
$model = null;
$view->sort_by = 'date';
$view->sort_order = 'asc';
$view->ads = Model::getForPage( (int) $number );
$view->render();
}
public function pageAction( $number ) {
public function sortAction( $column, $order ,$number=1 ) {
$view = new View('index');
$view->page_title = "Доска объявлений";
$model = new Model();
$view->pages_count = $model->countPages();
$view->current_page = $number;
$model = null;
$view->sort_by = $column;
$view->sort_order = $order;
if ($column=='date')$column='pdate';
if ($column=='user')$column='username';
if ($column=='mail')$column='email';
$view->ads = Model::getForPage( (int) $number, $column, $order);
$view->render();
}
public function fullAction( $number ) {
$model = Model::findFirst( 'id = '. $number );
if ( ! $model ) {
$this->app->routeRun('error404');
}
$view = new View('full');
$view->ad = $model;
$model = null;
$view->render();
}
public function newAction() {

Просмотреть файл

@ -28,6 +28,13 @@ class AdModel extends Model{
protected $table_pdate;
/**
* @return mixed
*/
public function getId() {
return (int) $this->table_id;
}
/**
* @param $username
*
@ -74,7 +81,7 @@ class AdModel extends Model{
*/
public function setHomepage( $homepage ) {
if ( preg_match('|https?://.*\..*|i', $homepage ) ) {
$this->table_homepage = $homepage;
$this->table_homepage = strip_tags( $homepage );
return true;
} else {
return "Введите коректный адрес";
@ -143,4 +150,21 @@ class AdModel extends Model{
public function getDate() {
return $this->table_pdate;
}
public function countPages() {
return ceil($this->count()/25);
}
/**
* @param int $page_number
* @param string $sort_by
* @param string $order
*
* @return mixed
*/
static public function getForPage( $page_number = 1, $sort_by = 'pdate', $order = 'ASC' ) {
$class_name = __CLASS__;
$offset = ($page_number - 1) * 25;
return $class_name::find(" 1 ORDER BY $sort_by $order LIMIT $offset,25");
}
}

Просмотреть файл

@ -7,10 +7,8 @@ require __DIR__ . '/inc/head.php';
$this->content = <<<HTML
<article>
<h1 class="page-title">$this->page_title</h1>
<div class="content">
<p>К&nbsp;сожению, страница не&nbsp;найдена.
<p>Попробуйте проследовать на&nbsp;<a href="/" title="Главная">главную</a>.
</div>
</article>
HTML;

32
src/V/full.php Обычный файл
Просмотреть файл

@ -0,0 +1,32 @@
<?php
$email_filter = function ($email) { return str_replace( [ '@', '.' ], [ ' &lt;at&gt; ', ' &lt;dot&gt; ' ], $email ); };
$h1 = function ($text) {$t = substr(trim($text),0,50); return substr($t, 0,strrpos($t,' ')).'&hellip;'; };
$text = function ($t) {return trim( preg_replace('/<br>(\s*)?<br>/','<p>',str_replace(["\n"],['<br>'], preg_replace("/[\t\ ]{2,}/",' ',$t))) ); };
$this->page_title = 'Объявление №'.$this->ad->getId().' '.$h1($this->ad->getText());
require __DIR__ . '/inc/head.php';
ob_start();
?>
<article>
<h1 class="page-title"><?php echo $this->page_title; ?></h1>
<a href="/" class="to-front">&larr;Главная</a>
<header>
<div>
<span><i class="i-date"></i><?php echo $this->ad->getDate(); ?></span>
<span><i class="i-user"></i><?php echo $this->ad->getUserName(); ?></span><br>
<span><i class="i-email"></i><?php echo $email_filter($this->ad->getEmail()); ?></span>
<?php
if ( ! empty( $this->ad->getHomepage() ) ) {
echo '<br><span><i class="i-homepage"></i><a href="' . $this->ad->getHomepage() . '" target="_blank">' . $this->ad->getHomepage() . '</a>';
}
?>
</div>
</header>
<p><?php echo $text( $this->ad->getText() ); ?>
</article>
<?php
$this->content = ob_get_contents();
ob_end_clean();
require __DIR__ . '/inc/body.php';

Просмотреть файл

@ -3,7 +3,7 @@
<header class="header">
<h1 class="header__title"><?php echo $this->site_name; ?></h1>
</header>
<section role="main">
<section role="main" class="content">
<?php echo $this->content; ?>
</section>
<footer class="footer">

Просмотреть файл

@ -6,5 +6,5 @@
<meta charset="utf-8">
<link rel="stylesheet" href="/css/style.css">
<script src="/js/script.js"></script>
<title><?php echo $this->page_title; ?></title>
<title><?php echo $this->site_name.'&mdash;'.$this->page_title; ?></title>
</head>

Просмотреть файл

@ -1,3 +1,124 @@
<?php
require __DIR__ . '/inc/head.php';
$email_filter = function ($email) { return str_replace( [ '@', '.' ], [ ' &lt;at&gt; ', ' &lt;dot&gt; ' ], $email ); };
$h2 = function ($text) {$t = substr(trim($text),0,50); return substr($t, 0,strrpos($t,' ')).'&hellip;'; };
$preview = function ($text) {$t = substr( trim( str_replace(["\n"],['<br>'], preg_replace('/<br>(\s*)?<br>/','<p>',preg_replace("/[\t\ ]{2,}/",' ',$text))) ),0,1000); return substr($t, 0,strrpos($t,' ')); };
ob_start();
$one_href = '/date/desc/';
$two_href = '/user/asc/';
$three_href = '/mail/asc/';
$one_arr = '&uarr; ';
$two_arr = '&ensp;&nbsp;';
$three_arr = '&ensp;&nbsp;';
if ($this->sort_by == 'date' && $this->sort_order == 'desc') {
$one_href = '/';
$one_arr = '&darr; ';
}
if ($this->sort_by == 'user') {
$one_href = '/';
$one_arr = '&ensp;&nbsp;';
if ($this->sort_order == 'asc') {
$two_href = '/user/desc/';
$two_arr = '&uarr; ';
} else {
$two_href = '/user/asc/';
$two_arr = '&darr; ';
}
}
if ($this->sort_by == 'mail') {
$one_href = '/';
$one_arr = '&ensp;&nbsp;';
if ($this->sort_order == 'asc') {
$three_href = '/mail/desc/';
$three_arr = '&uarr; ';
} else {
$three_href = '/mail/asc/';
$three_arr = '&darr; ';
}
}
?>
<h1 class="page-title"><?php echo $this->page_title ?></h1>
<div class="sort">
<div class="sort__cell">Сортировка:</div>
<div class="sort__cell"><a href="<?php echo $one_href ?>"><?php echo $one_arr ?>Дата</a></div>
<div class="sort__cell"><a href="<?php echo $two_href ?>"><?php echo $two_arr ?>Пользователь</a></div>
<div class="sort__cell"><a href="<?php echo $three_href ?>"><?php echo $three_arr ?>e-mail</a></div>
</div>
<?php
foreach ($this->ads as $item){
?>
<article>
<header>
<div>
<h2><?php echo $h2( $item->getText() ); ?></h2>
<span><i class="i-date"></i><?php echo $item->getDate(); ?></span>
<span><i class="i-user"></i><?php echo $item->getUserName(); ?></span><br>
<span><i class="i-email"></i><?php echo $email_filter($item->getEmail()); ?></span>
<?php
if ( ! empty( $item->getHomepage() ) ) {
echo '<br><span><i class="i-homepage"></i><a href="' . $item->getHomepage() . '" target="_blank">' . $item->getHomepage() . '</a>';
}
?>
</div>
</header>
<p><?php echo $preview( $item->getText() ); ?>
<footer>
<a href="/full/<?php echo $item->getId(); ?>/">Подробнее</a>
</footer>
</article>
<?php
}
if ($this->pages_count>1) {
$pages = [];
$prefix_url = ($this->sort_by == 'date' && $this->sort_order == 'asc')?'':'/'.$this->sort_by.'/'.$this->sort_order;
$start = $this->current_page - 2;
$start = ($start<=0)?1:$start;
$end = $this->current_page + 2;
$end = ($end<=$this->pages_count)?$end:$this->pages_count;
if ((($end - $start) < 4) && ($this->pages_count > 4)) {
$end++;
if ((($end - $start) < 4) && ($this->pages_count > 4)) {
$end++;
}
};
$end = ($end<=$this->pages_count)?$end:$this->pages_count;
if ($this->current_page > 3) {
$pages[]=['В&nbsp;начало' , $prefix_url . '/'];
}
for ($i=$start;$i<=$end;$i++){
$pages[]=[ $i, $prefix_url . '/page/' . $i . '/'];
}
if ($this->current_page != $this->pages_count) {
$pages[]=['дальше' , $prefix_url . '/page/' . ( $this->current_page + 1 ). '/'];
}
?>
<footer>
<div class="pager"><?php
foreach ($pages as $value) {
if ((int)$this->current_page != (int)$value[0] ) {
?>
<div class="pager__page<?php if ((int)$value[0]==0)echo " pager__page--string";?>"><a href="<?php echo $value[1];?>"><?php echo $value[0];?></a></div>
<?php
} else { ?>
<div class="pager__page pager__page--current"><span><?php echo $value[0];?></span></div>
<?php
}
}
?>
</div>
</footer>
<?php
}
$this->content = ob_get_contents();
ob_end_clean();
require __DIR__ . '/inc/body.php';

Просмотреть файл

@ -6,7 +6,8 @@ ob_start();
?>
<article>
<h1 class="page-title"><?php echo $this->page_title ?></h1>
<div class="content">
<a href="/" class="to-front">&larr;Главная</a>
<div>
<form action="" method="post">
<div class="form-element<?php echo ($this->errors->name)?' form-element--error':''; ?>">
<input class="form-element__input" type="text" name="name" placeholder="Имя" tabindex="1" value="<?php echo ($this->post_data->name)?$this->post_data->name:'';?>">

Просмотреть файл

@ -29,7 +29,13 @@ $config = (object) [
$app = new PFRM\App( $config );
$app->setRoute( '/^\/CAPTCHA.png\?*\d*$/', 'CAPTCHA' );
$app->setRoute( '|^/page/(?<id>\d+)/$|', 'Index', 'page');
$app->setRoute( '|^/page/((?<id>\d+)/)?$|', 'Index', 'index');
$app->setRoute( '|^/(?<column>date)/(?<order>desc)/(page/(?<id>\d+)/)?$|', 'Index', 'sort');
$app->setRoute( '|^/(?<column>user)/(?<order>asc)/(page/(?<id>\d+)/)?$|', 'Index', 'sort');
$app->setRoute( '|^/(?<column>user)/(?<order>desc)/(page/(?<id>\d+)/)?$|', 'Index', 'sort');
$app->setRoute( '|^/(?<column>mail)/(?<order>asc)/(page/(?<id>\d+)/)?$|', 'Index', 'sort');
$app->setRoute( '|^/(?<column>mail)/(?<order>desc)/(page/(?<id>\d+)/)?$|', 'Index', 'sort');
$app->setRoute( '|^/full/(?<id>\d+)/$|', 'Index', 'full');
$app->setRoute( '|^/new/$|', 'Index', 'new');
$app->setRoute( '|^/view_table/((?<id>\d+)/)*$|', 'Index', 'table');
$app->setRoute( '/^.*$/', 'error404' );