Refine survey list layout and backend active toggle

This commit is contained in:
Jürgen Mummert
2026-06-07 20:52:57 +02:00
parent 59514c6911
commit fb9a5b9ee6
5 changed files with 65 additions and 57 deletions
+2 -2
View File
@@ -59,11 +59,11 @@ $GLOBALS['TL_DCA']['tl_survey'] = [
'icon' => 'important.svg', 'icon' => 'important.svg',
'button_callback' => [SurveyDcaListener::class, 'generatePublishedWarningButton'], 'button_callback' => [SurveyDcaListener::class, 'generatePublishedWarningButton'],
], ],
'toggleActive' => [ 'toggle' => [
'label' => &$GLOBALS['TL_LANG']['tl_survey']['toggleActive'], 'label' => &$GLOBALS['TL_LANG']['tl_survey']['toggleActive'],
'href' => 'act=toggle&field=isActive', 'href' => 'act=toggle&field=isActive',
'icon' => 'visible.svg', 'icon' => 'visible.svg',
'button_callback' => [SurveyDcaListener::class, 'generateToggleActiveButton'], 'primary' => true,
], ],
'delete' => [ 'delete' => [
'href' => 'act=delete', 'href' => 'act=delete',
@@ -277,13 +277,13 @@
.survey-list-card { .survey-list-card {
display: grid; display: grid;
gap: 0.9rem; gap: 0.55rem;
padding: 1.1rem 1.15rem; padding: 0.9rem 1rem;
} }
.survey-list-card__head { .survey-list-card__head {
display: flex; display: flex;
gap: 1rem; gap: 0.75rem;
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: flex-start;
} }
@@ -322,10 +322,21 @@
.survey-list-card__stats { .survey-list-card__stats {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.85rem; gap: 0.45rem;
margin-top: 0.1rem;
}
.survey-list-stat {
display: inline-flex;
align-items: center;
padding: 0.34rem 0.62rem;
border-radius: 999px;
border: 1px solid rgba(0, 100, 173, 0.12);
background: rgba(255, 255, 255, 0.72);
color: var(--survey-gray-dark); color: var(--survey-gray-dark);
font-weight: 600; font-size: 0.78rem;
margin-top: 0.3rem; font-weight: 700;
line-height: 1;
} }
.survey-meta { .survey-meta {
@@ -379,7 +390,7 @@
transform: translateY(0); transform: translateY(0);
} }
.survey-visibility-eye { .survey-visibility-dot {
width: 2.75rem; width: 2.75rem;
height: 2.75rem; height: 2.75rem;
border-radius: 999px; border-radius: 999px;
@@ -392,41 +403,28 @@
transition: background 0.18s ease, border-color 0.18s ease; transition: background 0.18s ease, border-color 0.18s ease;
} }
.survey-visibility-eye__icon { .survey-visibility-dot__icon {
width: 1.25rem; width: 1rem;
height: 0.8rem; height: 1rem;
border: 2px solid currentColor;
border-radius: 99px;
position: relative;
color: #7f8793;
}
.survey-visibility-eye__icon::after {
content: "";
position: absolute;
width: 0.34rem;
height: 0.34rem;
border-radius: 50%; border-radius: 50%;
background: currentColor; background: #7f8793;
left: 50%; display: inline-block;
top: 50%;
transform: translate(-50%, -50%);
} }
.survey-visibility-eye.is-on { .survey-visibility-dot.is-on {
background: rgba(0, 174, 151, 0.2); background: rgba(0, 174, 151, 0.2);
border-color: rgba(0, 174, 151, 0.68); border-color: rgba(0, 174, 151, 0.68);
} }
.survey-visibility-eye.is-on .survey-visibility-eye__icon { .survey-visibility-dot.is-on .survey-visibility-dot__icon {
color: #0a8378; background: #0a8378;
} }
.survey-button-row { .survey-button-row {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0.75rem; gap: 0.5rem;
margin-top: 1rem; margin-top: 0.65rem;
} }
.survey-button-row--form-actions { .survey-button-row--form-actions {
@@ -517,7 +515,7 @@
justify-content: center; justify-content: center;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
padding: 0.8rem 1rem; padding: 0.72rem 0.95rem;
border-radius: 999px; border-radius: 999px;
border: 1px solid transparent; border: 1px solid transparent;
text-decoration: none; text-decoration: none;
@@ -525,6 +523,15 @@
cursor: pointer; cursor: pointer;
} }
.survey-list-card__actions .survey-button {
padding: 0.55rem 0.82rem;
font-size: 0.9rem;
}
.survey-editor-meta-card {
margin-bottom: 1rem;
}
.survey-button.primary { background: var(--survey-blue); color: #fff; } .survey-button.primary { background: var(--survey-blue); color: #fff; }
.survey-button.secondary { background: rgba(255,255,255,0.86); color: var(--survey-blue); border-color: rgba(0,100,173,0.18); } .survey-button.secondary { background: rgba(255,255,255,0.86); color: var(--survey-blue); border-color: rgba(0,100,173,0.18); }
.survey-button.danger { background: rgba(157, 82, 118, 0.12); color: var(--survey-purple); border-color: rgba(157, 82, 118, 0.22); } .survey-button.danger { background: rgba(157, 82, 118, 0.12); color: var(--survey-purple); border-color: rgba(157, 82, 118, 0.22); }
@@ -46,16 +46,33 @@
{{ form_end(surveyForm, {render_rest: false}) }} {{ form_end(surveyForm, {render_rest: false}) }}
</div> </div>
{% else %} {% else %}
{% set surveyMetaFormId = 'survey-meta-form' %}
{% set newQuestionFormId = 'survey-question-form-new' %}
<div class="survey-button-row survey-button-row--editor-actions"> <div class="survey-button-row survey-button-row--editor-actions">
{% if backUrl %}<a class="survey-button secondary" href="{{ backUrl }}">{{ 'survey.edit.back_to_list'|trans }}</a>{% endif %} {% if backUrl %}<a class="survey-button secondary" href="{{ backUrl }}">{{ 'survey.edit.back_to_list'|trans }}</a>{% endif %}
</div> </div>
{% if structureLocked|default(false) %} {% if not survey.published %}
<div class="survey-alert warning">{{ 'survey.edit.structure_locked'|trans }}</div> <div class="survey-card survey-editor-meta-card">
{{ form_start(surveyForm, {action: metadataFormActionUrl, attr: {class: 'survey-form-grid', id: surveyMetaFormId, 'data-survey-dirty-form': '1'}}) }}
<input type="hidden" name="REQUEST_TOKEN" value="{{ contao.request_token }}">
<input type="hidden" name="{{ surveyForm.published.vars.full_name }}" value="0">
{{ form_widget(surveyForm._token) }}
{{ form_errors(surveyForm) }}
<label class="survey-label">{{ 'survey.edit.label_survey_title'|trans }}{{ form_widget(surveyForm.title) }}{{ form_errors(surveyForm.title) }}</label>
<label class="survey-label">{{ 'survey.edit.label_description'|trans }}{{ form_widget(surveyForm.description) }}</label>
<div class="survey-button-row survey-button-row--form-actions">
<button class="survey-button primary">{{ 'survey.edit.save_metadata'|trans }}</button>
<div class="survey-dirty-hint" data-survey-dirty-hint-for="{{ surveyMetaFormId }}" hidden>{{ 'survey.edit.dirty_metadata'|trans }}</div>
</div>
{{ form_end(surveyForm, {render_rest: false}) }}
</div>
{% endif %} {% endif %}
{% set surveyMetaFormId = 'survey-meta-form' %} {% if structureLocked|default(false) and not survey.published %}
{% set newQuestionFormId = 'survey-question-form-new' %} <div class="survey-alert warning">{{ 'survey.edit.structure_locked'|trans }}</div>
{% endif %}
<div class="survey-grid-columns survey-editor-layout"> <div class="survey-grid-columns survey-editor-layout">
<div class="survey-question-editor-shell" data-survey-question-editor> <div class="survey-question-editor-shell" data-survey-question-editor>
@@ -60,15 +60,15 @@
<input type="hidden" name="_survey_action" value="toggle-active"> <input type="hidden" name="_survey_action" value="toggle-active">
<input type="hidden" name="item_id" value="{{ survey.id }}"> <input type="hidden" name="item_id" value="{{ survey.id }}">
<input type="hidden" name="_token" value="{{ csrf_token('toggle-active-' ~ survey.id) }}"> <input type="hidden" name="_token" value="{{ csrf_token('toggle-active-' ~ survey.id) }}">
<button type="submit" class="survey-visibility-eye{{ survey.isActive ? ' is-on' : '' }}" title="{{ survey.isActive ? 'survey.edit.deactivate_survey'|trans : 'survey.edit.activate_survey'|trans }}" aria-label="{{ survey.isActive ? 'survey.edit.deactivate_survey'|trans : 'survey.edit.activate_survey'|trans }}"> <button type="submit" class="survey-visibility-dot{{ survey.isActive ? ' is-on' : '' }}" title="{{ survey.isActive ? 'survey.edit.deactivate_survey'|trans : 'survey.edit.activate_survey'|trans }}" aria-label="{{ survey.isActive ? 'survey.edit.deactivate_survey'|trans : 'survey.edit.activate_survey'|trans }}">
<span class="survey-visibility-eye__icon" aria-hidden="true"></span> <span class="survey-visibility-dot__icon" aria-hidden="true"></span>
</button> </button>
</form> </form>
</div> </div>
</div> </div>
<div class="survey-list-card__stats"> <div class="survey-list-card__stats">
<span>{{ 'survey.list.questions'|trans({'%count%': survey.questionCount}) }}</span> <span class="survey-list-stat">{{ 'survey.list.questions'|trans({'%count%': survey.questionCount}) }}</span>
<span>{{ 'survey.list.participations'|trans({'%count%': survey.participationCount}) }}</span> <span class="survey-list-stat">{{ 'survey.list.participations'|trans({'%count%': survey.participationCount}) }}</span>
</div> </div>
<div class="survey-button-row survey-list-card__actions"> <div class="survey-button-row survey-list-card__actions">
{% if survey.editUrl %} {% if survey.editUrl %}
-16
View File
@@ -4,7 +4,6 @@ declare(strict_types=1);
namespace Mummert\SurveyBundle\EventListener; namespace Mummert\SurveyBundle\EventListener;
use Contao\Backend;
use Contao\Config; use Contao\Config;
use Contao\CoreBundle\Routing\ContentUrlGenerator; use Contao\CoreBundle\Routing\ContentUrlGenerator;
use Contao\CoreBundle\Framework\ContaoFramework; use Contao\CoreBundle\Framework\ContaoFramework;
@@ -105,21 +104,6 @@ final class SurveyDcaListener
); );
} }
public function generateToggleActiveButton(array $row, ?string $href, string $label, string $title, ?string $icon, string $attributes): string
{
$isActive = '1' === (string) ($row['isActive'] ?? '');
$icon = $isActive ? 'visible.svg' : 'invisible.svg';
$title = $isActive ? 'Umfrage vorübergehend deaktivieren' : 'Umfrage wieder aktivieren';
return sprintf(
'<a href="%s" title="%s"%s>%s</a>',
htmlspecialchars(Backend::addToUrl(($href ?? '').'&amp;id='.(int) ($row['id'] ?? 0)), ENT_QUOTES),
htmlspecialchars($title, ENT_QUOTES),
$attributes,
Image::getHtml($icon, $label)
);
}
/** /**
* @return array<int, string> * @return array<int, string>
*/ */