diff options
| author | Miquel Sabaté Solà <msabate@suse.com> | 2024-03-13 18:03:43 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <msabate@suse.com> | 2024-03-13 18:03:43 +0100 |
| commit | a7791635aa98f012d35f97c3c5288494bbb28e38 (patch) | |
| tree | bad987e6b4d10ad2f7cd02e40658d464907595ee /app/views | |
| download | operum-a7791635aa98f012d35f97c3c5288494bbb28e38.tar.gz operum-a7791635aa98f012d35f97c3c5288494bbb28e38.zip | |
Initial commit
Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
Diffstat (limited to 'app/views')
29 files changed, 504 insertions, 0 deletions
diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb new file mode 100644 index 0000000..49ba357 --- /dev/null +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -0,0 +1,14 @@ +<figure class="attachment attachment--<%= blob.representable? ? "preview" : "file" %> attachment--<%= blob.filename.extension %>"> + <% if blob.representable? %> + <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> + <% end %> + + <figcaption class="attachment__caption"> + <% if caption = blob.try(:caption) %> + <%= caption %> + <% else %> + <span class="attachment__name"><%= blob.filename %></span> + <span class="attachment__size"><%= number_to_human_size blob.byte_size %></span> + <% end %> + </figcaption> +</figure> diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb new file mode 100644 index 0000000..8c0975e --- /dev/null +++ b/app/views/comments/_comment.html.erb @@ -0,0 +1,42 @@ +<div id="<%= dom_id(comment) %>" class="comment"> + <div class="comment-header"> + <div class="comment-header-title"> + <% if defined?(idx) %> + <span title="Commented on <%= comment.created_at %>"><b><%= I18n.t('comments.title') %></b> #<%= idx + 1 %></span> + <% else %> + <span title="Commented on <%= comment.created_at %>"><b><%= I18n.t('comments.title') %></b> <%= I18n.t('general.in') %> <%= link_to comment.thing.title, thing_path(comment.thing) %></span> + <% end %> + </div> + + <div class="comment-header-actions"> + <% if defined?(from) %> + <a title="<%= I18n.t('comments.edit-title') %>" href="#" class="edit-comment" data-action="comment#toggle"><%= I18n.t('general.edit').capitalize %></a> + <%= link_to I18n.t('general.delete').capitalize, thing_comment_path(comment.thing, comment, from: from), data: { "turbo-method": :delete }, title: I18n.t('comments.delete-title'), class: 'delete-comment' %> + <% end %> + </div> + </div> + + <div class="comment-body"> + <%= comment.content %> + </div> + + <% if comment.tag_references.any? %> + <div class="comment-footer"> + <small><b><%= I18n.t('tags.title') %></b>: <%= comment.tags.order(:name).pluck(:name).join(", ") %></small> + </div> + <% end %> + + <% if defined?(from) %> + <div class="comment-edit-body hidden"> + <%= form_with model: [comment.thing, comment] do |form| %> + <%= form.hidden_field :from, value: from %> + <%= form.rich_text_area :content, autofocus: true %> + + <%= render "tags/taggable", tag_references: comment.tag_references.pluck(:tag_id), form: form %> + + <%= form.submit %> + <span><%= I18n.t('general.or') %> <a title="Cancel editing of comment" href="#" data-action="comment#toggle"><%= I18n.t('general.cancel') %></a></span> + <% end %> + </div> + <% end %> +</div> diff --git a/app/views/comments/_list.html.erb b/app/views/comments/_list.html.erb new file mode 100644 index 0000000..2396140 --- /dev/null +++ b/app/views/comments/_list.html.erb @@ -0,0 +1,30 @@ +<div id="comment-list" data-controller="comment"> + <h5><%= I18n.t('comments.title-plural') %></h5> + + <div> + <% if thing.comments.any? %> + <% thing.comments.each_with_index do |comment, idx| %> + <%= render comment, from: from, idx: idx %> + <% end %> + <% else %> + <p><%= I18n.t('comments.none') %>.</p> + <% end %> + </div> + + <div id="comment-new-section"> + <a id="comment-new-button" class="button" href="#" data-action="comment#toggleNewComment"><%= I18n.t('comments.new') %></a> + + <div id="comment-new-body" class="hidden"> + <%= form_with model: [thing, Comment.new] do |form| %> + <%= form.rich_text_area :content, size: "20x5", autofocus: true %> + + <%= form.hidden_field :from, value: from %> + + <%= render "tags/taggable", tag_references: [], form: form %> + + <%= form.submit %> + <span><%= I18n.t('general.or') %> <a title="<%= I18n.t('general.cancel') %>" href="#" data-action="comment#toggleNewComment"><%= I18n.t('general.cancel') %></a></span> + <% end %> + </div> + </div> +</div> diff --git a/app/views/exports/new.html.erb b/app/views/exports/new.html.erb new file mode 100644 index 0000000..73481a7 --- /dev/null +++ b/app/views/exports/new.html.erb @@ -0,0 +1,14 @@ +<div class="notice"><b><%= I18n.t('searches.export.note') %></b>: <%= I18n.t('searches.export.note-msg') %>.</div> + +<div data-controller="export"> + <div id="errors"></div> + + <input type="hidden" data-export-target="id" value="<%= @search.id %>" /> + + <select id="export-select-format" data-action="export#change"> + <option selected="selected" value="csv">CSV</option> + <option value="uoc">UOC</option> + </select> + + <a id="export-format-button" class="button" href="#">Export</a> +</div> diff --git a/app/views/exports/show.csv.erb b/app/views/exports/show.csv.erb new file mode 100644 index 0000000..43c7b82 --- /dev/null +++ b/app/views/exports/show.csv.erb @@ -0,0 +1 @@ +<%= CsvExporter.new(things: @results).export.html_safe %> diff --git a/app/views/exports/show.uoc.erb b/app/views/exports/show.uoc.erb new file mode 100644 index 0000000..b8f73b1 --- /dev/null +++ b/app/views/exports/show.uoc.erb @@ -0,0 +1,7 @@ +\chapter{<%= I18n.t('searches.export.chapter') %>} + +{\setlength{\parskip}{-0.3cm} + +<%= UocExporter.new(things: @results.order(:authors)).export %> + +} diff --git a/app/views/layouts/_errors.html.erb b/app/views/layouts/_errors.html.erb new file mode 100644 index 0000000..9e5ce38 --- /dev/null +++ b/app/views/layouts/_errors.html.erb @@ -0,0 +1,13 @@ +<% if model.errors.size.positive? %> + <div class="notice"> + <% if model.errors.size == 1 %> + <span><%= model.errors.first.full_message %>.</span> + <% else %> + <ul> + <% model.errors.each do |error| %> + <li><%= error.full_message %>.</li> + <% end %> + </ul> + <% end %> + </div> +<% end %> diff --git a/app/views/layouts/action_text/contents/_content.html.erb b/app/views/layouts/action_text/contents/_content.html.erb new file mode 100644 index 0000000..9e3c0d0 --- /dev/null +++ b/app/views/layouts/action_text/contents/_content.html.erb @@ -0,0 +1,3 @@ +<div class="trix-content"> + <%= yield -%> +</div> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000..6042f43 --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html> + <head> + <title><%= ENV.fetch('OPERUM_BASE_TITLE', 'Operum') %></title> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> + <%= javascript_importmap_tags %> + </head> + + <body> + <% if current_user && @searches %> + <header data-controller="header"> + <nav> + <a class="<%= 'current' if current_user.last_search_id.nil? %>" href="/"><%= I18n.t('searches.home') %></a> + <% Search.find_each do |s| %> + <a class="<%= 'current' if current_user.last_search_id == s.id %>" href="<%= search_path(s) %>"><%= s.name %></a> + <% end %> + <a id="toggle-hidden-global-menu" href="#" data-action="header#toggle"><i id="header-chevron" class="gg-chevron-down"></i></a> + </nav> + + <div id="hidden-nav" class="hidden"> + <div class="flex-wrap"> + <span><%= I18n.t('general.create').capitalize %>: </span> + <%= link_to I18n.t('searches.object'), new_search_path %> + <%= link_to I18n.t('things.object'), new_thing_path %> + </div> + + <div class="flex-wrap"> + <span><%= I18n.t('searches.title') %>: </span> + <% if @search&.id %> + <%= link_to I18n.t('general.edit'), edit_search_path(@search) %> + <%= link_to I18n.t('general.delete'), search_path(@search), data: { turbo_confirm: I18n.t('general.sure'), turbo_method: :delete } %> + <% end %> + + <%= link_to I18n.t('searches.export.action'), new_search_exports_path(current_user.last_search_id ? current_user.last_search_id : '0') %> + </div> + + <div class="flex-wrap"> + <span><%= I18n.t('general.list').capitalize %>: </span> + <%= link_to I18n.t('tags.title').downcase, tags_path %> + <%= link_to I18n.t('searches.shared.title').downcase, shared_searches_path %> + </div> + </div> + </header> + <% end %> + + <main> + <% if flash[:notice] %> + <div class="notice"> + <span><%= flash[:notice] %>.</span> + </div> + <% end %> + + <% if flash[:alert] %> + <div class="notice"> + <span><%= flash[:alert] %>.</span> + </div> + <% end %> + + <%= yield %> + </main> + + <footer> + <p> + <%= I18n.t('layout.created-by') %> <a href="http://jo.mssola.com/">Miquel Sabaté Solà</a> + <br> + <%= I18n.t('layout.this-page-license') %> <a href="/license">AGPLv3</a> (<a href="https://github.com/mssola/operum"><%= I18n.t('layout.source-code') %></a>) + <% if current_user %> + <br> + <%= link_to I18n.t('sessions.sign-out'), sessions_path, data: { turbo_method: :delete } %> + <% end %> + </p> + </footer> + </body> +</html> diff --git a/app/views/licenses/show.html.erb b/app/views/licenses/show.html.erb new file mode 100644 index 0000000..7687d54 --- /dev/null +++ b/app/views/licenses/show.html.erb @@ -0,0 +1,23 @@ +<h3><%= t('license.title') %> <a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPLv3</a></h3> + +<p><%= t('license.at') %> <a href="https://github.com/mssola/operum"><%= t('license.here') %></a>.</p> + +<blockquote> +<pre> +Copyright (C) 2023-Ω Miquel Sabaté Solà <mikisabate@gmail.com> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. +</pre> + +</blockquote> diff --git a/app/views/searches/_form.html.erb b/app/views/searches/_form.html.erb new file mode 100644 index 0000000..c940fe2 --- /dev/null +++ b/app/views/searches/_form.html.erb @@ -0,0 +1,29 @@ +<div data-controller="search"> + <%= form_with(model: search) do |form| %> + <%= render "layouts/errors", model: search %> + + <div id="search_form"> + <div id="search-form-name" class="hidden"> + <%= form.label :name %> + <%= form.text_field :name, required: true, autocomplete: 'off' %> + </div> + + <div> + <%= form.text_field :body, "data-action": "keydown.enter->search#load", "data-search-target": "body", placeholder: 'Search body' %> + <a id="save-search" href="#" data-action="search#save" class="hidden"><%= I18n.t('searches.save') %></a> + </div> + + <div id="search-form-shared" class="hidden"> + <%= form.check_box :shared %> + <%= form.label :shared, I18n.t('searches.public') %> + </div> + + <div id="search-form-submit" class="hidden"> + <%= form.submit %> + </div> + </div> + <% end %> + + <div id="results"> + </div> +</div> diff --git a/app/views/searches/_search.html.erb b/app/views/searches/_search.html.erb new file mode 100644 index 0000000..a717a22 --- /dev/null +++ b/app/views/searches/_search.html.erb @@ -0,0 +1,5 @@ +<div id="items"> + <% items.values.flatten.each do |item| %> + <%= render item %> + <% end %> +</div> diff --git a/app/views/searches/edit.html.erb b/app/views/searches/edit.html.erb new file mode 100644 index 0000000..2702224 --- /dev/null +++ b/app/views/searches/edit.html.erb @@ -0,0 +1 @@ +<%= render "form", search: @search %> diff --git a/app/views/searches/index.html.erb b/app/views/searches/index.html.erb new file mode 100644 index 0000000..b7d3854 --- /dev/null +++ b/app/views/searches/index.html.erb @@ -0,0 +1 @@ +<%= render "search", items: @search.results %> diff --git a/app/views/searches/new.html.erb b/app/views/searches/new.html.erb new file mode 100644 index 0000000..2702224 --- /dev/null +++ b/app/views/searches/new.html.erb @@ -0,0 +1 @@ +<%= render "form", search: @search %> diff --git a/app/views/searches/show.html.erb b/app/views/searches/show.html.erb new file mode 100644 index 0000000..b7d3854 --- /dev/null +++ b/app/views/searches/show.html.erb @@ -0,0 +1 @@ +<%= render "search", items: @search.results %> diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb new file mode 100644 index 0000000..c6d7f4f --- /dev/null +++ b/app/views/sessions/new.html.erb @@ -0,0 +1,21 @@ +<div class="center-contents"> + <div></div> + <div> + <h2><%= I18n.t('sessions.title') %></h2> + + <%= form_tag sessions_path do |form| %> + <div class='field'> + <%= label_tag :username, I18n.t('activerecord.attributes.user.username') %> + <%= text_field_tag :username, '', autofocus: true, class: 'width-100' %> + </div> + <div class='field'> + <%= label_tag :password, I18n.t('activerecord.attributes.user.password') %> + <%= password_field_tag :password, '', class: 'width-100' %> + </div> + <div class='actions'> + <%= submit_tag I18n.t('sessions.sign-in') %> + </div> + <% end %> + </div> + <div></div> +</div> diff --git a/app/views/shared_searches/index.html.erb b/app/views/shared_searches/index.html.erb new file mode 100644 index 0000000..9a145f6 --- /dev/null +++ b/app/views/shared_searches/index.html.erb @@ -0,0 +1,13 @@ +<h3><%= I18n.t('searches.shared.title') %></h3> + +<% if @searches.empty? %> + <div><span><%= I18n.t('searches.shared.none') %>.</span></div> +<% else %> + <div id="shared-searches-list"> + <% @searches.each do |s| %> + <div> + <%= link_to s.name, search_shared_path(s) %> + </div> + <% end %> + </div> +<% end %> diff --git a/app/views/shared_searches/show.html.erb b/app/views/shared_searches/show.html.erb new file mode 100644 index 0000000..1430529 --- /dev/null +++ b/app/views/shared_searches/show.html.erb @@ -0,0 +1,28 @@ +<table id="public-search-table"> + <% @search.results.values.flatten.each do |res| %> + <tr> + <td> + <details> + <% if res.is_a? Thing %> + <summary><%= res.title %></summary> + <div class="details-flex"> + <div><span><b>Authors</b>: <%= authors_or_editors(res) %></span></div> + <div><span><b>Publisher</b>: <%= string_maybe(res.publisher) %></span></div> + <div><span><b>Year</b>: <%= string_maybe(res.year) %></span></div> + <div><span><b>Kind</b>: <%= res.kind %></span></div> + <div><span><b>Note</b>: <%= string_maybe(res.note) %></span></div> + <% unless res.url.blank? %> + <div><span><b>URL</b>: <a href="<%= res.url %>" target="_blank"><%= res.url %></a></span></div> + <% end %> + </div> + <% else %> + <summary><b><%= I18n.t('comments.title') %></b> <%= I18n.t('general.in') %> «<i><%= res.thing.title %></i>»</summary> + <div class="details-flex"> + <%= res.content %> + </div> + <% end %> + </details> + </td> + </tr> + <% end %> +</table> diff --git a/app/views/tags/_form.html.erb b/app/views/tags/_form.html.erb new file mode 100644 index 0000000..75fc003 --- /dev/null +++ b/app/views/tags/_form.html.erb @@ -0,0 +1,12 @@ +<%= form_with(model: tag) do |form| %> + <%= render "layouts/errors", model: tag %> + + <div> + <%= form.label :name, style: "display: block" %> + <%= form.text_field :name, autofocus: true, autocomplete: 'off', class: 'width-100' %> + </div> + + <div> + <%= form.submit %> + </div> +<% end %> diff --git a/app/views/tags/_tag.html.erb b/app/views/tags/_tag.html.erb new file mode 100644 index 0000000..65c6d4e --- /dev/null +++ b/app/views/tags/_tag.html.erb @@ -0,0 +1,8 @@ +<div class="tag-container" id="<%= dom_id tag %>"> + <div class="name"> + <%= tag.name %> + </div> + <div class="action"> + <%= link_to I18n.t('general.delete'), tag_path(tag), data: { "turbo-method": :delete } %> + </div> +</div> diff --git a/app/views/tags/_taggable.html.erb b/app/views/tags/_taggable.html.erb new file mode 100644 index 0000000..84e236b --- /dev/null +++ b/app/views/tags/_taggable.html.erb @@ -0,0 +1,17 @@ +<% if Tag.any? %> + <div> + <h5><%= I18n.t('tags.title') %> — <%= link_to I18n.t('tags.new-action'), new_tag_path %></h5> + + <div class="flex-list"> + <% Tag.find_each do |tag| %> + <div class="flex-element"> + <label> + <%= form.check_box :tag_ids, { multiple: true, checked: tag_references&.include?(tag.id) }, tag.id, nil %> + <%= tag.name %> + </label> + </div> + <% end %> + </div> + </div> + <p></p> +<% end %> diff --git a/app/views/tags/index.html.erb b/app/views/tags/index.html.erb new file mode 100644 index 0000000..329e069 --- /dev/null +++ b/app/views/tags/index.html.erb @@ -0,0 +1,13 @@ +<div class="center-contents"> + <div></div> + <div id="tag-index"> + <h2><%= I18n.t('tags.title') %> <span>— <%= link_to I18n.t('tags.new-action'), new_tag_path %></span></h2> + + <div id="tags-list"> + <% @tags.each do |tag| %> + <%= render tag %> + <% end %> + </div> + </div> + <div></div> +</div> diff --git a/app/views/tags/new.html.erb b/app/views/tags/new.html.erb new file mode 100644 index 0000000..bd6c586 --- /dev/null +++ b/app/views/tags/new.html.erb @@ -0,0 +1,9 @@ +<div class="center-contents"> + <div></div> + <div id="tag-new"> + <h2><%= I18n.t('tags.new') %> <span>— <%= link_to I18n.t('general.back-to-list'), tags_path %></span></h2> + + <%= render "form", tag: @tag %> + </div> + <div></div> +</div> diff --git a/app/views/things/_form.html.erb b/app/views/things/_form.html.erb new file mode 100644 index 0000000..da90302 --- /dev/null +++ b/app/views/things/_form.html.erb @@ -0,0 +1,102 @@ +<%= form_with(model: thing) do |form| %> + <%= render "layouts/errors", model: thing %> + + <div id="thing_form"> + <div class="thing_large"> + <%= form.label :title %> + <%= form.text_field :title, autofocus: true, required: true %> + </div> + + <div class="thing_large"> + <%= form.label :authors %> + <%= form.text_field :authors, required: true %> + <%= form.check_box :editors %> + <%= form.label :editors %> + </div> + + <div class="thing_large"> + <%= form.label :note %> + <%= form.text_field :note %> + </div> + + <div> + <%= form.label :target %> + <%= form.text_field :target, required: true %> + </div> + + <div> + <%= form.label :publisher %> + <%= form.text_field :publisher %> + </div> + + <div> + <%= form.label :year %> + <%= form.number_field :year %> + </div> + + <div> + <%= form.label :address %> + <%= form.text_field :address %> + </div> + + <div> + <%= form.label :url %> + <%= form.text_field :url %> + </div> + + <div> + <%= form.label :access %> + <%= form.date_field :access %> + </div> + + <div> + <%= form.label :location %> + <%= form.text_field :location %> + </div> + + <div> + <%= form.label :insideof %> + <%= form.text_field :insideof %> + </div> + + <div> + <%= form.label :pages %> + <%= form.text_field :pages %> + </div> + + <div> + <%= form.label :rate %> + <%= form.number_field :rate, min: 0, max: 10, required: true %> + </div> + + <div> + <%= form.label :status %> + <%= form.select :status, options_for_select(Thing.statuses.map { |k, _| [I18n.t("things.status.#{k}"), k] }.sort, thing.status) %> + </div> + + <div> + <%= form.label :kind %> + <%= form.select :kind, options_for_select(Thing.kinds.map { |k, _| [I18n.t("things.kind.#{k}"), k] }.sort, thing.kind) %> + </div> + + <div> + <%= form.label :bought_at %> + <%= form.date_field :bought_at %> + </div> + + <div> + <%= form.label :where_is_it %> + <%= form.text_field :where_is_it %> + </div> + </div> + + <%= render "tags/taggable", tag_references: thing.tag_references.pluck(:tag_id), form: form %> + + <div> + <%= form.submit %> + </div> +<% end %> + +<% if thing.id %> + <%= button_to I18n.t('general.delete').capitalize, thing, id: 'thing-delete-button', form: { data: { turbo_confirm: I18n.t('general.sure') } }, method: :delete %> +<% end %> diff --git a/app/views/things/_thing.html.erb b/app/views/things/_thing.html.erb new file mode 100644 index 0000000..5a31ccc --- /dev/null +++ b/app/views/things/_thing.html.erb @@ -0,0 +1,7 @@ +<div id="<%= dom_id thing %>" class="thing_row"> + <div class="thing_head"> + <div class="dot dot_<%= thing.kind %>" title="<%= I18n.t("things.kind.#{thing.kind}") %>"></div> + </div> + <div class="thing_body"><%= link_to thing.title, edit_thing_path(thing) %></div> + <div class="thing_tail"><%= thing.rate %></div> +</div> diff --git a/app/views/things/edit.html.erb b/app/views/things/edit.html.erb new file mode 100644 index 0000000..f30ec5c --- /dev/null +++ b/app/views/things/edit.html.erb @@ -0,0 +1,3 @@ +<%= render "form", thing: @thing %> + +<%= render "comments/list", thing: @thing, from: 'things/edit' %> diff --git a/app/views/things/new.html.erb b/app/views/things/new.html.erb new file mode 100644 index 0000000..d28df14 --- /dev/null +++ b/app/views/things/new.html.erb @@ -0,0 +1 @@ +<%= render "form", thing: @thing %> diff --git a/app/views/things/show.html.erb b/app/views/things/show.html.erb new file mode 100644 index 0000000..c534e49 --- /dev/null +++ b/app/views/things/show.html.erb @@ -0,0 +1,7 @@ +<%= render "things/thing", thing: @thing %> + +<p> + <%= link_to I18n.t('things.create-another'), new_thing_path %> +</p> + +<%= render "comments/list", thing: @thing, from: 'things/show' %> |
