This commit is contained in:
21
app/views/books/_book.html.erb
Normal file
21
app/views/books/_book.html.erb
Normal file
@@ -0,0 +1,21 @@
|
||||
<% cache book do %>
|
||||
<figure class="library__book <%= "theme--#{book&.theme}" unless book.cover.attached? %>">
|
||||
<div class="flex flex-column gap-half">
|
||||
<div class="flex-inline position-relative center">
|
||||
<% if book.cover.attached? %>
|
||||
<%= image_tag book.cover, alt: "Book cover", class: "book__cover" %>
|
||||
<% else %>
|
||||
<span class="book__cover-wrapper">
|
||||
<%= image_tag "empty-cover.png", alt: "Book cover", class: "book__cover margin-block-none center" %>
|
||||
<span class="book__title overflow-line-clamp pad txt-align-start txt-tight-lines" style="--lines: 6" aria-hidden="true"><%= book.title %></span>
|
||||
</span>
|
||||
<% end %>
|
||||
<%= turbo_frame_tag dom_id(book, :bookmark), src: book_bookmark_path(book), target: "_top" %>
|
||||
</div>
|
||||
<h2 class="margin-none flex flex-column txt-normal txt-tight-lines txt-medium--responsive">
|
||||
<strong><%= book.title %></strong>
|
||||
<span class="overflow-line-clamp"><%= book.author %></span>
|
||||
</h2>
|
||||
</div>
|
||||
</figure>
|
||||
<% end %>
|
||||
31
app/views/books/_create_buttons.html.erb
Normal file
31
app/views/books/_create_buttons.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<%= book_part_create_button book, Page do %>
|
||||
<svg viewBox="0 0 20 24" xmlns="http://www.w3.org/2000/svg" fill="var(--color-ink)">
|
||||
<path d="m15.8 21.7c0 .3-.2.4-.4.4h-13.5-.2v-16.9c0-.3.2-.4.4-.4h6.3c0-.6.1-1.2.3-1.8h-6.9c-1 0-1.8.8-1.8 1.8v17.5c0 1 .8 1.8 1.8 1.8h14c.9 0 1.6-.6 1.8-1.4v-11.6c-.5.2-1.1.4-1.8.5v10.3z"/>
|
||||
<path fill="var(--color-positive)" d="m15 0c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm1.9 5.6h-1.2c-.1 0-.2 0-.2.2v1.2c0 .3-.3.6-.6.6s-.6-.3-.6-.6v-1.2c0-.1 0-.2-.2-.2h-1.2c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h1.2c.1 0 .2 0 .2-.2v-1.2c0-.3.3-.6.6-.6s.6.3.6.6v1.2c0 .1 0 .2.2.2h1.2c.3 0 .6.3.6.6s-.3.6-.6.6z"/>
|
||||
<path d="m4.4 16.3.4-.4c.3-.3.8-.3 1.1 0 1 .9 2.5.9 3.4 0 .3-.3.8-.3 1.1 0 1 1 2.5 1 3.4 0l.3-.3c.3-.3.3-.8 0-1.1s-.8-.3-1.1 0l-.3.3c-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0l-.4.4c-.3.3-.3.8 0 1.1s.8.3 1.1 0z"/>
|
||||
<path d="m4.5 20.1.5-.5c.4-.4.9-.4 1.3 0 1.1 1.1 2.8 1.1 3.9 0 .3-.4.3-.9 0-1.3-.4-.3-.9-.3-1.3 0s-.9.3-1.3 0c-1.1-1.1-2.8-1.1-3.9 0l-.5.5c-.3.4-.3.9 0 1.3.4.3.9.3 1.3 0z"/>
|
||||
<path d="m12.8 11.2c-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0s-.4.4-.4.4c-.3.3-.3.8 0 1.1s.8.3 1.1 0 .4-.4.4-.4c.3-.3.8-.3 1.1 0 1 .9 2.5.9 3.4 0 .3-.3.8-.3 1.1 0 1 1 2.5 1 3.4 0s.3-.3.3-.3c.2-.2.3-.4.2-.6-.6 0-1.1-.2-1.6-.3z"/>
|
||||
<path d="m8.3 7.6c-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0l-.4.4c-.3.3-.3.8 0 1.1s.8.3 1.1 0 .4-.4.4-.4c.3-.3.8-.3 1.1 0 1 .9 2.5.9 3.4 0 0 0 .1-.1.2-.1-.3-.4-.5-.9-.7-1.4-.2.1-.4.3-.6.4z"/>
|
||||
</svg>
|
||||
<span class="for-screen-reader">Add a new text page</span>
|
||||
<% end %>
|
||||
|
||||
<%= book_part_create_button book, Picture do %>
|
||||
<svg viewBox="0 0 20 24" xmlns="http://www.w3.org/2000/svg" fill="var(--color-ink)">
|
||||
<path d="m14.4 16.8s.2-.2.2-.3v-5.1c-2.8-.2-5.1-2.2-5.8-4.9h-4.2c-.8 0-1.4.6-1.4 1.4v11.1c0 .8.6 1.5 1.5 1.5h1.2s.2 0 .3-.2l4.4-6.8c.2-.3.3-.4.7-.4s.5.2.7.4l2.2 3.1c0 .2.3.2.4 0zm-7.3-1.9c-.9 0-1.7-.8-1.7-1.7s.8-1.7 1.7-1.7 1.7.8 1.7 1.7-.8 1.7-1.7 1.7z"/>
|
||||
<path d="m11.2 15.8c0-.2-.2-.2-.3 0s-2.6 4.1-2.6 4.1v.4h.2 4.3c.3 0 .7-.2.8-.3s.2-.2 0-.3l-2.4-3.8z"/>
|
||||
<path d="m15.8 21.7c0 .3-.2.4-.4.4h-13.5-.2v-16.9c0-.3.2-.4.4-.4h6.3c0-.6.1-1.2.3-1.8h-6.9c-1 0-1.8.8-1.8 1.8v17.5c0 1 .8 1.8 1.8 1.8h14c.9 0 1.6-.6 1.8-1.4v-11.6c-.5.2-1.1.4-1.8.5v10.3z"/>
|
||||
<path fill="var(--color-positive)" d="m15 0c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm1.9 5.6h-1.2c-.1 0-.2 0-.2.2v1.2c0 .3-.3.6-.6.6s-.6-.3-.6-.6v-1.2c0-.1 0-.2-.2-.2h-1.2c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h1.2c.1 0 .2 0 .2-.2v-1.2c0-.3.3-.6.6-.6s.6.3.6.6v1.2c0 .1 0 .2.2.2h1.2c.3 0 .6.3.6.6s-.3.6-.6.6z"/>
|
||||
</svg>
|
||||
<span class="for-screen-reader">Add a new picture page</span>
|
||||
<% end %>
|
||||
|
||||
<%= book_part_create_button book, Section do %>
|
||||
<svg viewBox="0 0 20 24" xmlns="http://www.w3.org/2000/svg" fill="var(--color-ink)">
|
||||
<path d="m15 11.5c-3.6 0-6.5-2.9-6.5-6.5s0-.2 0-.2h-6.3c-.3 0-.4.2-.4.4v16.9s0 .2.2 0h13.4c.3 0 .4-.2.4-.4v-10.3c-.2 0-.5 0-.8 0z" opacity="0"/>
|
||||
<path d="m15.8 21.7c0 .3-.2.4-.4.4h-13.5-.2v-16.9c0-.3.2-.4.4-.4h6.3c0-.6.1-1.2.3-1.8h-6.9c-1 0-1.8.8-1.8 1.8v17.5c0 1 .8 1.8 1.8 1.8h14c.9 0 1.6-.6 1.8-1.4v-11.6c-.5.2-1.1.4-1.8.5v10.3z"/>
|
||||
<path fill="var(--color-positive)" d="m15 0c-2.8 0-5 2.2-5 5s2.2 5 5 5 5-2.2 5-5-2.2-5-5-5zm1.9 5.6h-1.2c-.1 0-.2 0-.2.2v1.2c0 .3-.3.6-.6.6s-.6-.3-.6-.6v-1.2c0-.1 0-.2-.2-.2h-1.2c-.3 0-.6-.3-.6-.6s.3-.6.6-.6h1.2c.1 0 .2 0 .2-.2v-1.2c0-.3.3-.6.6-.6s.6.3.6.6v1.2c0 .1 0 .2.2.2h1.2c.3 0 .6.3.6.6s-.3.6-.6.6z"/>
|
||||
<path d="m4.4 14.5.4-.4c.3-.3.8-.3 1.1 0 1 .9 2.5.9 3.4 0 .3-.3.8-.3 1.1 0 1 1 2.5 1 3.4 0l.3-.3c.3-.3.3-.8 0-1.1s-.8-.3-1.1 0l-.3.3c-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0-.3.3-.8.3-1.1 0-1-1-2.5-1-3.4 0l-.4.4c-.3.3-.3.8 0 1.1s.8.3 1.1 0z"/>
|
||||
</svg>
|
||||
<span class="for-screen-reader">Add a new section page</span>
|
||||
<% end %>
|
||||
15
app/views/books/_edit_mode.html.erb
Normal file
15
app/views/books/_edit_mode.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
<%= tag.div class: "flex align-center gap flex-item-no-shrink",
|
||||
data: {
|
||||
controller: "edit-mode",
|
||||
edit_mode_target_url_value: target_url,
|
||||
edit_mode_editing_class: "edit-mode",
|
||||
edit_mode_autosave_outlet: "[data-controller='autosave']",
|
||||
} do %>
|
||||
<%= image_tag "eye.svg", aria: { hidden: true }, size: 28, class: "colorize--black" %>
|
||||
<label class="switch txt-medium">
|
||||
<%= check_box_tag :edit_mode_enabled, checked: checked, class: "switch__input", data: { action: "edit-mode#change" } %>
|
||||
<span class="switch__btn round"></span>
|
||||
<span class="for-screen-reader">Editing mode</span>
|
||||
</label>
|
||||
<%= image_tag "write.svg", aria: { hidden: true }, size: 24, class: "colorize--black" %>
|
||||
<% end %>
|
||||
85
app/views/books/_form.html.erb
Normal file
85
app/views/books/_form.html.erb
Normal file
@@ -0,0 +1,85 @@
|
||||
<%= form_with model: book, id: "book-editor" do |form| %>
|
||||
<%= tag.div class:"book__form flex align-center gap full-width #{"theme--#{book&.theme}" unless book.cover.attached? }", style:"--input-padding: 0.5rem 1rem; --input-border-radius: 0.5rem" do %>
|
||||
<div class="flex gap-half">
|
||||
<fieldset class="flex flex-column unpad margin-block-end borderless justify-space-between">
|
||||
<legend class="for-screen-reader">Cover color</legend>
|
||||
|
||||
<% Book.themes.keys.each do | theme | %>
|
||||
<label class="btn btn--circle txt-small" style="--btn-background: var(--theme-color--<%= theme -%>)" >
|
||||
<%= form.radio_button :theme, theme %>
|
||||
<%= image_tag "check.svg", aria: { hidden: "true" }, size: 24, class: "checked" %>
|
||||
<span class="for-screen-reader"><%= theme %></span>
|
||||
</label>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<%= tag.div class: "flex flex-column", data: { controller: "upload-preview", upload_preview_default_image_value: asset_url("empty-cover.png") } do %>
|
||||
<label class="align-center center gap position-relative margin-block-end">
|
||||
<% unless book.cover.attached? %>
|
||||
<span class="btn btn--reversed txt-medium book__cover--add">
|
||||
<%= image_tag "camera.svg", aria: { hidden: "true" }, size: 24 %>
|
||||
<span class="for-screen-reader">Upload a cover</span>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<div class="input--file">
|
||||
<%= image_tag book.cover.attached? ? book.cover : "empty-cover.png", alt: "Book cover",
|
||||
class: "book__cover margin-none", style: "--cover-height: 60vh",
|
||||
data: { upload_preview_target: "image" } %>
|
||||
<%= form.file_field :cover, class: "input", accept: "image/png, image/jpeg, image/jpg, image/webp",
|
||||
data: { upload_preview_target: "input", action: "upload-preview#previewImage" },
|
||||
title: book.cover.attached? ? "Replace book cover" : "Upload book cover" %>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<% if book.cover.attached? %>
|
||||
<%= tag.label class:"btn btn--negative txt-small center book__cover--remove", data: { action: "click->upload-preview#clear", upload_preview_target: "button" } do %>
|
||||
<%= image_tag "minus.svg", aria: { hidden: "true" }, size: 24 %>
|
||||
<%= check_box_tag "remove_cover", "true" %>
|
||||
<span class="for-screen-reader">Remove cover image</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<div class="flex flex-column gap full-width">
|
||||
<div class="flex align-center gap txt-medium">
|
||||
<%= translation_button(:book_title) %>
|
||||
<h1 class="txt-xx-large margin-none full-width">
|
||||
<%= form.text_field :title, required: true, autofocus: true, class: "input", placeholder: "Book title", autocomplete: "off" %>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="flex align-center gap txt-medium">
|
||||
<%= translation_button(:book_subtitle) %>
|
||||
<small class="txt-normal txt-large txt-tight-lines full-width"><%= form.text_area :subtitle, class: "input", placeholder: "Subtitle", autocomplete: "off" %></small>
|
||||
</div>
|
||||
<div class="flex align-center gap txt-medium">
|
||||
<%= translation_button(:book_author) %>
|
||||
<small class="txt-normal txt-large txt-tight-lines full-width"><%= form.text_field :author, class: "input", placeholder: "Author", autocomplete: "off" %></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="book-access border-radius center pad-double fill-shade flex flex-column gap margin-block-double">
|
||||
<div class="flex align-center gap txt-medium--responsive">
|
||||
<%= image_tag "eye.svg", aria: { hidden: true }, size: 36, class: "colorize--black" %>
|
||||
|
||||
<div class="min-width">
|
||||
<div class="overflow-ellipsis fill-shade"><strong>Everyone</strong></div>
|
||||
</div>
|
||||
|
||||
<hr class="flex-item-grow margin-none" aria-hidden="true" style="--border-style: dashed">
|
||||
|
||||
<label for="book_everyone_access" class="switch">
|
||||
<%= form.check_box :everyone_access, class: "switch__input book-access__switch" %>
|
||||
<span class="switch__btn"></span>
|
||||
<span class="for-screen-reader">Only allow some people to read this book</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<hr class="full-width margin-block-start margin-block-end-half">
|
||||
|
||||
<%= render partial: "books/accesses/access", collection: users, as: :user, locals: { book: book, creating_user: creating_user } %>
|
||||
</div>
|
||||
|
||||
<%= form.submit "Save", hidden: true %>
|
||||
<% end %>
|
||||
4
app/views/books/_index_link.html.erb
Normal file
4
app/views/books/_index_link.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<%= link_to root_path, class: "btn borderless txt-small flex-item-no-shrink" do %>
|
||||
<%= image_tag "books.svg", aria: { label: "Books" }, size: 19, class: "colorize--black", alt: "Books" %>
|
||||
<span class="for-screen-reader">All books</span>
|
||||
<% end %>
|
||||
11
app/views/books/_mode_buttons.html.erb
Normal file
11
app/views/books/_mode_buttons.html.erb
Normal file
@@ -0,0 +1,11 @@
|
||||
<label class="btn arrange-mode__button txt-medium flex-item-justify-end disable-when-deleting disable-when-empty">
|
||||
<input type="checkbox" name="arrange-mode" id="arrange-mode" data-action="arrangement#setArrangeMode">
|
||||
<%= image_tag "rearrange.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Rearrange</span>
|
||||
</label>
|
||||
|
||||
<label class="btn delete-mode__button txt-medium disable-when-arranging disable-when-empty">
|
||||
<input type="checkbox" id="delete-mode">
|
||||
<%= image_tag "minus.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Delete pages</span>
|
||||
</label>
|
||||
12
app/views/books/_new.html.erb
Normal file
12
app/views/books/_new.html.erb
Normal file
@@ -0,0 +1,12 @@
|
||||
<figure class="library__book position-relative">
|
||||
<div class="library__book--empty center">
|
||||
<%= image_tag "empty-cover.png", alt: "Book cover", class: "book__cover" %>
|
||||
<span class="btn btn--positive center">
|
||||
<%= image_tag "add.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader"></span>
|
||||
</span>
|
||||
</div>
|
||||
<%= link_to new_book_path, class: "bookmark__link" do %>
|
||||
<span class="for-screen-reader">Create a new book</span>
|
||||
<% end %>
|
||||
</figure>
|
||||
24
app/views/books/accesses/_access.html.erb
Normal file
24
app/views/books/accesses/_access.html.erb
Normal file
@@ -0,0 +1,24 @@
|
||||
<div class="flex align-center gap txt-medium--responsive" data-controller="dependent-checkbox">
|
||||
<span class="flex align-center gap-half">
|
||||
<% if user.can_administer? %>
|
||||
<%= image_tag "crown.svg", size: 18, aria: { hidden: "true" }, class: "colorize--black" %>
|
||||
<% end %>
|
||||
<span class="overflow-ellipsis txt-medium--responsive"><%= user.name %></span>
|
||||
</span>
|
||||
<hr class="flex-item-grow margin-none" aria-hidden="true" style="--border-style: dashed">
|
||||
|
||||
<fieldset class="flex align-center gap borderless unpad margin-none">
|
||||
<legend class="for-screen-reader"><%= user.name %></legend>
|
||||
<label class="btn btn--small flex-item-no-shrink">
|
||||
<%= check_box_tag "editor_ids[]", user.id, book.editable?(user: user) || user == creating_user || user.can_administer?, id: nil, disabled: user.current? || user.can_administer?, data: { action: "dependent-checkbox#input", dependent_checkbox_target: "dependant" }, aria: { label: "Role: Writer" } %>
|
||||
<%= image_tag "write.svg", size: 24, aria: { hidden: "true" } %>
|
||||
<span class="for-screen-reader"></span>
|
||||
</label>
|
||||
|
||||
<label class="btn btn--small flex-item-no-shrink book-access__reader">
|
||||
<%= check_box_tag "reader_ids[]", user.id, book.accessable?(user: user) || user == creating_user || user.can_administer?, id: nil, disabled: user.current? || user.can_administer?, data: { action: "dependent-checkbox#input", dependent_checkbox_target: "dependee" }, aria: { label: "Role: Reader" } %>
|
||||
<%= image_tag "eye.svg", size: 24, aria: { hidden: "true" } %>
|
||||
<span class="for-screen-reader"></span>
|
||||
</label>
|
||||
</fieldset>
|
||||
</div>
|
||||
4
app/views/books/accesses/_editor.html.erb
Normal file
4
app/views/books/accesses/_editor.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<%= button_to book_user_access_path(book, user), method: :delete, class: "btn txt-small flex-item-no-shrink" do %>
|
||||
<%= image_tag "write.svg", size: 24, aria: { hidden: "true" } %>
|
||||
<span class="for-screen-reader">Role: Writer</span>
|
||||
<% end %>
|
||||
4
app/views/books/accesses/_none.html.erb
Normal file
4
app/views/books/accesses/_none.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<%= button_to book_user_access_path(book, user), params: { level: :reader }, class: "btn txt-small flex-item-no-shrink" do %>
|
||||
<%= image_tag "remove.svg", size: 24, aria: { hidden: "true" } %>
|
||||
<span class="for-screen-reader">Role: None</span>
|
||||
<% end %>
|
||||
4
app/views/books/accesses/_reader.html.erb
Normal file
4
app/views/books/accesses/_reader.html.erb
Normal file
@@ -0,0 +1,4 @@
|
||||
<%= button_to book_user_access_path(book, user), params: { level: :editor }, class: "btn txt-small flex-item-no-shrink" do %>
|
||||
<%= image_tag "eye.svg", size: 24, aria: { hidden: "true" } %>
|
||||
<span class="for-screen-reader">Role: Reader</span>
|
||||
<% end %>
|
||||
21
app/views/books/bookmarks/show.html.erb
Normal file
21
app/views/books/bookmarks/show.html.erb
Normal file
@@ -0,0 +1,21 @@
|
||||
<%= turbo_frame_tag dom_id(@book, :bookmark) do %>
|
||||
<% if @leaf %>
|
||||
<%= link_to book_slug_path(@book, anchor: dom_id(@leaf)), class: "bookmark__link" do %>
|
||||
<span class="for-screen-reader">Bookmark: Resume reading <%= @book.title %></span>
|
||||
<% end %>
|
||||
|
||||
<%= tag.span class: "bookmark", style: "--progress: #{ @leaf.position_as_percentage }%" do %>
|
||||
<div class="flex align-center">
|
||||
<span class="bookmark__icon">
|
||||
<svg viewBox="0 0 64 64" width="64px" height="64px" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m17.01 54.01v-42.98.00000045c-.00000025-1.65685 1.34315-3 3-3h24-.00000013c1.65685-.00000007 3 1.34315 3 3v42.98.0001206c0 1.10457-.895431 2-2 2-.34994 0-.693756-.0918173-.997105-.266281l-11.5039-6.61564c-.308638-.17748-.688362-.17748-.997 0l-11.5046 6.6153.00000011-.00000006c-.957413.550849-2.1801.221264-2.73095-.736149-.174564-.303405-.266442-.647312-.266451-.997351z" fill-rule="evenodd" fill="var(--color-marker)" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= link_to book_slug_path(@book), class: "bookmark__link" do %>
|
||||
<span class="for-screen-reader">Start reading <%= @book.title %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
25
app/views/books/edit.html.erb
Normal file
25
app/views/books/edit.html.erb
Normal file
@@ -0,0 +1,25 @@
|
||||
<% content_for(:title) { "Edit #{@book.title}" } %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<%= link_to book_slug_path(@book), class: "btn flex-item-justify-start" do %>
|
||||
<%= image_tag "arrow-left.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Cancel and go back</span>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<%= render "books/form", book: @book, users: @users, creating_user: nil %>
|
||||
|
||||
<% content_for :footer do %>
|
||||
<nav class="flex align-end justify-center pad">
|
||||
<%= button_to book_path(@book), method: :delete, class: "btn btn--negative",
|
||||
data: { turbo_confirm: "Are you sure you want to delete this book? It cannot be undone." } do %>
|
||||
<%= image_tag "trash.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Delete <%= @book.title %></span>
|
||||
<% end %>
|
||||
<button type="submit" form="book-editor", class="new-book-btn btn btn--reversed center txt-medium--responsive" aria-label="Save changes" title="Save changes">
|
||||
<%= image_tag "check.svg", aria: { hidden: true }, size: 24 %>
|
||||
</button>
|
||||
</nav>
|
||||
<% end %>
|
||||
32
app/views/books/index.html.erb
Normal file
32
app/views/books/index.html.erb
Normal file
@@ -0,0 +1,32 @@
|
||||
<% content_for(:title) { "Library | Writebook" } %>
|
||||
<% @layout_class = "books" %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<span class="btn btn--placeholder" aria-hidden="true"></span>
|
||||
|
||||
<a href="https://once.com/writebook" class="product__wordmark btn btn--plain txt-large center" target="_blank">
|
||||
<%= image_tag "writebook-icon.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span>Writebook</span>
|
||||
</a>
|
||||
|
||||
<% if Current.user %>
|
||||
<%= link_to users_path, class: "btn" do %>
|
||||
<%= image_tag "settings.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Manage people and settings</span>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= link_to new_session_path, class: "btn" do %>
|
||||
<%= image_tag "login-keys.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Sign in</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<% cache [ @books, signed_in? ] do %>
|
||||
<div class="library">
|
||||
<%= render @books %>
|
||||
<%= render "books/new" if signed_in? %>
|
||||
</div>
|
||||
<% end %>
|
||||
20
app/views/books/new.html.erb
Normal file
20
app/views/books/new.html.erb
Normal file
@@ -0,0 +1,20 @@
|
||||
<% content_for(:title) { "Create a new book" } %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav>
|
||||
<%= link_to root_path, class: "btn flex-item-justify-start" do %>
|
||||
<%= image_tag "arrow-left.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Cancel and go back</span>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<%= render "books/form", book: @book, users: @users, creating_user: Current.user %>
|
||||
|
||||
<% content_for :footer do %>
|
||||
<nav class="new-book-btn flex justify-center pad">
|
||||
<button type="submit" form="book-editor", class="btn btn--reversed txt-medium--responsive" aria-label="Create book" title="Create book">
|
||||
<%= image_tag "arrow-right.svg", aria: { hidden: true }, size: 24 %>
|
||||
</button>
|
||||
</nav>
|
||||
<% end %>
|
||||
63
app/views/books/publications/_publication.html.erb
Normal file
63
app/views/books/publications/_publication.html.erb
Normal file
@@ -0,0 +1,63 @@
|
||||
<div class="flex flex-column gap margin-block-start pad <%= book.published? ? "fill-selected" : "fill-shade" %> border-radius">
|
||||
<% if book.editable? %>
|
||||
<div class="flex align-center justify-center gap-half center">
|
||||
<%= image_tag "lock.svg", aria: { hidden: true }, size: 36, class: "colorize--black" %>
|
||||
<%= form_with model: book, url: book_publication_path(book), data: { controller: "form", action: "change->form#submit" }, html: { contents: true } do |form| %>
|
||||
<label class="switch txt-medium">
|
||||
<%= form.check_box :published, checked: book.published?, class: "switch__input" %>
|
||||
<span class="switch__btn round"></span>
|
||||
<span class="for-screen-reader">Publish this book</span>
|
||||
</label>
|
||||
<% end %>
|
||||
<%= image_tag "world.svg", aria: { hidden: true }, size: 36, class: "colorize--black" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if book.published? %>
|
||||
<div class="flex flex-column align-center gap txt-medium">
|
||||
<% public_url = book_slug_url(book) %>
|
||||
|
||||
<label class="flex flex-column gap full-width txt-align-center">
|
||||
<strong id="invite_label" class="invite-label for-screen-reader">Public link to this book</strong>
|
||||
<input type="text" class="input fill-white" id="invite_url" value="<%= public_url %>" aria-labelledby="invite_label" readonly>
|
||||
</label>
|
||||
|
||||
<div class="flex align-center gap">
|
||||
<div data-controller="dialog" class="flex-inline">
|
||||
<%= tag.button class: "btn", data: { action: "dialog#open" } do %>
|
||||
<%= image_tag "qr-code.svg", aria: { hidden: "true" }, size: 24, class: "colorize--black" %>
|
||||
<span class="for-screen-reader">Show public link QR code</span>
|
||||
<% end %>
|
||||
|
||||
<dialog class="dialog panel shadow" data-dialog-target="menu">
|
||||
<%= qr_code_image(public_url) %>
|
||||
|
||||
<form method="dialog" class="margin-block-start flex justify-center">
|
||||
<button class="btn">
|
||||
<%= image_tag "remove.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Close</span>
|
||||
</button>
|
||||
</form>
|
||||
</dialog>
|
||||
</div>
|
||||
|
||||
<%= button_to_copy_to_clipboard(public_url) do %>
|
||||
<%= image_tag "copy-paste.svg", aria: { hidden: "true" }, size: 24, class: "colorize--black" %>
|
||||
<span class="for-screen-reader">Copy public link</span>
|
||||
<% end %>
|
||||
|
||||
<%= web_share_button(public_url, "Link to join Writebook", "Hit this link to join me in Writebook and start writing.") do %>
|
||||
<%= image_tag "share.svg", aria: { hidden: "true" }, size: 24, class: "colorize--black" %>
|
||||
<span class="for-screen-reader">Share public link</span>
|
||||
<% end %>
|
||||
|
||||
<% if book.editable? %>
|
||||
<%= link_to edit_book_publication_path(book), class: "btn" do %>
|
||||
<%= image_tag "pencil.svg", aria: { hidden: "true" }, size: 24, class: "colorize--black" %>
|
||||
<span class="for-screen-reader">Edit link URL</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
38
app/views/books/publications/edit.html.erb
Normal file
38
app/views/books/publications/edit.html.erb
Normal file
@@ -0,0 +1,38 @@
|
||||
<%= turbo_frame_tag @book, :publication do %>
|
||||
<div class="flex flex-column gap margin-block-start pad fill-shade border-radius <%= "shake" if @book.errors[:slug].any? %>">
|
||||
<div class="flex flex-column align-center gap txt-medium">
|
||||
<% public_url = book_url(@book) %>
|
||||
|
||||
<%= form_with model: @book, url: book_publication_path(@book), class: "max-width", data: { turbo_frame: "_top" } do |form| %>
|
||||
<%= form.hidden_field :publication, value: true %>
|
||||
|
||||
<label class="flex flex-column gap full-width txt-align-center">
|
||||
<div id="public_link_label" class="flex align-center gap justify-center">
|
||||
<strong>Edit publication link</strong>
|
||||
</div>
|
||||
<span class="input input--actor flex align-center fill-white">
|
||||
<%= "#{request.host}/#{@book.id}/" %>
|
||||
<%= form.text_field :slug,
|
||||
autofocus: true,
|
||||
class: class_names("input"),
|
||||
required: true,
|
||||
pattern: "^[\\-A-Za-z0-9]+$",
|
||||
title: "Enter letters, numbers, or hyphens only" %>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="flex align-center gap margin-inline margin-block-start">
|
||||
<button type="submit" class="btn btn--positive flex-item-justify-end">
|
||||
<%= image_tag "check.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Save</span>
|
||||
</button>
|
||||
|
||||
<%= link_to book_slug_path(@book), class: "btn flex-item-justify-start" do %>
|
||||
<%= image_tag "remove.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Cancel</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
3
app/views/books/publications/show.html.erb
Normal file
3
app/views/books/publications/show.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<%= turbo_frame_tag @book, :publication do %>
|
||||
<%= render "publication", book: @book %>
|
||||
<% end %>
|
||||
131
app/views/books/show.html.erb
Normal file
131
app/views/books/show.html.erb
Normal file
@@ -0,0 +1,131 @@
|
||||
<% content_for(:title) { @book.title } %>
|
||||
<% @layout_class = "book" %>
|
||||
|
||||
<% content_for :head do %>
|
||||
<%= tag.meta property: "og:title", content: @book.title %>
|
||||
<%= tag.meta property: "og:description", content: @book.subtitle %>
|
||||
<%= tag.meta property: "og:image", content: @book.cover.blank? ? asset_url("covers/cover-#{@book.theme}-og.png") : "#{root_url}#{url_for(@book.cover)}" %>
|
||||
<%= tag.meta property: "og:url", content: book_slug_url(@book) %>
|
||||
|
||||
<%= tag.meta property: "twitter:title", content: @book.title %>
|
||||
<%= tag.meta property: "twitter:description", content: @book.subtitle %>
|
||||
<%= tag.meta property: "twitter:image", content: @book.cover.blank? ? asset_url("covers/cover-#{@book.theme}-og.png") : "#{root_url}#{url_for(@book.cover)}" %>
|
||||
<%= tag.meta property: "twitter:card", content: "summary_large_image" %>
|
||||
<% end %>
|
||||
|
||||
<% content_for :header do %>
|
||||
<nav class="book__navbar">
|
||||
<%= link_to root_path, class: "btn" do %>
|
||||
<%= image_tag "arrow-left.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Go back</span>
|
||||
<% end %>
|
||||
|
||||
<span class="btn btn--placeholder placeholder-start" aria-hidden="true"></span>
|
||||
|
||||
<div class="breadcrumbs">
|
||||
<%= render "books/index_link" %>
|
||||
<span class="flex-item-no-shrink">▸</span>
|
||||
<strong><%= @book.title %></strong>
|
||||
</div>
|
||||
|
||||
<%= link_to_first_leafable(@leaves) %>
|
||||
|
||||
<span class="btn btn--placeholder placeholder-end" aria-hidden="true"></span>
|
||||
|
||||
<button class="btn fullscreen" data-action="fullscreen#toggle" data-fullscreen-target="button">
|
||||
<%= image_tag "expand.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Enter fullscreen</span>
|
||||
</button>
|
||||
|
||||
<% if @book.editable? %>
|
||||
<%= link_to edit_book_path(@book), class: "btn settings" do %>
|
||||
<%= image_tag "settings.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Edit book settings</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<% cache [ @book, @book.editable? ] do %>
|
||||
<aside class="txt-align-center margin-block">
|
||||
<div class="book__sidebar <%= "theme--#{@book&.theme}" unless @book.cover.attached? %>">
|
||||
<% if @book.cover.attached? %>
|
||||
<%= link_to rails_blob_path(@book.cover, disposition: "attachment", only_path: true), data: { action: "lightbox#open:prevent", lightbox_target: "image", lightbox_url_value: rails_blob_path(@book.cover, disposition: "attachment", only_path: true) } do %>
|
||||
<%= image_tag @book.cover, alt: "Cover for #{ @book.title }", class: "book__cover margin-block-none center" %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<span class="book__cover-wrapper">
|
||||
<%= image_tag "empty-cover.png", alt: "Book cover", class: "book__cover margin-block-none center" %>
|
||||
<span class="book__title overflow-line-clamp pad txt-align-start txt-tight-lines"" style="--lines: 6" aria-hidden="true"><%= @book.title %></span>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if @book.editable? %>
|
||||
<%= turbo_frame_tag @book, :publication do %>
|
||||
<%= render "books/publications/publication", book: @book %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<span data-controller="edit-mode" data-edit-mode-editing-class="edit-mode" />
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<%= arrangement_tag @book, class: "arrangement__container toc__container full-width txt-align-center" do %>
|
||||
<h1 class="flex flex-column txt-tight-lines txt-align-start margin-block-end">
|
||||
<strong class="book__title txt-x-large--responsive"><%= @book.title %></strong>
|
||||
<span class="txt-large--responsive txt-normal"><%= @book.subtitle %></span>
|
||||
<span class="txt-large--responsive txt-normal"><%= @book.author %></span>
|
||||
</h1>
|
||||
|
||||
<div class="book__toolbar fill-white flex gap-half pad-block margin-block-end-half justify-center <%= "position-sticky" if @book.editable? %>" data-controller="toc-view" data-toc-view-id-value="<%= dom_id(@book) %>">
|
||||
<label class="btn txt-medium disable-when-empty">
|
||||
<input type="radio" name="view" id="toc-list" value="list" data-toc-view-target="switch" data-toc-view-type-value="list" data-action="toc-view#saveViewPref">
|
||||
<%= image_tag "view-list.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">List view</span>
|
||||
</label>
|
||||
|
||||
<label class="btn txt-medium flex-item-justify-start disable-when-empty">
|
||||
<input type="radio" name="view" id="toc-grid" value="grid" checked="checked" data-toc-view-target="switch" data-toc-view-type-value="grid" data-action="toc-view#saveViewPref">
|
||||
<%= image_tag "view-grid.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span class="for-screen-reader">Page view</span>
|
||||
</label>
|
||||
|
||||
<% if @book.editable? %>
|
||||
<%= render "books/create_buttons", book: @book %>
|
||||
<%= render "books/mode_buttons", book: @book %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="position-relative">
|
||||
<% if @book.editable? %>
|
||||
<div class="toc__blank-slate align-center justify-start">
|
||||
<%= image_tag "blank-slate-arrows.svg", aria: { hidden: true }, size: 60, class: "colorize--black" %>
|
||||
<span class="flex align-center gap-half"><span>🇺🇸</span> <span>Pick a page type to get started</span></span>
|
||||
<span class="flex align-center gap-half"><span>🇪🇸</span> <span>Elige un tipo de página para comenzar</span></span>
|
||||
<span class="flex align-center gap-half"><span>🇫🇷</span> <span>Choisissez un type de page pour commencer</span></span>
|
||||
<span class="flex align-center gap-half"><span>🇮🇳</span> <span>शुरू करने के लिए एक पृष्ठ प्रकार चुनें</span></span>
|
||||
<span class="flex align-center gap-half"><span>🇩🇪</span> <span>Wählen Sie einen Seitentyp, um zu beginnen</span></span>
|
||||
<span class="flex align-center gap-half"><span>🇧🇷</span> <span>Escolha um tipo de página para começar</span></span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<menu class="toc margin-none" tabindex="0" data-arrangement-target="container" data-action="<%= arrangement_actions %>">
|
||||
<%= turbo_frame_tag :leaves, data: { arrangement_target: "list" } do -%>
|
||||
<%= render partial: "leaves/leaf", collection: @leaves, as: :leaf -%>
|
||||
<% end -%>
|
||||
</menu>
|
||||
|
||||
<div data-arrangement-target="layer" class="toc"></div>
|
||||
<div data-arrangement-target="dragImage" class="arrangement-drag-image"></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% content_for :footer do %>
|
||||
<nav class="book__nav flex align-center justify-center">
|
||||
<a href="https://once.com/writebook" class="product__wordmark btn btn--plain txt-medium" target="_blank">
|
||||
<%= image_tag "writebook-icon.svg", aria: { hidden: true }, size: 24 %>
|
||||
<span>Made with Writebook</span>
|
||||
</a>
|
||||
</nav>
|
||||
<% end %>
|
||||
1
app/views/books/users/accesses/create.html.erb
Normal file
1
app/views/books/users/accesses/create.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= render "books/accesses/access", user: @user, book: @book %>
|
||||
1
app/views/books/users/accesses/destroy.html.erb
Normal file
1
app/views/books/users/accesses/destroy.html.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= render "books/accesses/access", user: @user, book: @book %>
|
||||
Reference in New Issue
Block a user