mirror of
https://github.com/ToxicCrack/PrintABrick.git
synced 2025-05-16 20:30:09 -07:00
Add Imagine PartImage loader
This commit is contained in:
parent
28d7b64244
commit
e684d30c45
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,5 +18,6 @@
|
||||
/node_modules/
|
||||
/app/Resources/libs/semantic/dist
|
||||
/web/resources/
|
||||
/var/media/
|
||||
/web/media/
|
||||
.php_cs.cache
|
BIN
app/Resources/assets/images/noimage.png
Normal file
BIN
app/Resources/assets/images/noimage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 31 KiB |
@ -1,6 +1,3 @@
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% for label, flashes in app.session.flashbag.all %}
|
||||
{% for flash in flashes %}
|
||||
{{ elements.flash(label,flash) }}
|
||||
|
@ -1,5 +1,8 @@
|
||||
{% extends 'ajax.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block content %}
|
||||
{% if description|length %}
|
||||
{{ description|raw }}
|
||||
|
@ -1,5 +1,8 @@
|
||||
{% extends 'ajax.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block content %}
|
||||
{% if images|length %}
|
||||
<div class="ui six doubling cards">
|
||||
|
@ -1,5 +1,8 @@
|
||||
{% extends 'ajax.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block content %}
|
||||
{% if instructions|length != 0 %}
|
||||
<p><cite>{{ 'set.instructions.text' | trans | raw | nl2br }}</cite></p>
|
||||
|
@ -1,13 +1,41 @@
|
||||
{% extends 'ajax.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
|
||||
{% block content %}
|
||||
{% if reviews|length != 0 %}
|
||||
<div class="ui comments">
|
||||
{% for review in reviews %}
|
||||
<div class="comment">
|
||||
<a class="avatar">
|
||||
<div class="ui segment vertical">
|
||||
<div class="ui container divided stackable grid comment">
|
||||
<div class="row">
|
||||
<div class="column four wide ratings">
|
||||
<dl>
|
||||
{% if review.overallRating %}
|
||||
<dt>Overall rating</dt>
|
||||
<dd><span class="ui star rating" data-rating="{{ review.overallRating }}" data-max-rating="5"></span></dd>
|
||||
{% endif %}
|
||||
{% if review.valueForMoney %}
|
||||
<dt>Value for money</dt>
|
||||
<dd><span class="ui star rating" data-rating="{{ review.valueForMoney }}" data-max-rating="5"></span></dd>
|
||||
{% endif %}
|
||||
{% if review.playability %}
|
||||
<dt>Playability</dt>
|
||||
<dd><span class="ui star rating" data-rating="{{ review.playability }}" data-max-rating="5"></span></dd>
|
||||
{% endif %}
|
||||
{% if review.parts %}
|
||||
<dt>Parts</dt>
|
||||
<dd><span class="ui star rating" data-rating="{{ review.parts }}" data-max-rating="5"></span></dd>
|
||||
{% endif %}
|
||||
{% if review.buildingExperience %}
|
||||
<dt>Building experience</dt>
|
||||
<dd><span class="ui star rating" data-rating="{{ review.buildingExperience }}" data-max-rating="5"></span></dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
</a>
|
||||
<div class="column twelve wide comment">
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<h2>{{ review.title }}</h2>
|
||||
@ -24,12 +52,8 @@
|
||||
<p>{{ review.review }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
Overall rating <div class="ui star rating" data-rating="{{ review.overallRating }}" data-max-rating="5"></div>
|
||||
Value for money <div class="ui star rating" data-rating="{{ review.valueForMoney }}" data-max-rating="5"></div>
|
||||
Playability <div class="ui star rating" data-rating="{{ review.playability }}" data-max-rating="5"></div>
|
||||
Parts <div class="ui star rating" data-rating="{{ review.parts }}" data-max-rating="5"></div>
|
||||
Building experience <div class="ui star rating" data-rating="{{ review.buildingExperience }}" data-max-rating="5"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,39 +1,70 @@
|
||||
{% macro modelImageMin(model, color) %}
|
||||
{% macro partImage(number, filter, color = -1) %}
|
||||
{% if filter == 'part_large' %}
|
||||
{% set placeholder = asset("resources/images/unknown_large.png") %}
|
||||
{% else %}
|
||||
{% set placeholder = asset("resources/images/unknown.png") %}
|
||||
{% endif %}
|
||||
|
||||
<div class="image load">
|
||||
<img src="{{ asset('/images/'~color~'/'~model.number~'.png') | imagine_filter('media_min') }}">
|
||||
<img src="{{ placeholder }}" data-src="{{ asset(color~'/'~number~'.png') | imagine_filter(filter)}}">
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro modelImageLarge(model, color) %}
|
||||
<div class="image">
|
||||
<img src="{{ asset('/images/'~color~'/'~model.number~'.png')|imagine_filter('media_large') }}">
|
||||
{% macro setImage(number, filter) %}
|
||||
<div class="image load">
|
||||
{% if filter == 'set_large' %}
|
||||
{% set placeholder = asset("resources/images/unknown_large.png") %}
|
||||
{% else %}
|
||||
{% set placeholder = asset("resources/images/unknown.png") %}
|
||||
{% endif %}
|
||||
|
||||
<img src="{{ placeholder }}" data-src="{{ asset('/sets/'~number|lower~'.jpg')|imagine_filter(filter) }}">
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro model(model, quantity = null) %}
|
||||
<div class="column">
|
||||
<div class="ui bordered fluid image">
|
||||
{% macro model(model, quantity = null, color = -1) %}
|
||||
<div class="column model">
|
||||
<a href="{{ url('model_detail', {'number': model.number})}}">
|
||||
<div class="ui bordered fluid image">
|
||||
{% import _self as blocks %}
|
||||
{{ blocks.modelImageMin(model, -1) }}
|
||||
<div class="ui bottom attached label">{% if quantity %}{{ quantity }}x{% endif %} {{ model.number }}</div>
|
||||
{{ blocks.partImage(model.number, 'part_min', color) }}
|
||||
</div>
|
||||
<div class="model-meta">
|
||||
<span class="quantity"></span> {% if quantity %}{{ quantity }}x{% endif %}<span class="number">{{ model.number }}</span>
|
||||
{#<span class="name">{{ model.name }}</span>#}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro part(part, quantity, color = -1) %}
|
||||
{% macro part(part, quantity = null, color = -1) %}
|
||||
<div class="column">
|
||||
<div class="ui bordered fluid image">
|
||||
<div class="ui color-{{ color }} bordered fluid image">
|
||||
<a href="{{ url('reb_part_detail', {'number': part.number})}}">
|
||||
{% import _self as blocks %}
|
||||
{#{{ blocks.partImage(part.number, -1) }}#}
|
||||
<div class="ui bottom attached label">{{ quantity }}x {{ part.number }}</div>
|
||||
{{ blocks.partImage(part.number,'part_min', color) }}
|
||||
<div class="part-meta">
|
||||
<span class="quantity"></span> {% if quantity %}{{ quantity }}x{% endif %}<span class="number">{{ part.number }}</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro set(set) %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.number}) }}">
|
||||
<div class="ui bordered fluid image">
|
||||
{{ blocks.setImage(set.number,'set_min') }}
|
||||
</div>
|
||||
<div class="set-meta">
|
||||
<p>{{ set.number }}</p>
|
||||
<p>{{ set.name }}</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro empty(message) %}
|
||||
<p class="ui center aligned icon header"><i class="circular frown icon"></i>{{ message }}</p>
|
||||
{% endmacro %}
|
||||
@ -41,3 +72,4 @@
|
||||
{% macro ccal2_license(title,author) %}
|
||||
"{{ title }}" by {{ author }}, used under <a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a> / Converted to stl from original
|
||||
{% endmacro %}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
|
||||
{% block title %}#{{ model.number }} - {{ model.name }}{% endblock %}
|
||||
|
||||
{% block header %}#{{ model.number }} - {{ model.name }}{% endblock %}
|
||||
@ -9,16 +11,15 @@
|
||||
<div class="ui grid">
|
||||
<div class="column ten wide">
|
||||
<div id="model-viewer" class="model-container">
|
||||
{{ blocks.modelImageLarge(model, -1) }}
|
||||
{{ blocks.partImage(model.number,'part_large') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column six wide">
|
||||
<div class="item-info ui">
|
||||
<a class="ui download primary button" href="{{ path('model_zip', {number: model.number}) }}">{{ 'model.download'|trans }}</a>
|
||||
|
||||
<table class="ui very basic table">
|
||||
<tr>
|
||||
<td>{{ 'model.category' | trans }}</td><td>{{ model.category ? model.category.name }}</td>
|
||||
<td>{{ 'model.category' | trans }}</td>
|
||||
<td><a href="{{ path('model_index',{}) }}">{{ model.category ? model.category.name }}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'model.author' | trans }}</td><td>{{ model.author.name }}</td>
|
||||
@ -51,6 +52,9 @@
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
<a class="ui download primary button" href="{{ path('model_zip', {number: model.number}) }}">{{ 'model.download'|trans }}</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -66,12 +70,8 @@
|
||||
|
||||
<div class="ui tab active" data-tab="subparts">
|
||||
<div class="ui eight column grid">
|
||||
{% for subpart in model.subparts %}
|
||||
<div class="column">
|
||||
{{ blocks.part(subpart.subpart) }}
|
||||
<p>{{ subpart.count }}</p>
|
||||
<p style="border-bottom: 2px solid #{{ subpart.color.rgb }}">color: {{ subpart.color.name }}</p>
|
||||
</div>
|
||||
{% for subpart in subparts %}
|
||||
{{ blocks.model(subpart['model'], subpart['quantity']) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@ -80,7 +80,7 @@
|
||||
<div class="ui eight column grid">
|
||||
{% for subpart in related %}
|
||||
<div class="column">
|
||||
{{ blocks.part(subpart) }}
|
||||
{{ blocks.model(subpart) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
@ -90,16 +90,25 @@
|
||||
<div class="ui eight column grid">
|
||||
{% for subpart in model.parents %}
|
||||
<div class="column">
|
||||
{{ blocks.part(subpart.parent) }}
|
||||
{{ blocks.model(subpart.parent) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui tab" data-tab="sets">
|
||||
{% for set in sets %}
|
||||
<span style="margin: 5px"><a href="{{ url('set_detail', {number:set.number}) }}">{{ set.number }}</a></span>
|
||||
{% endfor %}
|
||||
<div class="ui six column doubling grid">
|
||||
<div class="row">
|
||||
{#{% for set in sets %}#}
|
||||
{#<div class="column">#}
|
||||
{#<a href="{{ url('set_detail', {number:set.number}) }}">#}
|
||||
{#{{ blocks.setImage(set.number,'set_min') }}#}
|
||||
{#<h5>{{ set.number }}</h5>#}
|
||||
{#</a>#}
|
||||
{#</div>#}
|
||||
{#{% endfor %}#}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
|
||||
{% block title %}{{ 'page.model.index' | trans }}{% endblock %}
|
||||
|
||||
{% block header %}{{ 'page.model.index' | trans }}{% endblock %}
|
||||
@ -14,7 +16,7 @@
|
||||
{{ form_row(form.search) }}
|
||||
<div class="field fluid search selection">
|
||||
{{ form_label(form.category.id) }}
|
||||
{{ form_widget(form.category.id) }}
|
||||
{{ form_widget(form.category.id)}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<input class="ui submit button" type="submit" value="filter"/>
|
||||
@ -23,16 +25,15 @@
|
||||
</form>
|
||||
</div>
|
||||
<div class="column twelve wide">
|
||||
<div class="ui spacing 20">
|
||||
<div class="ui eight column doubling grid">
|
||||
<div class="ui six column doubling grid">
|
||||
{% for model in models %}
|
||||
{{ blocks.model(model) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui column vertical segment noborder">
|
||||
{{ knp_pagination_render(models) }}
|
||||
<p>{{ models.getTotalItemCount }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% import 'macros/elements.html.twig' as elements %}
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
|
||||
{% block header %}#{{ part.number }} - {{ part.name }}{% endblock %}
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<div class="ui grid">
|
||||
<div class="column ten wide">
|
||||
<div id="model-viewer" class="model-container">
|
||||
<img src="{{ apiPart.imgUrl }}">
|
||||
{{ blocks.partImage(part.number,'part_large') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column six wide">
|
||||
@ -21,7 +21,7 @@
|
||||
<td>{{ 'part.name' | trans }}</td><td>{{ part.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'part.category' | trans }}</td><td>{{ part.category.name }}</td>
|
||||
<td>{{ 'part.category' | trans }}</td><td>{{ part.category ? part.category.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'part.model' | trans }}</td>
|
||||
@ -48,6 +48,13 @@
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><a href="{{ apiPart.url }}">Rebrickable</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
{{ dump(apiPart.externalIds, apiPart) }}
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
@ -63,9 +70,7 @@
|
||||
<div class="column">
|
||||
<div class="ui fluid bordered image">
|
||||
<a href="{{ url('set_detail', {number:set.number}) }}">
|
||||
<div class="image load">
|
||||
<img class="ui bordered" src="{{ asset('resources/images/unknown_image.png') }}" data-src="{{ set.number|setImage|imagine_filter('rebrickable_min') }}">
|
||||
</div>
|
||||
{{ blocks.setImage(set.number,'set_min') }}
|
||||
<div class="ui bottom attached label">{{ set.number }}<br></div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -1,44 +1,38 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}{{ set ? set.number }} {{ set ? set.name }}{% endblock %}
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
|
||||
{% block header %}{{ set ? set.number }} {{ set ? set.name | escape('html') }}{% endblock %}
|
||||
{% block title %}{{ set.number }} {{ set.name }}{% endblock %}
|
||||
|
||||
{% block header %}{{ set.number }} {{ set.name | escape('html') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="ui stackable grid">
|
||||
<div class="column nine wide">
|
||||
<div class="image bordered ui big">
|
||||
{% if brset %}
|
||||
<img class="big" src="{{ ('/sets/images/'~brset.legoSetID~'.jpg')|imagine_filter('brickset_large') }}">
|
||||
{% else %}
|
||||
<img class="big" src="{{ set.number|setImage|imagine_filter('rebrickable_large') }}">
|
||||
{% endif %}
|
||||
<div class="ui bordered fluid image">
|
||||
{{ blocks.setImage(set.number,'set_large') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column seven wide">
|
||||
<div class="item-info ui">
|
||||
<table class="ui very basic table">
|
||||
<tr>
|
||||
<td>{{ 'set.number' | trans }}</td><td>{{ brset ? brset.legoSetID : set ? set.number : null}}</td>
|
||||
<td>{{ 'set.number' | trans }}</td><td>{{ set.number }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'set.name' | trans }}</td><td>{{ brset ? brset.name : set ? set.name : null}}</td>
|
||||
<td>{{ 'set.name' | trans }}</td><td>{{ set.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'set.year' | trans }}</td><td>{{ brset ? brset.year : set ? set.year : null}}</td>
|
||||
<td>{{ 'set.year' | trans }}</td><td>{{ set.year }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'set.theme' | trans }}</td>
|
||||
{% if set %}
|
||||
<td><a href="#">{{ set.theme.parent ? set.theme.parent.name }}</a> <a href="#">{{ set.theme.name }}</a> </td>
|
||||
{% elseif brset %}
|
||||
<td>{{ brset.theme }}</td>
|
||||
{% endif %}
|
||||
<td><a href="#">{{ set.theme.parent ? set.theme.parent.name }}</a> > <a href="#">{{ set.theme ? set.theme.name }}</a> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ 'set.parts' | trans }}</td><td>
|
||||
{{ set ? set.partCount }} {{ brset ? '('~brset.pieces~')' }}
|
||||
{{ set.partCount }} {{ brset ? '('~brset.pieces~')' }}
|
||||
</td>
|
||||
</tr>
|
||||
{% if brset %}
|
||||
@ -64,22 +58,39 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<a class="ui download primary button">{{ 'set.download'|trans }}</a>
|
||||
<div class="ui download flowing popup bottom center transition hidden">
|
||||
|
||||
<div class="ui primary open-modal button">{{ 'set.download' | trans }}</div>
|
||||
|
||||
{% embed 'embeds/modal.html.twig' %}
|
||||
{% block title %}
|
||||
{{ 'set.download.title' | trans({'%set%': set.number~' '~set.name}) }}
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
{#<div class="ui icon message">#}
|
||||
{#<i class="warning icon"></i>#}
|
||||
{#<div class="content">#}
|
||||
{#<div class="header">#}
|
||||
{#{{ 'set.download.warning.title' | trans }}#}
|
||||
{#</div>#}
|
||||
{#<p> {{ 'set.download.warning.text' | trans }}</p>#}
|
||||
{#</div>#}
|
||||
{#</div>#}
|
||||
{% endblock %}
|
||||
{% block actions %}
|
||||
<div class="ui two column divided center aligned grid">
|
||||
<div class="column">
|
||||
<h4 class="ui header">{{ 'set.download.sorted' }}</h4>
|
||||
<h4 class="ui header">{{ 'set.download.sorted.title' | trans }}</h4>
|
||||
<p>{{ 'set.download.sorted.text' | trans }}</p>
|
||||
<a class="ui button" href="{{ path('set_zip', {number: set.number, sorted: true }) }}" download>Download ZIP</a>
|
||||
<a class="ui download button" href="{{ path('set_zip', {number: set.number, sorted: true }) }}" download>Download ZIP</a>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4 class="ui header">{{ 'set.download.unsorted' }}</h4>
|
||||
<h4 class="ui header">{{ 'set.download.unsorted.title' | trans }}</h4>
|
||||
<p>{{ 'set.download.unsorted.text' | trans }}</p>
|
||||
<a class="ui button" href="{{ path('set_zip', {number: set.number, sorted: false }) }}" download>Download ZIP</a>
|
||||
<a class="ui download button" href="{{ path('set_zip', {number: set.number, sorted: false }) }}" download>Download ZIP</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@ -97,11 +108,19 @@
|
||||
</div>
|
||||
<div class="ui vertical segment">
|
||||
<div class="ui tab active" data-tab="parts">
|
||||
{#<div class="ui icon buttons right floated">#}
|
||||
{#<button class="ui button"><i class="grid layout icon"></i></button>#}
|
||||
{#<button class="ui button"><i class="list layout icon"></i></button>#}
|
||||
{#</div>#}
|
||||
|
||||
<p>{{ 'set.models.text' | trans({'%rebrickable%' : partCount, '%brickset%' : brset ? brset.pieces }) | nl2br }}</p>
|
||||
|
||||
<div class="ajax-load" data-src="{{ path('set_models', { 'number': set.number }) }}">
|
||||
<div class="ui active centered inline loader"></div>
|
||||
</div>
|
||||
|
||||
{#{{ render(path('set_colors', {number: set.number})) }}#}
|
||||
{#{{ render(path('set_models', {number: set.number})) }}#}
|
||||
{{ render(path('set_sets', {number: set.number})) }}
|
||||
</div>
|
||||
{% if brset %}
|
||||
<div class="ui tab ajax-load" data-tab="description" data-src="{{ path('brickset_description', { 'id': brset.setID }) }}">
|
||||
|
@ -1,5 +1,7 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
|
||||
{% block title %}{{ 'page.set.index' | trans }}{% endblock %}
|
||||
|
||||
{% block header %}{{ 'page.set.index' | trans }}{% endblock %}
|
||||
@ -18,6 +20,7 @@
|
||||
{{ form_widget(form.theme.id) }}
|
||||
</div>
|
||||
<div class="field">
|
||||
<div id="slider"></div>
|
||||
{{ form_row(form.partCount) }}
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -33,15 +36,10 @@
|
||||
</div>
|
||||
<div class="column twelve wide">
|
||||
<div class="segment vertical">
|
||||
<div class="ui six column doubling grid">
|
||||
<div class="ui five column doubling grid">
|
||||
<div class="row">
|
||||
{% for set in sets %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.number}) }}">
|
||||
<img class="ui bordered image medium" src="{{ set.number|setImage|imagine_filter('rebrickable_min') }}">
|
||||
<p>{{ set.number }} - {{ set.name }}</p>
|
||||
</a>
|
||||
</div>
|
||||
{{ set(set) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@ -56,6 +54,4 @@
|
||||
{% block javascripts %}
|
||||
{{ parent() }}
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
@ -10,7 +10,7 @@
|
||||
|
||||
<div class="ui ten column grid">
|
||||
{% for model in color['models'] %}
|
||||
{{ blocks.model(model['model'],model['quantity']) }}
|
||||
{{ blocks.model(model['model'],model['quantity'], color['color'].id) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
<div class="ui ten column grid">
|
||||
{% for inventoryPart in regularParts %}
|
||||
{{ blocks.part(inventoryPart.part,inventoryPart.quantity, inventoryPart.color) }}
|
||||
{{ blocks.part(inventoryPart.part.number,inventoryPart.quantity, inventoryPart.color.id) }}
|
||||
{{ inventoryPart.color.id }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -19,7 +20,7 @@
|
||||
</h4>
|
||||
<div class="ui ten column grid">
|
||||
{% for inventoryPart in missing %}
|
||||
{{ blocks.part(inventoryPart.part,inventoryPart.quantity, inventoryPart.color) }}
|
||||
{{ blocks.part(inventoryPart.part.number,inventoryPart.quantity, inventoryPart.color.id) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@ -30,7 +31,7 @@
|
||||
</h4>
|
||||
<div class="ui ten column grid">
|
||||
{% for inventoryPart in spareParts %}
|
||||
{{ blocks.part(inventoryPart.part,inventoryPart.quantity, inventoryPart.color) }}
|
||||
{{ blocks.part(inventoryPart.part.number,inventoryPart.quantity, inventoryPart.color.id) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -1,13 +1,14 @@
|
||||
{% extends 'ajax.html.twig' %}
|
||||
|
||||
{% import 'macros/blocks.html.twig' as blocks %}
|
||||
|
||||
{% block content %}
|
||||
<p>{{ 'set.models.text' | trans | nl2br }}</p>
|
||||
|
||||
{% if models|length > 0 %}
|
||||
<h4 class="ui horizontal divider header">
|
||||
Regular parts
|
||||
Models
|
||||
</h4>
|
||||
<div class="ui segment vertical">
|
||||
<div class="ui segment vertical noborder">
|
||||
<div class="ui grid">
|
||||
<div class="doubling ten column row">
|
||||
{% for model in models %}
|
||||
@ -17,44 +18,43 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if missing|length > 0 %}
|
||||
<h4 class="ui horizontal divider header">
|
||||
Missing regular models
|
||||
Missing models
|
||||
</h4>
|
||||
<div class="ui segment vertical">
|
||||
<div class="ui segment vertical noborder">
|
||||
<div class="ui ten column grid">
|
||||
{% for inventoryPart in missing %}
|
||||
{{ blocks.part(inventoryPart.part,inventoryPart.quantity) }}
|
||||
{% for part in missing %}
|
||||
{{ blocks.part(part['part'],part['quantity']) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if spareModels|length > 0 %}
|
||||
<h4 class="ui horizontal divider header">
|
||||
Spare parts
|
||||
</h4>
|
||||
{#{% if spareModels|length > 0 %}#}
|
||||
{#<h4 class="ui horizontal divider header">#}
|
||||
{#Spare parts#}
|
||||
{#</h4>#}
|
||||
|
||||
<div class="ui segment vertical">
|
||||
<div class="ui ten column grid">
|
||||
{% for model in spareModels %}
|
||||
{{ blocks.model(model['model'],model['quantity']) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{#<div class="ui segment vertical">#}
|
||||
{#<div class="ui ten column grid">#}
|
||||
{#{% for model in spareModels %}#}
|
||||
{#{{ blocks.model(model['model'],model['quantity']) }}#}
|
||||
{#{% endfor %}#}
|
||||
{#</div>#}
|
||||
{#</div>#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{% if missingSpare|length > 0 %}
|
||||
<h4 class="ui horizontal divider header">
|
||||
Missing spare models
|
||||
</h4>
|
||||
<div class="ui segment vertical">
|
||||
<div class="ui ten column grid segment">
|
||||
{% for inventoryPart in missingSpare %}
|
||||
{{ blocks.part(inventoryPart.part,inventoryPart.quantity) }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{#{% if missingSpare|length > 0 %}#}
|
||||
{#<h4 class="ui horizontal divider header">#}
|
||||
{#Missing spare models#}
|
||||
{#</h4>#}
|
||||
{#<div class="ui segment vertical">#}
|
||||
{#<div class="ui ten column grid segment">#}
|
||||
{#{% for inventoryPart in missingSpare %}#}
|
||||
{#{{ blocks.part(inventoryPart.part.number,inventoryPart.quantity, inventoryPart.color.id) }}#}
|
||||
{#{% endfor %}#}
|
||||
{#</div>#}
|
||||
{#</div>#}
|
||||
{#{% endif %}#}
|
||||
{% endblock %}
|
@ -1,20 +1,20 @@
|
||||
{% extends 'ajax.html.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% if inventorySets %}
|
||||
<h4 class="ui horizontal divider header">Sets</h4>
|
||||
<div class="ui seven column grid">
|
||||
<div class="row">
|
||||
{% for set in inventorySets %}
|
||||
{% for inventorySet in inventorySets %}
|
||||
<div class="column">
|
||||
<a href="{{ url('set_detail', {'number': set.set.number}) }}">
|
||||
<div class="ui bordered image medium">
|
||||
<img src="{{ asset('resources/images/unknown_image.png') }}" data-src="{{ set.set.number|setImage|imagine_filter('rebrickable_set_min') }}" class="transition visible">
|
||||
</div>
|
||||
<p>{{ set.set.number }} - {{ set.set.name }}</p>
|
||||
<p>{{ set.quantity}}</p>
|
||||
<a href="{{ url('set_detail', {'number': inventorySet.set.number}) }}">
|
||||
{{ blocks.setImage(inventorySet.set.number,'set_min') }}
|
||||
<p>{{ inventorySet.set.number }} - {{ inventorySet.set.name }}</p>
|
||||
<p>{{ inventorySet.quantity}}</p>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -111,9 +111,6 @@ knp_paginator:
|
||||
|
||||
liip_imagine:
|
||||
loaders:
|
||||
media:
|
||||
flysystem:
|
||||
filesystem_service: oneup_flysystem.media_filesystem
|
||||
rebrickable:
|
||||
stream:
|
||||
wrapper: 'http://rebrickable.com/media/'
|
||||
@ -121,49 +118,11 @@ liip_imagine:
|
||||
stream:
|
||||
wrapper: 'https://images.brickset.com/'
|
||||
|
||||
|
||||
resolvers:
|
||||
default:
|
||||
web_path: ~
|
||||
|
||||
filter_sets:
|
||||
media:
|
||||
data_loader: media
|
||||
media_min:
|
||||
data_loader: media
|
||||
cache: ~
|
||||
quality: 80
|
||||
filters:
|
||||
thumbnail: { size: [200, 200], mode: inset }
|
||||
background: { size: [250, 250], position: center, color: '#FFFFFF' }
|
||||
media_large:
|
||||
data_loader: media
|
||||
cache: ~
|
||||
quality: 92
|
||||
filters:
|
||||
thumbnail: { size: [840, 580], mode: inset }
|
||||
background: { size: [900, 600], position: center, color: '#FFFFFF' }
|
||||
|
||||
rebrickable:
|
||||
data_loader: rebrickable
|
||||
rebrickable_min:
|
||||
quality: 80
|
||||
data_loader: rebrickable
|
||||
default_image: '/resources/images/unknown_image.png'
|
||||
cache: ~
|
||||
filters:
|
||||
thumbnail: { size: [200, 200], mode: inset }
|
||||
background: { size: [250, 250], position: center, color: '#FFFFFF' }
|
||||
rebrickable_large:
|
||||
data_loader: rebrickable
|
||||
cache: ~
|
||||
quality: 92
|
||||
filters:
|
||||
thumbnail: { size: [840, 580], mode: inset }
|
||||
background: { size: [900, 600], position: center, color: '#FFFFFF' }
|
||||
|
||||
brickset:
|
||||
data_loader: brickset
|
||||
brickset_large:
|
||||
data_loader: brickset
|
||||
cache: ~
|
||||
@ -171,6 +130,37 @@ liip_imagine:
|
||||
filters:
|
||||
thumbnail: { size: [840, 580], mode: inset }
|
||||
background: { size: [900, 600], position: center, color: '#FFFFFF' }
|
||||
|
||||
|
||||
set_min:
|
||||
quality: 80
|
||||
data_loader: rebrickable
|
||||
cache: ~
|
||||
filters:
|
||||
thumbnail: { size: [200, 200], mode: inset }
|
||||
background: { size: [250, 250], position: center, color: '#FFFFFF' }
|
||||
set_large:
|
||||
data_loader: rebrickable
|
||||
cache: ~
|
||||
quality: 92
|
||||
filters:
|
||||
thumbnail: { size: [840, 580], mode: inset }
|
||||
background: { size: [900, 600], position: center, color: '#FFFFFF' }
|
||||
part_large:
|
||||
data_loader: part_image_loader
|
||||
cache: ~
|
||||
quality: 92
|
||||
filters:
|
||||
thumbnail: { size: [840, 580], mode: inset }
|
||||
background: { size: [900, 600], position: center, color: '#FFFFFF' }
|
||||
part_min:
|
||||
quality: 80
|
||||
data_loader: part_image_loader
|
||||
default_image: "noimage.png"
|
||||
cache: ~
|
||||
filters:
|
||||
thumbnail: { size: [200, 200], mode: inset }
|
||||
background: { size: [250, 250], position: center, color: '#FFFFFF' }
|
||||
oneup_flysystem:
|
||||
adapters:
|
||||
media:
|
||||
|
@ -17,4 +17,9 @@ services:
|
||||
|
||||
service.set:
|
||||
class: AppBundle\Service\SetService
|
||||
arguments: ['@repository.rebrickable.inventorypart']
|
||||
arguments: ['@repository.rebrickable.inventorypart'] arguments: ['@repository.rebrickable.inventorypart'] app.part_image_loader:
|
||||
app.part_image_loader:
|
||||
class: AppBundle\Imagine\PartImageLoader
|
||||
arguments: ['@api.manager.rebrickable', '@oneup_flysystem.media_filesystem']
|
||||
tags:
|
||||
- { name: liip_imagine.binary.loader, loader: part_image_loader }
|
79
src/AppBundle/Imagine/PartImageLoader.php
Normal file
79
src/AppBundle/Imagine/PartImageLoader.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace AppBundle\Imagine;
|
||||
|
||||
use AppBundle\Api\Manager\RebrickableManager;
|
||||
use League\Flysystem\Filesystem;
|
||||
use Liip\ImagineBundle\Binary\Loader\LoaderInterface;
|
||||
use Liip\ImagineBundle\Exception\Binary\Loader\NotLoadableException;
|
||||
|
||||
class PartImageLoader implements LoaderInterface
|
||||
{
|
||||
/** @var Filesystem */
|
||||
private $mediaFilesystem;
|
||||
|
||||
/** @var RebrickableManager */
|
||||
private $rebrickableManager;
|
||||
|
||||
private $rebrickableContext = 'http://rebrickable.com/media/parts/ldraw/';
|
||||
|
||||
/**
|
||||
* LocalStreamLoader constructor.
|
||||
*
|
||||
* @param $rebrickableManager
|
||||
* @param $mediaFilesystem
|
||||
*/
|
||||
public function __construct($rebrickableManager, $mediaFilesystem)
|
||||
{
|
||||
$this->mediaFilesystem = $mediaFilesystem;
|
||||
$this->rebrickableManager = $rebrickableManager;
|
||||
}
|
||||
|
||||
public function find($path)
|
||||
{
|
||||
// try to load image from local mediaFilesystem
|
||||
if ($this->mediaFilesystem->has('/images/'.$path)) {
|
||||
return $this->mediaFilesystem->read('/images/'.$path);
|
||||
}
|
||||
|
||||
// try to load image from rebrickable website
|
||||
try {
|
||||
if ($this->remoteFileExists($this->rebrickableContext.$path)) {
|
||||
return file_get_contents($this->rebrickableContext.$path);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new NotLoadableException(sprintf('Source image %s could not be loaded.', $path), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
// Load part entity form rebrickable api and get image path from response
|
||||
try {
|
||||
if (preg_match('/^(.*)\/(.*).png$/', $path, $match)) {
|
||||
$part = $this->rebrickableManager->getPart($match[2]);
|
||||
|
||||
if ($part && $part->getImgUrl()) {
|
||||
return file_get_contents($part->getImgUrl());
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
throw new NotLoadableException(sprintf('Source image %s could not be loaded.', $path), $e->getCode(), $e);
|
||||
}
|
||||
|
||||
return $this->mediaFilesystem->read('noimage.png');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function remoteFileExists($url)
|
||||
{
|
||||
$resource = curl_init($url);
|
||||
curl_setopt($resource, CURLOPT_NOBODY, true);
|
||||
curl_exec($resource);
|
||||
$status = curl_getinfo($resource, CURLINFO_HTTP_CODE);
|
||||
curl_close($resource);
|
||||
|
||||
return $status === 200 ? true : false;
|
||||
}
|
||||
}
|
@ -2,33 +2,26 @@
|
||||
|
||||
namespace AppBundle\Twig;
|
||||
|
||||
use AppBundle\Api\Manager\RebrickableManager;
|
||||
use AppBundle\Transformer\FormatTransformer;
|
||||
|
||||
class AppExtension extends \Twig_Extension
|
||||
{
|
||||
/** @var RebrickableManager */
|
||||
private $rebrickableAPIManager;
|
||||
|
||||
/** @var FormatTransformer */
|
||||
private $formatTransformer;
|
||||
|
||||
/**
|
||||
* AppExtension constructor.
|
||||
*
|
||||
* @param RebrickableManager $rebrickableAPIManager
|
||||
* @param FormatTransformer $formatTransformer
|
||||
*/
|
||||
public function __construct($rebrickableAPIManager, $formatTransformer)
|
||||
public function __construct($formatTransformer)
|
||||
{
|
||||
$this->rebrickableAPIManager = $rebrickableAPIManager;
|
||||
$this->formatTransformer = $formatTransformer;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new \Twig_SimpleFilter('partImage', [$this, 'partImage']),
|
||||
new \Twig_SimpleFilter('setImage', [$this, 'setImage']),
|
||||
new \Twig_SimpleFilter('bytesToSize', [$this, 'bytesToSize']),
|
||||
];
|
||||
}
|
||||
@ -38,23 +31,31 @@ class AppExtension extends \Twig_Extension
|
||||
return [
|
||||
new \Twig_SimpleFunction('remoteSize', [$this, 'remoteSize']),
|
||||
new \Twig_SimpleFunction('remoteFilename', [$this, 'remoteFilename']),
|
||||
new \Twig_SimpleFunction('remoteFileExists', [$this, 'remoteFileExists']),
|
||||
];
|
||||
}
|
||||
|
||||
public function partImage($number, $color = null)
|
||||
public function bytesToSize($bytes, $precision = 2)
|
||||
{
|
||||
return '/parts/ldraw/'.($color !== null ? $color : '-1').'/'.$number.'.png';
|
||||
}
|
||||
|
||||
public function setImage($number)
|
||||
{
|
||||
return '/sets/'.strtolower($number).'.jpg';
|
||||
}
|
||||
|
||||
public function bytesToSize($bytes, $precision = 2) {
|
||||
return $this->formatTransformer->bytesToSize($bytes, $precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function remoteFileExists($url)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_NOBODY, true);
|
||||
curl_exec($ch);
|
||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
return $status === 200 ? true : false;
|
||||
}
|
||||
|
||||
public function remoteSize($url)
|
||||
{
|
||||
$ch = curl_init($url);
|
||||
|
Loading…
x
Reference in New Issue
Block a user