first draft

This commit is contained in:
Kevin Papst
2016-10-20 22:10:41 +02:00
parent 94a35ff914
commit 579b962c85
186 changed files with 30734 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
{#
By default, forms enable client-side validation. This means that you can't
test the server-side validation errors from the browser. To temporarily
disable this validation, add the 'novalidate' attribute:
{{ form_start(form, { attr: { novalidate: 'novalidate' } }) }}
#}
{% if show_confirmation|default(false) %}
{% set attr = {'data-confirmation': 'true'} %}
{{ include('blog/_delete_post_confirmation.html.twig') }}
{% endif %}
{{ form_start(form, { attr: attr|default({}) }) }}
{{ form_widget(form) }}
<input type="submit" value="{{ button_label|default('label.create_post'|trans) }}"
class="{{ button_css|default("btn btn-primary") }}" />
{% if include_back_to_home_link|default(false) %}
<a href="{{ path('admin_post_index') }}" class="btn btn-link">
{{ 'action.back_to_list'|trans }}
</a>
{% endif %}
{{ form_end(form) }}

View File

@@ -0,0 +1,26 @@
{% extends 'admin/layout.html.twig' %}
{% block body_id 'admin_post_edit' %}
{% block main %}
<h1>{{ 'title.edit_post'|trans({'%id%': post.id}) }}</h1>
{{ include('admin/blog/_form.html.twig', {
form: edit_form,
button_label: 'action.save'|trans,
include_back_to_home_link: true,
}, with_context = false) }}
{% endblock %}
{% block sidebar %}
<div class="section actions">
{{ include('admin/blog/_form.html.twig', {
form: delete_form,
button_label: 'action.delete_post'|trans,
button_css: 'btn btn-lg btn-block btn-danger',
show_confirmation: true,
}, with_context = false) }}
</div>
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,57 @@
{% extends 'admin/layout.html.twig' %}
{% block body_id 'admin_post_index' %}
{% block main %}
<h1>{{ 'title.post_list'|trans }}</h1>
<table class="table table-striped">
<thead>
<tr>
<th>{{ 'label.title'|trans }}</th>
<th><i class="fa fa-user"></i> {{ 'label.author'|trans }}</th>
<th><i class="fa fa-calendar"></i> {{ 'label.published_at'|trans }}</th>
<th><i class="fa fa-cogs"></i> {{ 'label.actions'|trans }}</th>
</tr>
</thead>
<tbody>
{% for post in posts %}
<tr>
<td>{{ post.title }}</td>
<td>{{ post.authorEmail }}</td>
{# it's not mandatory to set the timezone in localizeddate(). This is done to
avoid errors when the 'intl' PHP extension is not available and the application
is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
<td>{% if post.publishedAt %}{{ post.publishedAt|localizeddate('short', 'short', null, 'UTC') }}{% endif %}</td>
<td>
<div class="item-actions">
<a href="{{ path('admin_post_show', { id: post.id }) }}" class="btn btn-sm btn-default">
{{ 'action.show'|trans }}
</a>
{% if post.isAuthor(app.user) %}
<a href="{{ path('admin_post_edit', { id: post.id }) }}" class="btn btn-sm btn-primary">
<i class="fa fa-edit"></i> {{ 'action.edit'|trans }}
</a>
{% endif %}
</div>
</td>
</tr>
{% else %}
<tr>
<td colspan="4" align="center">{{ 'post.no_posts_found'|trans }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block sidebar %}
<div class="section actions">
<a href="{{ path('admin_post_new') }}" class="btn btn-lg btn-block btn-success">
<i class="fa fa-plus"></i> {{ 'action.create_post'|trans }}
</a>
</div>
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,27 @@
{% extends 'admin/layout.html.twig' %}
{% block body_id 'admin_post_new' %}
{% block main %}
<h1>{{ 'title.post_new'|trans }}</h1>
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.summary) }}
{{ form_row(form.content) }}
{{ form_row(form.authorEmail) }}
{{ form_row(form.publishedAt) }}
<input type="submit" value="{{ 'label.create_post'|trans }}" class="btn btn-primary" />
{{ form_widget(form.saveAndCreateNew, { label: 'label.save_and_create_new', attr: { class: 'btn btn-primary' } }) }}
<a href="{{ path('admin_post_index') }}" class="btn btn-link">
{{ 'action.back_to_list'|trans }}
</a>
{{ form_end(form) }}
{% endblock %}
{% block sidebar %}
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,48 @@
{% extends 'admin/layout.html.twig' %}
{% block body_id 'admin_post_show' %}
{% block main %}
<h1>{{ post.title }}</h1>
<table class="table">
<tbody>
<tr>
<th>{{ 'label.summary'|trans }}</th>
<td>{{ post.summary|md2html }}</td>
</tr>
<tr>
<th>{{ 'label.content'|trans }}</th>
<td>{{ post.content|md2html }}</td>
</tr>
<tr>
<th>{{ 'label.author'|trans }}</th>
<td><p>{{ post.authorEmail }}</p></td>
</tr>
<tr>
<th>{{ 'label.published_at'|trans }}</th>
{# it's not mandatory to set the timezone in localizeddate(). This is done to
avoid errors when the 'intl' PHP extension is not available and the application
is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
<td><p>{{ post.publishedAt|localizeddate('long', 'medium', null, 'UTC') }}</p></td>
</tr>
</tbody>
</table>
{% endblock %}
{% block sidebar %}
<div class="section">
<a href="{{ path('admin_post_edit', { id: post.id }) }}" class="btn btn-lg btn-block btn-success">
<i class="fa fa-edit"></i> {{ 'action.edit_contents'|trans }}
</a>
</div>
<div class="section">
{{ include('admin/blog/_form.html.twig', {
form: delete_form,
button_label: 'action.delete_post'|trans,
button_css: 'btn btn-lg btn-block btn-danger',
show_confirmation: true,
}, with_context = false) }}
</div>
{% endblock %}

View File

@@ -0,0 +1,9 @@
{#
This is the base template of the all backend pages.
See http://symfony.com/doc/current/book/templating.html#template-inheritance-and-layouts
#}
{% extends 'base.html.twig' %}
{% block header_navigation_links %}
{{ knp_menu_render('admin', {'template': 'menu/admin_menu.html.twig'}) }}
{% endblock %}

View File

@@ -0,0 +1,122 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>{% block title %}Symfony Demo application{% endblock %}</title>
{% block stylesheets %}
{# uncomment the following lines to compile SCSS assets with Assetic
{% stylesheets filter="scssphp" output="css/app.css"
"%kernel.root_dir%/Resources/assets/scss/bootstrap-flatly.scss"
"%kernel.root_dir%/Resources/assets/scss/font-awesome.scss"
"%kernel.root_dir%/Resources/assets/css/*.css"
"%kernel.root_dir%/Resources/assets/scss/main.scss"
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}
#}
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
{% endblock %}
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}" />
</head>
<body id="{% block body_id %}{% endblock %}">
{% block header %}
<header>
<div class="navbar navbar-default navbar-static-top" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="{{ path('homepage') }}">
Timesheet
</a>
<button type="button" class="navbar-toggle"
data-toggle="collapse"
data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="navbar-collapse collapse">
{% block header_navigation_links %}
{{ knp_menu_render('main', {'template': 'menu/main_menu.html.twig'}) }}
{% endblock %}
{#
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-globe"></i> <span class="caret"></span></a>
<ul class="dropdown-menu locales" role="menu">
{% for locale in locales() %}
<li {% if app.request.locale == locale.code %}class="active"{% endif %}><a href="{{ path(app.request.get('_route', 'blog_index'), app.request.get('_route_params', [])|merge({ _locale: locale.code })) }}">{{ locale.name|capitalize }}</a></li>
{% endfor %}
</ul>
</li>
#}
</div>
</div>
</div>
</header>
{% endblock %}
<div class="container body-container">
{% block body %}
<div class="row">
<div id="main" class="col-sm-12">
{{ include('default/_flash_messages.html.twig') }}
{% block main %}{% endblock %}
</div>
</div>
{% endblock %}
</div>
{% block footer %}
<footer>
<div class="container">
<div class="row">
<div id="footer-copyright" class="col-md-6">
<p>&copy; {{ 'now'|date('Y') }} - The Symfony Project</p>
<p>{{ 'mit_license'|trans }}</p>
</div>
<div id="footer-resources" class="col-md-6">
<p>
<a href="https://twitter.com/symfony"><i class="fa fa-twitter"></i></a>
<a href="https://www.facebook.com/SensioLabs"><i class="fa fa-facebook"></i></a>
<a href="https://symfony.com/blog/"><i class="fa fa-rss"></i></a>
</p>
</div>
</div>
</div>
</footer>
{% endblock %}
{% block javascripts %}
{# uncomment the following lines to combine and minimize JavaScript assets with Assetic
{% javascripts filter="?jsqueeze" output="js/app.js"
"%kernel.root_dir%/Resources/assets/js/jquery-2.1.4.js"
"%kernel.root_dir%/Resources/assets/js/moment.min.js"
"%kernel.root_dir%/Resources/assets/js/bootstrap-3.3.4.js"
"%kernel.root_dir%/Resources/assets/js/highlight.pack.js"
"%kernel.root_dir%/Resources/assets/js/bootstrap-datetimepicker.min.js"
"%kernel.root_dir%/Resources/assets/js/main.js" %}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
#}
<script src="{{ asset('js/app.js') }}"></script>
{% endblock %}
{# it's not mandatory to set the timezone in localizeddate(). This is done to
avoid errors when the 'intl' PHP extension is not available and the application
is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
<!-- Page rendered on {{ 'now'|localizeddate('long', 'long', null, 'UTC') }} -->
</body>
</html>

View File

@@ -0,0 +1,35 @@
{#
By default, forms enable client-side validation. This means that you can't
test the server-side validation errors from the browser. To temporarily
disable this validation, add the 'novalidate' attribute:
{{ form_start(form, { method: ..., action: ..., attr: { novalidate: 'novalidate' } }) }}
#}
{{ form_start(form, { method: 'POST', action: path('comment_new', { 'postSlug': post.slug }) }) }}
{# instead of displaying form fields one by one, you can also display them
all with their default options and styles just by calling to this function:
{{ form_widget(form) }}
#}
<fieldset>
<legend>{{ 'title.add_comment'|trans }}</legend>
{# Render any global form error (e.g. when a constraint on a public getter method failed) #}
{{ form_errors(form) }}
<div class="form-group {% if not form.content.vars.valid %}has-error{% endif %}">
{{ form_label(form.content, 'label.content', { label_attr: { class: 'hidden' }}) }}
{# Render any errors for the "content" field (e.g. when a class property constraint failed) #}
{{ form_errors(form.content) }}
{{ form_widget(form.content, { attr: { rows: 10 } }) }}
</div>
<div class="form-group">
<button class="btn btn-primary pull-right" type="submit">{{ 'action.publish_comment'|trans }}</button>
</div>
</fieldset>
{{ form_end(form) }}

View File

@@ -0,0 +1,19 @@
{# Bootstrap modal, see http://getbootstrap.com/javascript/#modals #}
<div class="modal fade" id="confirmationModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<h4>{{ 'delete_post_modal.title'|trans }}</h4>
<p>{{ 'delete_post_modal.body'|trans }}</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="btnNo" data-dismiss="modal">
{{ 'label.cancel'|trans }}
</button>
<button type="button" class="btn btn-danger" id="btnYes" data-dismiss="modal">
{{ 'label.delete_post'|trans }}
</button>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,15 @@
<div class="section about">
<div class="well well-lg">
<p>
{{ 'help.app_description'|trans|raw }}
</p>
<p>
{{ 'help.more_information'|trans|raw }}
</p>
</div>
</div>
{# it's not mandatory to set the timezone in localizeddate(). This is done to
avoid errors when the 'intl' PHP extension is not available and the application
is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
<!-- Fragment rendered on {{ 'now'|localizeddate('long', 'long', null, 'UTC') }} -->

View File

@@ -0,0 +1,11 @@
{% extends 'base.html.twig' %}
{% block body_id 'comment_form_error' %}
{% block main %}
<h1 class="text-danger">{{ 'title.comment_error'|trans }}</h1>
<div class="well">
{{ include('blog/_comment_form.html.twig') }}
</div>
{% endblock %}

View File

@@ -0,0 +1,27 @@
{% extends 'base.html.twig' %}
{% block body_id 'blog_index' %}
{% block main %}
{% for post in posts %}
<article class="post">
<h2>
<a href="{{ path('blog_post', { slug: post.slug }) }}">
{{ post.title }}
</a>
</h2>
{{ post.summary|md2html }}
</article>
{% else %}
<div class="well">{{ 'post.no_posts_found'|trans }}</div>
{% endfor %}
<div class="navigation text-center">
{{ pagerfanta(posts, 'twitter_bootstrap3_translated', { routeName: 'blog_index_paginated' }) }}
</div>
{% endblock %}
{% block sidebar %}
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,64 @@
{% extends 'base.html.twig' %}
{% block body_id 'blog_post_show' %}
{% block main %}
<h1>{{ post.title }}</h1>
{{ post.content|md2html }}
<div id="post-add-comment" class="well">
{# The 'IS_AUTHENTICATED_FULLY' role ensures that the user has entered
his/her credentials (login + password) during this session. If he/she
is automatically logged via the 'Remember Me' functionality, he/she won't
be able to add a comment.
See http://symfony.com/doc/current/cookbook/security/remember_me.html#forcing-the-user-to-re-authenticate-before-accessing-certain-resources
#}
{% if is_granted('IS_AUTHENTICATED_FULLY') %}
{{ render(controller('AppBundle:Blog:commentForm', { 'id': post.id })) }}
{% else %}
<p>
<a class="btn btn-success" href="{{ path('security_login') }}">
<i class="fa fa-sign-in"></i> {{ 'action.sign_in'|trans }}
</a>
{{ 'post.to_publish_a_comment'|trans }}
</p>
{% endif %}
</div>
<h3>{{ 'post.num_comments'|transchoice(post.comments|length) }}</h3>
{% for comment in post.comments %}
<div class="row post-comment">
<h4 class="col-sm-3">
<strong>{{ comment.authorEmail }}</strong> {{ 'post.commented_on'|trans }}
{# it's not mandatory to set the timezone in localizeddate(). This is done to
avoid errors when the 'intl' PHP extension is not available and the application
is forced to use the limited "intl polyfill", which only supports UTC and GMT #}
<strong>{{ comment.publishedAt|localizeddate('medium', 'short', null, 'UTC') }}</strong>
</h4>
<div class="col-sm-9">
{{ comment.content|md2html }}
</div>
</div>
{% else %}
<div class="post-comment">
<p>{{ 'post.no_comments'|trans }}</p>
</div>
{% endfor %}
{% endblock %}
{% block sidebar %}
{% if app.user and post.isAuthor(app.user) %}
<div class="section">
<a class="btn btn-lg btn-block btn-success" href="{{ path('admin_post_edit', { id: post.id }) }}">
<i class="fa fa-edit"></i> {{ 'action.edit_post'|trans }}
</a>
</div>
{% endif %}
{# the parent() function includes the contents defined by the parent template
('base.html.twig') for this block ('sidebar'). This is a very convenient way
to share common contents in different templates #}
{{ parent() }}
{% endblock %}

View File

@@ -0,0 +1,25 @@
{#
This is a template fragment designed to be included in other templates
See http://symfony.com/doc/current/book/templating.html#including-other-templates
A common practice to better distinguish between templates and fragments is to
prefix fragments with an underscore. That's why this template is called
'_flash_messages.html.twig' instead of 'flash_messages.html.twig'
#}
{% if app.session.started and app.session.flashBag.peekAll is not empty %}
<div class="messages">
{% for type, messages in app.session.flashBag.all %}
{% for message in messages %}
{# Bootstrap alert, see http://getbootstrap.com/components/#alerts #}
<div class="alert alert-dismissible alert-{{ type }}" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
{{ message|trans }}
</div>
{% endfor %}
{% endfor %}
</div>
{% endif %}

View File

@@ -0,0 +1,19 @@
{#
Each field type is rendered by a template fragment, which is determined
by the name of your form type class (DateTimePickerType -> date_time_picker)
and the suffix "_widget". This can be controlled by overriding getBlockPrefix()
in DateTimePickerType.
See http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html#creating-a-template-for-the-field
#}
{% block date_time_picker_widget %}
{% spaceless %}
<div class="input-group date" data-toggle="datetimepicker">
{{ block('datetime_widget') }}
<span class="input-group-addon">
<span class="fa fa-calendar"></span>
</span>
</div>
{% endspaceless %}
{% endblock %}

View File

@@ -0,0 +1 @@
{% extends 'menu/main_menu.html.twig' %}

View File

@@ -0,0 +1,18 @@
{% extends 'knp_menu.html.twig' %}
{% block linkElement %}
<a href="{{ item.uri }}"{{ knp_menu.attributes(item.linkAttributes) }}>
{% if item.childrenAttributes.icon is defined %}
<i class="fa fa-{{ item.childrenAttributes.icon }} }}"></i>
{% endif %}
{{ block('label') }}
</a>
{% endblock %}
{% block label %}
{% if options.allow_safe_labels and item.getExtra('safe_label', false) %}
{{ item.label|raw }}
{% else %}
{{ item.label|trans }}
{% endif %}
{% endblock %}

View File

@@ -0,0 +1,54 @@
{% extends 'base.html.twig' %}
{% block body_id 'login' %}
{% block main %}
{% if error %}
<div class="alert alert-danger">
{{ error.messageKey|trans(error.messageData, 'security') }}
</div>
{% endif %}
<div class="row">
<div class="col-sm-4"></div>
<div class="col-sm-4">
<div class="well">
<form action="{{ path('security_login') }}" method="post">
<fieldset>
<legend><i class="fa fa-lock"></i> {{ 'title.login'|trans }}</legend>
<div class="form-group">
<label for="username">{{ 'label.username'|trans }}</label>
<input type="text" id="username" name="_username" value="{{ last_username }}" class="form-control"/>
</div>
<div class="form-group">
<label for="password">{{ 'label.password'|trans }}</label>
<input type="password" id="password" name="_password" class="form-control" />
</div>
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}"/>
<button type="submit" class="btn btn-primary">
<i class="fa fa-sign-in"></i> {{ 'action.sign_in'|trans }}
</button>
</fieldset>
</form>
</div>
</div>
<div class="col-sm-4"></div>
</div>
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script>
$(document).ready(function() {
var usernameEl = $('#username');
var passwordEl = $('#password');
// in a real application, hardcoding the user/password would be idiotic
// but for the demo application it's very convenient to do so
if (!usernameEl.val() && !passwordEl.val()) {
usernameEl.val('anna_admin');
passwordEl.val('kitten');
}
});
</script>
{% endblock %}