Browse Source

Lists, reorganizing again

imwald
Nuša Pukšič 3 months ago
parent
commit
6feeaecaf5
  1. 4
      assets/styles/reading-lists.css
  2. 14
      src/Controller/ReadingListWizardController.php
  3. 1
      src/Form/CategoryArticlesType.php
  4. 4
      templates/components/ReadingListQuickInputComponent.html.twig
  5. 53
      templates/reading_list/compose.html.twig
  6. 2
      templates/reading_list/index.html.twig
  7. 4
      templates/reading_list/reading_articles.html.twig
  8. 30
      templates/reading_list/reading_review.html.twig

4
assets/styles/reading-lists.css

@ -117,3 +117,7 @@ @@ -117,3 +117,7 @@
.workflow-status-card .badge:hover {
transform: scale(1.05);
}
#aCollection li>div {
width: 100%;
}

14
src/Controller/ReadingListWizardController.php

@ -40,10 +40,15 @@ class ReadingListWizardController extends AbstractController @@ -40,10 +40,15 @@ class ReadingListWizardController extends AbstractController
}
#[Route('/reading-list/wizard/articles', name: 'read_wizard_articles')]
public function articles(Request $request): Response
public function articles(Request $request, ReadingListManager $readingListManager): Response
{
$draft = $this->getDraft($request);
if (!$draft) {
$loadSlug = $request->query->get('load');
if ($loadSlug) {
$draft = $readingListManager->loadPublishedListIntoDraft($loadSlug);
$this->saveDraft($request, $draft);
} elseif (!$draft) {
return $this->redirectToRoute('read_wizard_setup');
}
@ -61,6 +66,11 @@ class ReadingListWizardController extends AbstractController @@ -61,6 +66,11 @@ class ReadingListWizardController extends AbstractController
if (!$draft->slug) {
$draft->slug = $this->slugifyWithRandom($draft->title);
}
// If draft articles is still empty, remove the empty string we added
if (count($draft->articles) === 1 && $draft->articles[0] === '') {
$draft->articles = [];
}
$this->saveDraft($request, $draft);
return $this->redirectToRoute('read_wizard_review');
}

1
src/Form/CategoryArticlesType.php

@ -24,6 +24,7 @@ class CategoryArticlesType extends AbstractType @@ -24,6 +24,7 @@ class CategoryArticlesType extends AbstractType
->add('articles', CollectionType::class, [
'entry_type' => TextType::class,
'entry_options' => [
'required' => false,
'attr' => [
'placeholder' => '30023:pubkey:slug'
],

4
templates/components/ReadingListQuickInputComponent.html.twig

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<div {{ attributes }}>
<form data-action="live#action:prevent" data-live-action-param="addMultiple">
<div class="mb-3">
<label class="form-label">
<label class="form-label d-flex">
<strong>Paste article naddresses or coordinates</strong>
<small class="d-block text-muted">One per line. Supports both formats:</small>
<small class="d-block text-muted">• naddr1... (or nostr:naddr1...)</small>
@ -14,7 +14,9 @@ @@ -14,7 +14,9 @@
data-model="norender|input"
>{{ input }}</textarea>
</div>
<div class="actions">
<button type="submit" class="btn btn-primary">Add to Reading List</button>
</div>
</form>
{% if error %}

53
templates/reading_list/compose.html.twig

@ -15,40 +15,6 @@ @@ -15,40 +15,6 @@
</div>
{% endif %}
<div class="row g-4">
{# Left sidebar - Reading List Preview #}
<div class="col-lg-4">
<div class="sticky-top" style="top: 20px;">
<twig:ReadingListDraftComponent />
</div>
</div>
{# Main content - Simple tabbed interface #}
<div class="col-lg-8">
{# List Selector #}
<div class="card mb-3">
<div class="card-body">
<twig:ReadingListSelectorComponent />
</div>
</div>
{# Tabbed content #}
<ul class="nav nav-tabs mb-3" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="paste-tab" data-bs-toggle="tab" data-bs-target="#paste" type="button" role="tab">
📋 Paste Links
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="search-tab" data-bs-toggle="tab" data-bs-target="#search" type="button" role="tab">
🔍 Search
</button>
</li>
</ul>
<div class="tab-content">
{# Paste tab #}
<div class="tab-pane fade show active" id="paste" role="tabpanel">
<div class="card">
<div class="card-body">
<h5 class="card-title">Quick Add Articles</h5>
@ -56,20 +22,11 @@ @@ -56,20 +22,11 @@
<twig:ReadingListQuickInputComponent />
</div>
</div>
</div>
{# Search tab #}
<div class="tab-pane fade" id="search" role="tabpanel">
<div class="card">
<div class="card-body">
<h5 class="card-title">Search & Add Articles</h5>
<p class="text-muted small">Find articles and add them to your list</p>
<twig:SearchComponent :selectMode="true" currentRoute="compose" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block aside %}
{# Future sidebar content can go here #}
<twig:ReadingListDraftComponent />
{% endblock %}

2
templates/reading_list/index.html.twig

@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
<small class="text-muted">slug: {{ item.slug ?: '—' }} • created: {{ item.createdAt|date('Y-m-d H:i') }}</small>
</div>
<div class="d-flex flex-row gap-2">
<a class="btn btn-sm btn-primary" href="{{ path('reading_list_compose') }}">Open Composer</a>
<a class="btn btn-sm btn-primary" href="{{ path('read_wizard_articles', {'load': item.slug}) }}">Open Composer</a>
{% if item.slug %}
<a class="btn btn-sm btn-outline-primary" href="{{ path('reading-list', { slug: item.slug, npub: item.pubkey|toNpub }) }}">View</a>
<span data-controller="copy-to-clipboard">

4
templates/reading_list/reading_articles.html.twig

@ -15,13 +15,15 @@ @@ -15,13 +15,15 @@
{{ stimulus_controller('form-collection') }}
data-form-collection-index-value="{{ form.articles|length > 0 ? form.articles|last.vars.name + 1 : 0 }}"
data-form-collection-prototype-value="{{ form_widget(form.articles.vars.prototype)|e('html_attr') }}">
<ul class="d-flex gap-2 list-unstyled" {{ stimulus_target('form-collection', 'collectionContainer') }}>
<ul id="aCollection" class="d-flex gap-2 list-unstyled" {{ stimulus_target('form-collection', 'collectionContainer') }}>
{% for item in form.articles %}
<li class="d-flex flex-row">{{ form_row(item) }}</li>
{% endfor %}
</ul>
<div class="actions">
<button type="button" class="btn btn-secondary mt-2" {{ stimulus_action('form-collection', 'addCollectionElement') }}>Add article</button>
</div>
</div>
<div class="mt-3 d-flex flex-row gap-2 actions">
<a class="btn btn-secondary" href="{{ path('read_wizard_setup') }}">Back</a>

30
templates/reading_list/reading_review.html.twig

@ -4,7 +4,10 @@ @@ -4,7 +4,10 @@
<h1>Review & Sign Reading List</h1>
<div class="notice info">
<p>Review your reading list. When ready, click Sign & Publish. Your NIP-07 extension will be used to sign the event.</p>
{% if not is_granted('ROLE_USER') %}
<p>A Nostr identity is required so publish the list.</p>
{% endif %}
<p>Review your reading list. When ready, click Sign & Publish. Your NIP-07 extension or signer will be used to sign the event.</p>
</div>
<section class="mb-4">
@ -18,25 +21,20 @@ @@ -18,25 +21,20 @@
{% if draft.articles is defined and draft.articles|length %}
<div class="mt-2">
<strong>Articles:</strong>
<strong>Articles: {{ draft.articles|length }}</strong>
{% if draft.articles|length > 0 %}
<ul>
{% for a in draft.articles %}
<li><code>{{ a }}</code></li>
{% endfor %}
</ul>
</div>
{% else %}
<div class="mt-2"><small>No articles yet.</small></div>
{% endif %}
</section>
<section class="mb-4">
<details>
<summary>Show event preview (JSON)</summary>
<div class="mt-2">
<pre class="small">{{ eventJson }}</pre>
</div>
</details>
{% else %}
<div class="mt-2"><small>No articles yet.</small></div>
{% endif %}
</section>
<div
@ -46,17 +44,15 @@ @@ -46,17 +44,15 @@
csrfToken: csrfToken
}) }}
>
<section class="mb-3">
<h3>Final event (with your pubkey)</h3>
<pre class="small" data-nostr-single-sign-target="computedPreview"></pre>
</section>
<div class="d-flex flex-row gap-2">
<a class="btn btn-secondary" href="{{ path('read_wizard_cancel') }}">Cancel</a>
<button class="btn btn-primary" data-nostr-single-sign-target="publishButton" data-action="click->nostr-single-sign#signAndPublish">Sign & Publish</button>
</div>
<div class="mt-3" data-nostr-single-sign-target="status"></div>
<section class="mb-3">
<h3>Event preview</h3>
<pre class="small" data-nostr-single-sign-target="computedPreview"></pre>
</section>
</div>
{% endblock %}

Loading…
Cancel
Save