Redesign layout and navigation #64

Merged
raucao merged 22 commits from feature/new_layout into master 2022-02-26 15:45:12 +00:00
348 changed files with 1456 additions and 774 deletions

View File

@ -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

View File

@ -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

View File

@ -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/)

View File

@ -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";

View File

@ -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;
}
} }

View File

@ -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;
} }

View File

@ -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 {

View 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;
}
}

View File

@ -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;

View 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>

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class HeaderCompactComponent < ViewComponent::Base
def initialize(title:)
@title = title
end
end

View 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>

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class HeaderComponent < ViewComponent::Base
def initialize(title:)
@title = title
end
end

View 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>

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
class MainCompactComponent < ViewComponent::Base
end

View 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>

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
class MainSimpleComponent < ViewComponent::Base
end

View 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>

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class MainWithSidenavComponent < ViewComponent::Base
def initialize(sidenav_partial:)
@sidenav_partial = sidenav_partial
end
end

View 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>

View 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

View 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 %>

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -1,7 +0,0 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
this.element.textContent = "Hello World!"
}
}

View 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")
}
}

View 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);
}
}
}

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

Some files were not shown because too many files have changed in this diff Show More