Redesign layout and navigation #64
2
Gemfile
@ -5,6 +5,8 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
|||||||
gem 'rails', '~> 7.0.2'
|
gem 'rails', '~> 7.0.2'
|
||||||
# Use Puma as the app server
|
# Use Puma as the app server
|
||||||
gem 'puma', '~> 4.1'
|
gem 'puma', '~> 4.1'
|
||||||
|
# View components
|
||||||
|
gem "view_component"
|
||||||
# Separate dependency since Rails 7.0
|
# Separate dependency since Rails 7.0
|
||||||
gem 'sprockets-rails'
|
gem 'sprockets-rails'
|
||||||
# Allows custom JS build tasks to integrate with the asset pipeline
|
# Allows custom JS build tasks to integrate with the asset pipeline
|
||||||
|
@ -282,6 +282,9 @@ GEM
|
|||||||
railties (>= 6.0.0)
|
railties (>= 6.0.0)
|
||||||
tzinfo (2.0.4)
|
tzinfo (2.0.4)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
|
view_component (2.49.0)
|
||||||
|
activesupport (>= 5.0.0, < 8.0)
|
||||||
|
method_source (~> 1.0)
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
web-console (4.2.0)
|
web-console (4.2.0)
|
||||||
@ -331,6 +334,10 @@ DEPENDENCIES
|
|||||||
stimulus-rails
|
stimulus-rails
|
||||||
turbo-rails
|
turbo-rails
|
||||||
tzinfo-data
|
tzinfo-data
|
||||||
|
view_component
|
||||||
warden
|
warden
|
||||||
web-console (>= 3.3.0)
|
web-console (>= 3.3.0)
|
||||||
webmock
|
webmock
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
2.3.7
|
||||||
|
@ -45,11 +45,6 @@ manual LDIF imports etc. (or provide a staging instance)
|
|||||||
|
|
||||||
* [Tailwind CSS](https://tailwindcss.com/)
|
* [Tailwind CSS](https://tailwindcss.com/)
|
||||||
|
|
||||||
**Caveat:** if you only add Tailwind classes/directives to templates or
|
|
||||||
helpers, but there's no change in the stylesheet files, then the new directives
|
|
||||||
won't be compiled in production. In this case, count up the version comment at
|
|
||||||
the top of `app/javascript/stylesheets/application.scss` to trigger compilation.
|
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
* [RSpec](https://rspec.info/documentation/)
|
* [RSpec](https://rspec.info/documentation/)
|
||||||
|
@ -6,3 +6,4 @@
|
|||||||
@import "components/buttons";
|
@import "components/buttons";
|
||||||
@import "components/forms";
|
@import "components/forms";
|
||||||
@import "components/links";
|
@import "components/links";
|
||||||
|
@import "components/notifications";
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
@apply leading-none
|
@apply leading-none
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3 {
|
/* h1, h2, h3 { */
|
||||||
@apply font-light;
|
/* @apply font-light; */
|
||||||
}
|
/* } */
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@apply text-3xl uppercase;
|
@apply text-3xl uppercase;
|
||||||
@ -18,4 +18,12 @@
|
|||||||
h3 {
|
h3 {
|
||||||
@apply text-xl mb-6;
|
@apply text-xl mb-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main section {
|
||||||
|
@apply pt-8 sm:pt-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
main section:first-of-type {
|
||||||
|
@apply pt-0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@layer components {
|
@layer components {
|
||||||
.btn {
|
.btn {
|
||||||
@apply font-semibold rounded-md leading-none cursor-pointer
|
@apply font-semibold rounded-md leading-none cursor-pointer text-center
|
||||||
transition-colors duration-75 focus:outline-none focus:ring-4;
|
transition-colors duration-75 focus:outline-none focus:ring-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
input[type=text], input[type=email], input[type=password],
|
input[type=text], input[type=email], input[type=password],
|
||||||
input[type=number], select {
|
input[type=number], select {
|
||||||
@apply mt-1 rounded-md bg-gray-100 focus:bg-white
|
@apply mt-1 rounded-md bg-gray-100 focus:bg-white
|
||||||
border-transparent focus:border-gray-500 focus:ring-0;
|
border-transparent focus:border-transparent focus:ring-2
|
||||||
|
focus:ring-blue-600 focus:ring-opacity-75;
|
||||||
}
|
}
|
||||||
|
|
||||||
.field_with_errors {
|
.field_with_errors {
|
||||||
|
39
app/assets/stylesheets/components/notifications.css
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
@layer components {
|
||||||
|
@keyframes notification-countdown {
|
||||||
|
from { width: 100%; }
|
||||||
|
to { width: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-enter {
|
||||||
|
@apply transform ease-out duration-300 transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-enter-from {
|
||||||
|
@apply translate-y-2 opacity-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-enter-to {
|
||||||
|
@apply translate-y-0 opacity-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen sm {
|
||||||
|
.notification-enter-from {
|
||||||
|
@apply translate-y-0 translate-x-2;
|
||||||
|
}
|
||||||
|
.notification-enter-to {
|
||||||
|
@apply translate-x-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-leave {
|
||||||
|
@apply transition ease-in duration-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-leave-from {
|
||||||
|
@apply opacity-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-leave-to {
|
||||||
|
@apply opacity-0;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,29 @@
|
|||||||
@import "variables";
|
@import "variables";
|
||||||
@import "mediaqueries";
|
@import "mediaqueries";
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(13,79,153,0.8) 100%),
|
||||||
|
url('/img/bg-1.jpg');
|
||||||
|
background-size: cover;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
body#admin {
|
||||||
|
background: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(153,12,14,0.9) 100%),
|
||||||
|
url('/img/bg-1.jpg');
|
||||||
|
background-size: cover;
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-site-icon {
|
||||||
|
svg {
|
||||||
|
display: inline-block;
|
||||||
|
height: 1.875rem;
|
||||||
|
vertical-align: top;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#wrapper {
|
#wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -23,17 +46,6 @@
|
|||||||
span.project-name {
|
span.project-name {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.icon {
|
|
||||||
svg {
|
|
||||||
display: inline-block;
|
|
||||||
height: 1.875rem;
|
|
||||||
vertical-align: top;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
p.current-user {
|
p.current-user {
|
||||||
@ -55,58 +67,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body#admin-panel {
|
|
||||||
#wrapper {
|
|
||||||
> header {
|
|
||||||
background: $color-red-bright;
|
|
||||||
background: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(153,12,14,0.9) 100%),
|
|
||||||
url('/img/bg-1.jpg');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-nav {
|
|
||||||
ul {
|
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
|
|
||||||
li {
|
|
||||||
a {
|
|
||||||
&.active {
|
|
||||||
border-bottom: 2px solid $color-red-bright;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flash-msg {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 2rem 0;
|
|
||||||
|
|
||||||
&.notice {
|
|
||||||
background: $background-color-notice;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.alert {
|
|
||||||
background: $background-color-alert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
width: $content-width;
|
|
||||||
max-width: $content-max-width;
|
|
||||||
margin: 4rem auto 6rem auto;
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
@include media-max(medium) {
|
|
||||||
max-width: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-max(small) {
|
|
||||||
margin: 3rem auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
p {
|
||||||
line-height: 1.5rem;
|
line-height: 1.5rem;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
@ -124,25 +85,9 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
section {
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
th, td {
|
|
||||||
&.hide-small {
|
|
||||||
@include media-max(small) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
th {
|
||||||
color: $text-color-discreet;
|
color: $text-color-discreet;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
7
app/components/header_compact_component.html.erb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<header class="py-10">
|
||||||
|
<div class="max-w-xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<h1 class="text-3xl font-bold text-white text-center">
|
||||||
|
<%= @title %>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
7
app/components/header_compact_component.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class HeaderCompactComponent < ViewComponent::Base
|
||||||
|
def initialize(title:)
|
||||||
|
@title = title
|
||||||
|
end
|
||||||
|
end
|
7
app/components/header_component.html.erb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<header class="py-10">
|
||||||
|
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<h1 class="text-3xl font-bold text-white">
|
||||||
|
<%= @title %>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
7
app/components/header_component.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class HeaderComponent < ViewComponent::Base
|
||||||
|
def initialize(title:)
|
||||||
|
@title = title
|
||||||
|
end
|
||||||
|
end
|
5
app/components/main_compact_component.html.erb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<main class="w-full max-w-xl mx-auto pb-12 px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
|
||||||
|
<%= content %>
|
||||||
|
</div>
|
||||||
|
</main>
|
5
app/components/main_compact_component.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MainCompactComponent < ViewComponent::Base
|
||||||
|
|
||||||
|
end
|
5
app/components/main_simple_component.html.erb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<main class="w-full max-w-6xl mx-auto pb-12 px-4 md:px-6 lg:px-8">
|
||||||
|
<div class="bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
|
||||||
|
<%= content %>
|
||||||
|
</div>
|
||||||
|
</main>
|
5
app/components/main_simple_component.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MainSimpleComponent < ViewComponent::Base
|
||||||
|
|
||||||
|
end
|
15
app/components/main_with_sidenav_component.html.erb
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<main class="w-full max-w-6xl mx-auto pb-12 px-4 md:px-6 lg:px-8">
|
||||||
|
<div class="bg-white rounded-lg shadow">
|
||||||
|
<div class="divide-y divide-gray-200 lg:grid lg:grid-cols-12 lg:divide-y-0 lg:divide-x">
|
||||||
|
<aside class="py-6 sm:py-8 lg:col-span-3">
|
||||||
|
<nav class="space-y-1">
|
||||||
|
<%= render partial: @sidenav_partial %>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
<div class="lg:col-span-9 px-6 sm:px-12 py-8 sm:pt-10 sm:pb-12">
|
||||||
|
<%= content %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
7
app/components/main_with_sidenav_component.rb
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class MainWithSidenavComponent < ViewComponent::Base
|
||||||
|
def initialize(sidenav_partial:)
|
||||||
|
@sidenav_partial = sidenav_partial
|
||||||
|
end
|
||||||
|
end
|
49
app/components/notification_component.html.erb
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<div class="flash-msg <%= @type %> hidden max-w-sm w-full bg-white shadow-lg rounded-lg pointer-events-auto mt-4"
|
||||||
|
data-turbo="false"
|
||||||
|
data-notification-action-url="<%= @data.dig(:action, :url) %>"
|
||||||
|
data-notification-action-method="<%= @data.dig(:action, :method) %>"
|
||||||
|
data-notification-timeout="<%= @data[:timeout] %>"
|
||||||
|
data-controller="notification">
|
||||||
|
<div class="rounded-lg shadow-xs overflow-hidden">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="flex items-start">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<span class="inline-block h-6 w-6 <%= @icon_color_class %>">
|
||||||
|
<%= render "icons/#{@icon_name}" %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="ml-3 w-0 flex-1 pt-0.5">
|
||||||
|
<p class="text-sm leading-5 font-medium text-gray-900">
|
||||||
|
<%= @data[:title] %>
|
||||||
|
</p>
|
||||||
|
<% if @data[:body].present? %>
|
||||||
|
<p class="mt-1 text-sm leading-5 text-gray-500">
|
||||||
|
<%= @data[:body] %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<% if @data[:action].present? %>
|
||||||
|
<div class="mt-2" data-notification-target="buttons">
|
||||||
|
<a data-turbo-frame="_top" <% if @data.dig(:action, :method) == 'get' %> href="<%= @data.dig(:action, :url) %>" <% else %> href="#" data-action="notification#run" <% end %> class="text-sm leading-5 font-medium text-indigo-600 hover:text-indigo-500 focus:outline-none focus:underline transition ease-in-out duration-150">
|
||||||
|
<%= @data.dig(:action, :name) %>
|
||||||
|
</a>
|
||||||
|
<button data-action="notification#close" class="ml-6 text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:underline transition ease-in-out duration-150">
|
||||||
|
<%= t('.dismiss') %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<div class="ml-4 flex-shrink-0 flex">
|
||||||
|
<button class="inline-flex text-gray-400 focus:outline-none focus:text-gray-500 transition ease-in-out duration-150" data-action="notification#close">
|
||||||
|
<!-- Heroicon name: solid/x -->
|
||||||
|
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
||||||
|
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% if @data[:countdown] %>
|
||||||
|
<div class="bg-indigo-600 rounded-lg h-1 w-0" data-notification-target="countdown"></div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
54
app/components/notification_component.rb
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# @param type [String] Classic notification type `error`, `alert` and `info` + custom `success`
|
||||||
|
# @param data [String, Hash] `String` for backward compatibility,
|
||||||
|
# `Hash` for the new functionality `{title: '', body: '', timeout: 5, countdown: false, action: { url: '', method: '', name: ''}}`.
|
||||||
|
# The `title` attribute for `Hash` is mandatory.
|
||||||
|
class NotificationComponent < ViewComponent::Base
|
||||||
|
def initialize(type:, data:)
|
||||||
|
@type = type
|
||||||
|
@data = prepare_data(data)
|
||||||
|
@icon_name = icon_name
|
||||||
|
@icon_color_class = icon_color_class
|
||||||
|
|
||||||
|
@data[:timeout] ||= 5
|
||||||
|
@data[:action][:method] ||= "get" if @data[:action]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def prepare_data(data)
|
||||||
|
case data
|
||||||
|
when Hash
|
||||||
|
data
|
||||||
|
else
|
||||||
|
{ title: data }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def icon_name
|
||||||
|
case @type
|
||||||
|
when 'success'
|
||||||
|
'check-circle'
|
||||||
|
when 'error'
|
||||||
|
'alert-octagon'
|
||||||
|
when 'alert'
|
||||||
|
'alert-octagon'
|
||||||
|
else
|
||||||
|
'info'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def icon_color_class
|
||||||
|
case @type
|
||||||
|
when 'success'
|
||||||
|
'text-emerald-500'
|
||||||
|
when 'error'
|
||||||
|
'text-rose-600'
|
||||||
|
when 'alert'
|
||||||
|
'text-rose-600'
|
||||||
|
else
|
||||||
|
'text-gray-400'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
4
app/components/sidenav_link_component.html.erb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<%= link_to @path, class: @link_class do %>
|
||||||
|
<%= render partial: "icons/#{@icon}", locals: { custom_class: @icon_class } %>
|
||||||
|
<span class="truncate"><%= @name %></span>
|
||||||
|
<% end %>
|
33
app/components/sidenav_link_component.rb
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SidenavLinkComponent < ViewComponent::Base
|
||||||
|
def initialize(name:, path:, icon:, active: false, disabled: false)
|
||||||
|
@name = name
|
||||||
|
@path = path
|
||||||
|
@icon = icon
|
||||||
|
@active = active
|
||||||
|
@disabled = disabled
|
||||||
|
@link_class = class_names_link(path)
|
||||||
|
@icon_class = class_names_icon(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def class_names_link(path)
|
||||||
|
if @active
|
||||||
|
"bg-teal-50 border-teal-500 text-teal-700 hover:bg-teal-50 hover:text-teal-700 group border-l-4 px-4 py-2 flex items-center text-base font-medium"
|
||||||
|
elsif @disabled
|
||||||
|
"border-transparent text-gray-400 hover:bg-gray-50 group border-l-4 px-4 py-2 flex items-center text-base font-medium"
|
||||||
|
else
|
||||||
|
"border-transparent text-gray-900 hover:bg-gray-50 hover:text-gray-900 group border-l-4 px-4 py-2 flex items-center text-base font-medium"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def class_names_icon(path)
|
||||||
|
if @active
|
||||||
|
"text-teal-500 group-hover:text-teal-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
|
||||||
|
elsif @disabled
|
||||||
|
"text-gray-300 group-hover:text-gray-300 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
|
||||||
|
else
|
||||||
|
"text-gray-400 group-hover:text-gray-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -2,7 +2,10 @@ class Admin::BaseController < ApplicationController
|
|||||||
|
|
||||||
before_action :authenticate_user!
|
before_action :authenticate_user!
|
||||||
before_action :authorize_admin
|
before_action :authorize_admin
|
||||||
|
before_action :set_context
|
||||||
|
|
||||||
layout "admin"
|
def set_context
|
||||||
|
@context = :admin
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -2,8 +2,6 @@ class InvitationsController < ApplicationController
|
|||||||
before_action :require_user_signed_in, except: ["show"]
|
before_action :require_user_signed_in, except: ["show"]
|
||||||
before_action :require_user_signed_out, only: ["show"]
|
before_action :require_user_signed_out, only: ["show"]
|
||||||
|
|
||||||
layout "signup", only: ["show"]
|
|
||||||
|
|
||||||
# GET /invitations
|
# GET /invitations
|
||||||
def index
|
def index
|
||||||
@invitations_unused = current_user.invitations.unused
|
@invitations_unused = current_user.invitations.unused
|
||||||
|
@ -3,8 +3,7 @@ class SignupController < ApplicationController
|
|||||||
before_action :require_invitation
|
before_action :require_invitation
|
||||||
before_action :set_invitation
|
before_action :set_invitation
|
||||||
before_action :set_new_user, only: ["steps", "validate"]
|
before_action :set_new_user, only: ["steps", "validate"]
|
||||||
|
before_action :set_context
|
||||||
layout "signup"
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@invited_by_name = @invitation.user.address
|
@invited_by_name = @invitation.user.address
|
||||||
@ -105,4 +104,8 @@ class SignupController < ApplicationController
|
|||||||
invitation: @invitation
|
invitation: @invitation
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_context
|
||||||
|
@context = :signup
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,4 +2,13 @@ module ApplicationHelper
|
|||||||
def sats_to_btc(sats)
|
def sats_to_btc(sats)
|
||||||
sats.to_f / 100000000
|
sats.to_f / 100000000
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def main_nav_class(current_section, link_to_section)
|
||||||
|
if current_section == link_to_section
|
||||||
|
"bg-gray-900/50 text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block"
|
||||||
|
else
|
||||||
|
"text-gray-300 hover:bg-gray-900/30 hover:text-white active:bg-gray-900/30 active:text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
|
||||||
import "@hotwired/turbo-rails"
|
import "@hotwired/turbo-rails"
|
||||||
// import "controllers"
|
import "controllers"
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import { Controller } from "@hotwired/stimulus"
|
|
||||||
|
|
||||||
export default class extends Controller {
|
|
||||||
connect() {
|
|
||||||
this.element.textContent = "Hello World!"
|
|
||||||
}
|
|
||||||
}
|
|
110
app/javascript/controllers/notification_controller.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = ["buttons", "countdown"]
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
const timeoutSeconds = parseInt(this.data.get("timeout"));
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.classList.remove('hidden');
|
||||||
|
this.element.classList.add('notification-enter', 'notification-enter-from');
|
||||||
|
|
||||||
|
// Trigger transition
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.classList.add('notification-enter-to');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Trigger countdown
|
||||||
|
if (this.hasCountdownTarget) {
|
||||||
|
this.countdownTarget.style.animation = 'notification-countdown linear ' + timeoutSeconds + 's';
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 500);
|
||||||
|
this.timeoutId = setTimeout(() => {
|
||||||
|
this.close();
|
||||||
|
}, timeoutSeconds * 1000 + 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
run(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.stop();
|
||||||
|
let _this = this;
|
||||||
|
this.buttonsTarget.innerHTML = '<span class="text-sm leading-5 font-medium text-grey-700">Processing...</span>';
|
||||||
|
|
||||||
|
// Call the action
|
||||||
|
fetch(this.data.get("action-url"), {
|
||||||
|
method: this.data.get("action-method").toUpperCase(),
|
||||||
|
dataType: 'script',
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
"X-CSRF-Token": this.csrfToken
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw Error(response.statusText);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
// Set new content
|
||||||
|
_this.buttonsTarget.innerHTML = '<span class="text-sm leading-5 font-medium text-green-700">' + data.message + '</span>';
|
||||||
|
|
||||||
|
// Remove hidden class and display the record
|
||||||
|
if (data.inline) {
|
||||||
|
document.getElementById(data.dom_id).classList.toggle('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close
|
||||||
|
setTimeout(() => {
|
||||||
|
if (data.inline) {
|
||||||
|
// Just close the notification
|
||||||
|
_this.close();
|
||||||
|
} else {
|
||||||
|
// Reload the page using Turbo
|
||||||
|
window.Turbo.visit(window.location.toString(), {action: 'replace'})
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
_this.buttonsTarget.innerHTML = '<span class="text-sm leading-5 font-medium text-red-700">Error!</span>';
|
||||||
|
setTimeout(() => {
|
||||||
|
_this.close();
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
clearTimeout(this.timeoutId)
|
||||||
|
this.timeoutId = null
|
||||||
|
}
|
||||||
|
|
||||||
|
continue() {
|
||||||
|
this.timeoutId = setTimeout(() => {
|
||||||
|
this.close();
|
||||||
|
}, parseInt(this.data.get("timeout")));
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.element.classList.remove('notification-enter', 'notification-enter-from', 'notification-enter-to');
|
||||||
|
this.element.classList.add('notification-leave', 'notification-leave-from')
|
||||||
|
|
||||||
|
// Trigger transition
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.classList.add('notification-leave-to');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// Remove element after transition
|
||||||
|
setTimeout(() => {
|
||||||
|
this.element.remove();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
get csrfToken() {
|
||||||
|
const element = document.head.querySelector('meta[name="csrf-token"]')
|
||||||
|
return element.getAttribute("content")
|
||||||
|
}
|
||||||
|
}
|
31
app/javascript/controllers/topbar_controller.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Controller } from "@hotwired/stimulus"
|
||||||
|
|
||||||
|
function show (element) {
|
||||||
|
element.classList.add('block');
|
||||||
|
element.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide (element) {
|
||||||
|
element.classList.remove('block');
|
||||||
|
element.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class extends Controller {
|
||||||
|
static targets = [ 'mobileMenu', 'iconMobileMenuOpen', 'iconMobileMenuClose' ];
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.mobileMenuTarget.classList.add('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleMobileNav() {
|
||||||
|
if (this.mobileMenuTarget.classList.contains('hidden')) {
|
||||||
|
show(this.mobileMenuTarget);
|
||||||
|
show(this.iconMobileMenuCloseTarget);
|
||||||
|
hide(this.iconMobileMenuOpenTarget);
|
||||||
|
} else {
|
||||||
|
hide(this.mobileMenuTarget);
|
||||||
|
hide(this.iconMobileMenuCloseTarget);
|
||||||
|
show(this.iconMobileMenuOpenTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,7 @@
|
|||||||
<p class="text-center">
|
<%= render HeaderComponent.new(title: "Admin Panel") %>
|
||||||
|
|
||||||
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<p class="text-center">
|
||||||
With great power comes great responsibility.
|
With great power comes great responsibility.
|
||||||
</p>
|
</p>
|
||||||
|
<% end %>
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
<h2>Editing Donation</h2>
|
<%= render HeaderComponent.new(title: "Donations") %>
|
||||||
|
|
||||||
<%= render 'form', donation: @donation, url: admin_donation_path(@donation) %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<h2>Editing Donation</h2>
|
||||||
|
|
||||||
<p class="mt-8">
|
<%= render 'form', donation: @donation, url: admin_donation_path(@donation) %>
|
||||||
|
|
||||||
|
<p class="mt-8">
|
||||||
<%= link_to 'Show', admin_donation_path(@donation), class: 'ks-text-link' %> |
|
<%= link_to 'Show', admin_donation_path(@donation), class: 'ks-text-link' %> |
|
||||||
<%= link_to 'Back', admin_donations_path, class: 'ks-text-link' %>
|
<%= link_to 'Back', admin_donations_path, class: 'ks-text-link' %>
|
||||||
<p>
|
<p>
|
||||||
|
<% end %>
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
<h2>Donations</h2>
|
<%= render HeaderComponent.new(title: "Donations") %>
|
||||||
|
|
||||||
<% if @donations.any? %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<table>
|
<% if @donations.any? %>
|
||||||
|
<table class="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr class="text-left">
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
<th>Amount BTC</th>
|
<th>Amount BTC</th>
|
||||||
<th>in EUR</th>
|
<th>in EUR</th>
|
||||||
@ -17,25 +18,27 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% @donations.each do |donation| %>
|
<% @donations.each do |donation| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= donation.user.cn %></td>
|
<td><%= donation.user.address %></td>
|
||||||
<td><%= sats_to_btc donation.amount_sats %> BTC</td>
|
<td><%= sats_to_btc donation.amount_sats %> BTC</td>
|
||||||
<td><%= number_to_currency donation.amount_eur / 100, unit: "" %></td>
|
<td><% if donation.amount_eur.present? %><%= number_to_currency donation.amount_eur / 100, unit: "" %><% end %></td>
|
||||||
<td><%= number_to_currency donation.amount_usd / 100, unit: "" %></td>
|
<td><% if donation.amount_usd.present? %><%= number_to_currency donation.amount_usd / 100, unit: "" %><% end %></td>
|
||||||
<td><%= donation.public_name %></td>
|
<td><%= donation.public_name %></td>
|
||||||
<td><%= donation.paid_at ? donation.paid_at.strftime("%Y-%m-%d") : "" %></td>
|
<td><%= donation.paid_at ? donation.paid_at.strftime("%Y-%m-%d") : "" %></td>
|
||||||
<td><%= link_to 'Show', admin_donation_path(donation), class: 'btn btn-sm btn-gray' %></td>
|
<td><%= link_to 'Show', admin_donation_path(donation), class: 'btn btn-sm btn-gray' %></td>
|
||||||
<td><%= link_to 'Edit', edit_admin_donation_path(donation), class: 'btn btn-sm btn-gray' %></td>
|
<td><%= link_to 'Edit', edit_admin_donation_path(donation), class: 'btn btn-sm btn-gray' %></td>
|
||||||
<td><%= link_to 'Destroy', admin_donation_path(donation), class: 'btn btn-sm btn-red', method: :delete, data: { confirm: 'Are you sure?' } %></td>
|
<td><%= link_to 'Destroy', admin_donation_path(donation), class: 'btn btn-sm btn-red',
|
||||||
|
data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' } %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>
|
<p>
|
||||||
No donations yet.
|
No donations yet.
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<p class="mt-12">
|
<p class="mt-12">
|
||||||
<%= link_to 'Record an out-of-system donation', new_admin_donation_path, class: 'btn-md btn-gray' %>
|
<%= link_to 'Record an out-of-system donation', new_admin_donation_path, class: 'btn-md btn-gray' %>
|
||||||
</p>
|
</p>
|
||||||
|
<% end %>
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
<h2>New Donation</h2>
|
<%= render HeaderComponent.new(title: "Donations") %>
|
||||||
|
|
||||||
<%= render 'form', donation: @donation, url: admin_donations_path %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<h2>New Donation</h2>
|
||||||
|
|
||||||
<p class="mt-8">
|
<%= render 'form', donation: @donation, url: admin_donations_path %>
|
||||||
|
|
||||||
|
<p class="mt-8">
|
||||||
<%= link_to 'Back', admin_donations_path, class: 'ks-text-link' %>
|
<%= link_to 'Back', admin_donations_path, class: 'ks-text-link' %>
|
||||||
</p>
|
</p>
|
||||||
|
<% end %>
|
||||||
|
@ -1,36 +1,38 @@
|
|||||||
<p id="notice"><%= notice %></p>
|
<%= render HeaderComponent.new(title: "Donations") %>
|
||||||
|
|
||||||
<p>
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<p>
|
||||||
<strong>User:</strong>
|
<strong>User:</strong>
|
||||||
<%= @donation.user_id %>
|
<%= @donation.user.address %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Amount sats:</strong>
|
<strong>Amount sats:</strong>
|
||||||
<%= @donation.amount_sats %>
|
<%= @donation.amount_sats %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Amount eur:</strong>
|
<strong>Amount eur:</strong>
|
||||||
<%= @donation.amount_eur %>
|
<%= @donation.amount_eur %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Amount usd:</strong>
|
<strong>Amount usd:</strong>
|
||||||
<%= @donation.amount_usd %>
|
<%= @donation.amount_usd %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Public name:</strong>
|
<strong>Public name:</strong>
|
||||||
<%= @donation.public_name %>
|
<%= @donation.public_name %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<strong>Date:</strong>
|
<strong>Date:</strong>
|
||||||
<%= @donation.paid_at %>
|
<%= @donation.paid_at %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="mt-8">
|
<p class="mt-8">
|
||||||
<%= link_to 'Edit', edit_admin_donation_path(@donation), class: 'ks-text-link' %> |
|
<%= link_to 'Edit', edit_admin_donation_path(@donation), class: 'ks-text-link' %> |
|
||||||
<%= link_to 'Back', admin_donations_path, class: 'ks-text-link' %>
|
<%= link_to 'Back', admin_donations_path, class: 'ks-text-link' %>
|
||||||
</p>
|
</p>
|
||||||
|
<% end %>
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
<section>
|
<%= render HeaderComponent.new(title: "Invitations") %>
|
||||||
<h2>Invitations</h2>
|
|
||||||
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<section>
|
||||||
<p>
|
<p>
|
||||||
There are currently <strong><%= @invitations_unused_count %>
|
There are currently <strong><%= @invitations_unused_count %>
|
||||||
unused invitations</strong> available to existing users.
|
unused invitations</strong> available to existing users.
|
||||||
<strong><%= @users_with_referrals_count %> users</strong> have successfully
|
<strong><%= @users_with_referrals_count %> users</strong> have successfully
|
||||||
invited new users.
|
invited new users.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<% if @invitations_used.any? %>
|
<% if @invitations_used.any? %>
|
||||||
<section>
|
<section>
|
||||||
<h3>Accepted (<%= @invitations_used.length %>)</h3>
|
<h3>Accepted (<%= @invitations_used.length %>)</h3>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr class="text-left">
|
||||||
<th>Token</th>
|
<th>Token</th>
|
||||||
<th>Accepted</th>
|
<th>Accepted</th>
|
||||||
<th>Invited user</th>
|
<th>Invited user</th>
|
||||||
@ -21,7 +23,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<% @invitations_used.each do |invitation| %>
|
<% @invitations_used.each do |invitation| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="overflow-ellipsis"><%= invitation.token %></td>
|
<td class="overflow-ellipsis font-mono"><%= invitation.token %></td>
|
||||||
<td><%= invitation.used_at.strftime("%Y-%m-%d") %></td>
|
<td><%= invitation.used_at.strftime("%Y-%m-%d") %></td>
|
||||||
<td><%= User.find(invitation.invited_user_id).address %></td>
|
<td><%= User.find(invitation.invited_user_id).address %></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -29,4 +31,5 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</section>
|
</section>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
<h2>LDAP users: <%= @ou %></h2>
|
<%= render HeaderComponent.new(title: "LDAP Users: #{@ou}") %>
|
||||||
|
|
||||||
<h3 class="hidden">Domains</h3>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<ul class="mb-10">
|
<h3 class="hidden">Domains</h3>
|
||||||
|
<ul class="mb-10">
|
||||||
<li class="inline-block">
|
<li class="inline-block">
|
||||||
<%= link_to 'kosmos.org', admin_ldap_users_path, class: "ks-text-link" %>
|
<%= link_to 'kosmos.org', admin_ldap_users_path, class: "ks-text-link" %>
|
||||||
</li>
|
</li>
|
||||||
<li class="inline-block ml-6">
|
<li class="inline-block ml-6">
|
||||||
<%= link_to '5apps.com', admin_ldap_users_path(ou: '5apps.com'), class: "ks-text-link" %>
|
<%= link_to '5apps.com', admin_ldap_users_path(ou: '5apps.com'), class: "ks-text-link" %>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr class="text-left">
|
||||||
<th>UID</th>
|
<th>UID</th>
|
||||||
<th>E-Mail</th>
|
<th>E-Mail</th>
|
||||||
<th>Admin</th>
|
<th>Admin</th>
|
||||||
@ -29,4 +30,5 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<% end %>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
<section>
|
<%= render HeaderComponent.new(title: "Services") %>
|
||||||
<h2>Services</h2>
|
|
||||||
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<section>
|
||||||
<p>
|
<p>
|
||||||
Your Kosmos account and password currently give you access to these
|
Your Kosmos account and password currently give you access to these
|
||||||
services:
|
services:
|
||||||
@ -55,4 +57,5 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<% end %>
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
<h2>Resend confirmation instructions</h2>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|
||||||
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
<%= render MainCompactComponent.new do %>
|
||||||
|
<h2>Resend confirmation instructions</h2>
|
||||||
|
|
||||||
|
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
||||||
<%= render "devise/shared/error_messages", resource: resource %>
|
<%= render "devise/shared/error_messages", resource: resource %>
|
||||||
<p>
|
<p>
|
||||||
<%= f.label :email, 'Email address', class: 'block mb-1' %>
|
<%= f.label :email, 'Email address', class: 'block mb-1 w-full' %>
|
||||||
<%= f.email_field :email, required: true, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
|
<%= f.email_field :email,
|
||||||
|
required: true, autofocus: true, autocomplete: "email",
|
||||||
|
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email),
|
||||||
|
class: "w-full" %>
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-8">
|
<p class="mt-8">
|
||||||
<%= f.submit "Resend confirmation instructions", class: 'btn-md btn-blue' %>
|
<%= f.submit "Resend confirmation link",
|
||||||
|
class: 'btn-md btn-blue w-full sm:w-auto' %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
<%= render "devise/shared/links" %>
|
||||||
|
<% end %>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<h2>Change your password</h2>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|
||||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
|
<%= render MainCompactComponent.new do %>
|
||||||
|
<h2>Change your password</h2>
|
||||||
|
|
||||||
|
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
|
||||||
<%= render "devise/shared/error_messages", resource: resource %>
|
<%= render "devise/shared/error_messages", resource: resource %>
|
||||||
<%= f.hidden_field :reset_password_token %>
|
<%= f.hidden_field :reset_password_token %>
|
||||||
|
|
||||||
@ -22,6 +25,7 @@
|
|||||||
<p class="mt-8">
|
<p class="mt-8">
|
||||||
<%= f.submit "Change my password", class: 'btn-md btn-blue' %>
|
<%= f.submit "Change my password", class: 'btn-md btn-blue' %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
<%= render "devise/shared/links" %>
|
||||||
|
<% end %>
|
||||||
|
@ -1,18 +1,25 @@
|
|||||||
<h2>Forgot your password?</h2>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|
||||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
|
<%= render MainCompactComponent.new do %>
|
||||||
|
<h2>Forgot your password?</h2>
|
||||||
|
|
||||||
|
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
|
||||||
<%= render "devise/shared/error_messages", resource: resource %>
|
<%= render "devise/shared/error_messages", resource: resource %>
|
||||||
<p>
|
<p>
|
||||||
<%= f.label :cn, 'User', class: 'block' %>
|
<%= f.label :cn, 'User', class: 'block' %>
|
||||||
<%= f.text_field :cn, autofocus: true, autocomplete: "username", required: true %> @ kosmos.org
|
<%= f.text_field :cn, autofocus: true, autocomplete: "username",
|
||||||
|
required: true, class: "w-full md:w-3/5"%>
|
||||||
|
<span class="ml-1 text-gray-500">@ kosmos.org</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<%= f.label :email, 'Email address', class: 'block' %>
|
<%= f.label :email, 'Email address', class: 'block' %>
|
||||||
<%= f.email_field :email, autocomplete: "email", required: true %>
|
<%= f.email_field :email, autocomplete: "email", required: true,
|
||||||
|
class: "w-full md:w-3/5"%>
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-8">
|
<p class="mt-8">
|
||||||
<%= f.submit "Send me reset password instructions", class: 'btn-md btn-blue' %>
|
<%= f.submit "Send me a reset link", class: 'btn-md btn-blue w-full sm:w-auto' %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
<%= render "devise/shared/links" %>
|
||||||
|
<% end %>
|
||||||
|
@ -1,18 +1,23 @@
|
|||||||
<h2>Log in</h2>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|
||||||
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
<%= render MainCompactComponent.new do %>
|
||||||
|
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
||||||
<%= render "devise/shared/error_messages", resource: resource %>
|
<%= render "devise/shared/error_messages", resource: resource %>
|
||||||
<p>
|
<p>
|
||||||
<%= f.label :cn, 'User', class: 'block' %>
|
<%= f.label :cn, 'User', class: 'block' %>
|
||||||
<%= f.text_field :cn, autofocus: true, autocomplete: "username" %> @ kosmos.org
|
<%= f.text_field :cn, autofocus: true, autocomplete: "username",
|
||||||
|
class: "w-full md:w-3/5"%>
|
||||||
|
<span class="ml-1 text-gray-500">@ kosmos.org</span>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<%= f.label :password, class: 'block' %>
|
<%= f.label :password, class: 'block' %>
|
||||||
<%= f.password_field :password, autocomplete: "current-password" %>
|
<%= f.password_field :password, autocomplete: "current-password",
|
||||||
|
class: "w-full md:w-3/5"%>
|
||||||
</p>
|
</p>
|
||||||
<p class="mt-8">
|
<p class="mt-8">
|
||||||
<%= f.submit "Log in", class: 'btn-md btn-blue' %>
|
<%= f.submit "Log in", class: 'btn-md btn-blue w-full sm:w-auto' %>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
<%= render "devise/shared/links" %>
|
||||||
|
<% end %>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<section>
|
<%= render HeaderComponent.new(title: "Donations") %>
|
||||||
<h2>Donations</h2>
|
|
||||||
<p>
|
|
||||||
Your financial contributions to the development and
|
|
||||||
upkeep of Kosmos software and services.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<section>
|
||||||
|
<p class="mb-12">
|
||||||
|
Your financial contributions to the development and upkeep of Kosmos
|
||||||
|
software and services.
|
||||||
|
</p>
|
||||||
<% if @donations.any? %>
|
<% if @donations.any? %>
|
||||||
<ul class="donations list-none">
|
<ul class="list-none">
|
||||||
<% @donations.each do |donation| %>
|
<% @donations.each do |donation| %>
|
||||||
<li class="mb-8 grid gap-y-2 gap-x-8 grid-cols-2 items-center">
|
<li class="mb-8 grid gap-y-2 gap-x-8 grid-cols-2 items-center">
|
||||||
<h3 class="mb-0">
|
<h3 class="mb-0">
|
||||||
@ -34,8 +33,9 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>
|
<p class="text-gray-500">
|
||||||
No donations to show.
|
No donations to show.
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</section>
|
</section>
|
||||||
|
<% end %>
|
||||||
|
1
app/views/icons/_activity.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-activity"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"></polyline></svg>
|
After Width: | Height: | Size: 282 B |
1
app/views/icons/_airplay.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-airplay"><path d="M5 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-1"></path><polygon points="12 15 17 21 7 21 12 15"></polygon></svg>
|
After Width: | Height: | Size: 362 B |
1
app/views/icons/_alert-circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
|
After Width: | Height: | Size: 356 B |
1
app/views/icons/_alert-octagon.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-octagon"><polygon points="7.86 2 16.14 2 22 7.86 22 16.14 16.14 22 7.86 22 2 16.14 2 7.86 7.86 2"></polygon><line x1="12" y1="8" x2="12" y2="12"></line><line x1="12" y1="16" x2="12.01" y2="16"></line></svg>
|
After Width: | Height: | Size: 416 B |
1
app/views/icons/_alert-triangle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-alert-triangle"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
After Width: | Height: | Size: 424 B |
1
app/views/icons/_align-center.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-align-center"><line x1="18" y1="10" x2="6" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="18" y1="18" x2="6" y2="18"></line></svg>
|
After Width: | Height: | Size: 398 B |
1
app/views/icons/_align-justify.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-align-justify"><line x1="21" y1="10" x2="3" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="21" y1="18" x2="3" y2="18"></line></svg>
|
After Width: | Height: | Size: 399 B |
1
app/views/icons/_align-left.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-align-left"><line x1="17" y1="10" x2="3" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="17" y1="18" x2="3" y2="18"></line></svg>
|
After Width: | Height: | Size: 396 B |
1
app/views/icons/_align-right.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-align-right"><line x1="21" y1="10" x2="7" y2="10"></line><line x1="21" y1="6" x2="3" y2="6"></line><line x1="21" y1="14" x2="3" y2="14"></line><line x1="21" y1="18" x2="7" y2="18"></line></svg>
|
After Width: | Height: | Size: 397 B |
1
app/views/icons/_anchor.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-anchor"><circle cx="12" cy="5" r="3"></circle><line x1="12" y1="22" x2="12" y2="8"></line><path d="M5 12H2a10 10 0 0 0 20 0h-3"></path></svg>
|
After Width: | Height: | Size: 345 B |
1
app/views/icons/_aperture.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-aperture"><circle cx="12" cy="12" r="10"></circle><line x1="14.31" y1="8" x2="20.05" y2="17.94"></line><line x1="9.69" y1="8" x2="21.17" y2="8"></line><line x1="7.38" y1="12" x2="13.12" y2="2.06"></line><line x1="9.69" y1="16" x2="3.95" y2="6.06"></line><line x1="14.31" y1="16" x2="2.83" y2="16"></line><line x1="16.62" y1="12" x2="10.88" y2="21.94"></line></svg>
|
After Width: | Height: | Size: 568 B |
1
app/views/icons/_archive.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-archive"><polyline points="21 8 21 21 3 21 3 8"></polyline><rect x="1" y="3" width="22" height="5"></rect><line x1="10" y1="12" x2="14" y2="12"></line></svg>
|
After Width: | Height: | Size: 361 B |
1
app/views/icons/_arrow-down-circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-down-circle"><circle cx="12" cy="12" r="10"></circle><polyline points="8 12 12 16 16 12"></polyline><line x1="12" y1="8" x2="12" y2="16"></line></svg>
|
After Width: | Height: | Size: 360 B |
1
app/views/icons/_arrow-down-left.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-down-left"><line x1="17" y1="7" x2="7" y2="17"></line><polyline points="17 17 7 17 7 7"></polyline></svg>
|
After Width: | Height: | Size: 315 B |
1
app/views/icons/_arrow-down-right.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-down-right"><line x1="7" y1="7" x2="17" y2="17"></line><polyline points="17 7 17 17 7 17"></polyline></svg>
|
After Width: | Height: | Size: 317 B |
1
app/views/icons/_arrow-down.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-down"><line x1="12" y1="5" x2="12" y2="19"></line><polyline points="19 12 12 19 5 12"></polyline></svg>
|
After Width: | Height: | Size: 313 B |
1
app/views/icons/_arrow-left-circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left-circle"><circle cx="12" cy="12" r="10"></circle><polyline points="12 8 8 12 12 16"></polyline><line x1="16" y1="12" x2="8" y2="12"></line></svg>
|
After Width: | Height: | Size: 359 B |
1
app/views/icons/_arrow-left.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>
|
After Width: | Height: | Size: 312 B |
1
app/views/icons/_arrow-right-circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right-circle"><circle cx="12" cy="12" r="10"></circle><polyline points="12 16 16 12 12 8"></polyline><line x1="8" y1="12" x2="16" y2="12"></line></svg>
|
After Width: | Height: | Size: 361 B |
1
app/views/icons/_arrow-right.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>
|
After Width: | Height: | Size: 314 B |
1
app/views/icons/_arrow-up-circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-up-circle"><circle cx="12" cy="12" r="10"></circle><polyline points="16 12 12 8 8 12"></polyline><line x1="12" y1="16" x2="12" y2="8"></line></svg>
|
After Width: | Height: | Size: 357 B |
1
app/views/icons/_arrow-up-left.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-up-left"><line x1="17" y1="17" x2="7" y2="7"></line><polyline points="7 17 7 7 17 7"></polyline></svg>
|
After Width: | Height: | Size: 312 B |
1
app/views/icons/_arrow-up-right.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-up-right"><line x1="7" y1="17" x2="17" y2="7"></line><polyline points="7 7 17 7 17 17"></polyline></svg>
|
After Width: | Height: | Size: 314 B |
1
app/views/icons/_arrow-up.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-up"><line x1="12" y1="19" x2="12" y2="5"></line><polyline points="5 12 12 5 19 12"></polyline></svg>
|
After Width: | Height: | Size: 310 B |
1
app/views/icons/_at-sign.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-at-sign"><circle cx="12" cy="12" r="4"></circle><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.92 7.94"></path></svg>
|
After Width: | Height: | Size: 322 B |
1
app/views/icons/_award.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-award"><circle cx="12" cy="8" r="7"></circle><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"></polyline></svg>
|
After Width: | Height: | Size: 325 B |
1
app/views/icons/_bar-chart-2.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2"><line x1="18" y1="20" x2="18" y2="10"></line><line x1="12" y1="20" x2="12" y2="4"></line><line x1="6" y1="20" x2="6" y2="14"></line></svg>
|
After Width: | Height: | Size: 355 B |
1
app/views/icons/_bar-chart.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart"><line x1="12" y1="20" x2="12" y2="10"></line><line x1="18" y1="20" x2="18" y2="4"></line><line x1="6" y1="20" x2="6" y2="16"></line></svg>
|
After Width: | Height: | Size: 353 B |
1
app/views/icons/_battery-charging.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-battery-charging"><path d="M5 18H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3.19M15 6h2a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-3.19"></path><line x1="23" y1="13" x2="23" y2="11"></line><polyline points="11 6 7 12 13 12 9 18"></polyline></svg>
|
After Width: | Height: | Size: 427 B |
1
app/views/icons/_battery.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-battery"><rect x="1" y="6" width="18" height="12" rx="2" ry="2"></rect><line x1="23" y1="13" x2="23" y2="11"></line></svg>
|
After Width: | Height: | Size: 326 B |
1
app/views/icons/_bell-off.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bell-off"><path d="M13.73 21a2 2 0 0 1-3.46 0"></path><path d="M18.63 13A17.89 17.89 0 0 1 18 8"></path><path d="M6.26 6.26A5.86 5.86 0 0 0 6 8c0 7-3 9-3 9h14"></path><path d="M18 8a6 6 0 0 0-9.33-5"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>
|
After Width: | Height: | Size: 460 B |
1
app/views/icons/_bell.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bell"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path></svg>
|
After Width: | Height: | Size: 321 B |
1
app/views/icons/_bluetooth.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bluetooth"><polyline points="6.5 6.5 17.5 17.5 12 23 12 1 17.5 6.5 6.5 17.5"></polyline></svg>
|
After Width: | Height: | Size: 298 B |
1
app/views/icons/_bold.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bold"><path d="M6 4h8a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path><path d="M6 12h9a4 4 0 0 1 4 4 4 4 0 0 1-4 4H6z"></path></svg>
|
After Width: | Height: | Size: 327 B |
1
app/views/icons/_book-open.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-book-open"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path></svg>
|
After Width: | Height: | Size: 339 B |
1
app/views/icons/_book.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-book"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"></path><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"></path></svg>
|
After Width: | Height: | Size: 345 B |
1
app/views/icons/_bookmark.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bookmark"><path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path></svg>
|
After Width: | Height: | Size: 287 B |
1
app/views/icons/_box.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-box"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>
|
After Width: | Height: | Size: 462 B |
1
app/views/icons/_briefcase.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-briefcase"><rect x="2" y="7" width="20" height="14" rx="2" ry="2"></rect><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"></path></svg>
|
After Width: | Height: | Size: 343 B |
1
app/views/icons/_calendar.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-calendar"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect><line x1="16" y1="2" x2="16" y2="6"></line><line x1="8" y1="2" x2="8" y2="6"></line><line x1="3" y1="10" x2="21" y2="10"></line></svg>
|
After Width: | Height: | Size: 410 B |
1
app/views/icons/_camera-off.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-camera-off"><line x1="1" y1="1" x2="23" y2="23"></line><path d="M21 21H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h3m3-3h6l2 3h4a2 2 0 0 1 2 2v9.34m-7.72-2.06a4 4 0 1 1-5.56-5.56"></path></svg>
|
After Width: | Height: | Size: 385 B |
1
app/views/icons/_camera.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-camera"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"></path><circle cx="12" cy="13" r="4"></circle></svg>
|
After Width: | Height: | Size: 356 B |
1
app/views/icons/_cast.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-cast"><path d="M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6"></path><line x1="2" y1="20" x2="2.01" y2="20"></line></svg>
|
After Width: | Height: | Size: 387 B |
1
app/views/icons/_check-circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>
|
After Width: | Height: | Size: 328 B |
1
app/views/icons/_check-square.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-square"><polyline points="9 11 12 14 22 4"></polyline><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path></svg>
|
After Width: | Height: | Size: 345 B |
1
app/views/icons/_check.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check"><polyline points="20 6 9 17 4 12"></polyline></svg>
|
After Width: | Height: | Size: 262 B |
1
app/views/icons/_chevron-down.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
After Width: | Height: | Size: 269 B |
1
app/views/icons/_chevron-left.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left"><polyline points="15 18 9 12 15 6"></polyline></svg>
|
After Width: | Height: | Size: 270 B |
1
app/views/icons/_chevron-right.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
After Width: | Height: | Size: 270 B |
1
app/views/icons/_chevron-up.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>
|
After Width: | Height: | Size: 268 B |
1
app/views/icons/_chevrons-down.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-down"><polyline points="7 13 12 18 17 13"></polyline><polyline points="7 6 12 11 17 6"></polyline></svg>
|
After Width: | Height: | Size: 317 B |
1
app/views/icons/_chevrons-left.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-left"><polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline></svg>
|
After Width: | Height: | Size: 318 B |
1
app/views/icons/_chevrons-right.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-right"><polyline points="13 17 18 12 13 7"></polyline><polyline points="6 17 11 12 6 7"></polyline></svg>
|
After Width: | Height: | Size: 318 B |
1
app/views/icons/_chevrons-up.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevrons-up"><polyline points="17 11 12 6 7 11"></polyline><polyline points="17 18 12 13 7 18"></polyline></svg>
|
After Width: | Height: | Size: 316 B |
1
app/views/icons/_chrome.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chrome"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4"></circle><line x1="21.17" y1="8" x2="12" y2="8"></line><line x1="3.95" y1="6.06" x2="8.54" y2="14"></line><line x1="10.88" y1="21.94" x2="15.46" y2="14"></line></svg>
|
After Width: | Height: | Size: 448 B |
1
app/views/icons/_circle.html.erb
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-circle"><circle cx="12" cy="12" r="10"></circle></svg>
|
After Width: | Height: | Size: 258 B |