Compare commits
31 Commits
2b00eebb73
...
v0.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
4e0d4bf86d
|
|||
|
333bcbfe7e
|
|||
| 875af6d14c | |||
| 8f87a03060 | |||
|
7838fe5f34
|
|||
|
512798d122
|
|||
|
384c28aaaa
|
|||
|
8e5d6dabdc
|
|||
|
ade9261c2c
|
|||
|
bd2a161306
|
|||
|
78c243c985
|
|||
|
cf62bfc5c2
|
|||
|
10f179a095
|
|||
|
f7d0a0ba85
|
|||
| 83e4dfa18f | |||
|
4c70600d1f
|
|||
|
9903683536
|
|||
|
4c51b9c966
|
|||
| 6790e8383d | |||
|
ed886d8182
|
|||
|
ca940ec35d
|
|||
|
5751c0338a
|
|||
|
b9ec363f36
|
|||
|
417768a30c
|
|||
|
9824dcd2c6
|
|||
|
5a784b5fa6
|
|||
|
f36f6866a7
|
|||
|
1fecfe57de
|
|||
|
3165714957
|
|||
|
4ccf43cf4a
|
|||
|
c0e79918ea
|
@@ -29,9 +29,6 @@ steps:
|
|||||||
- yarn install
|
- yarn install
|
||||||
- rake css:build
|
- rake css:build
|
||||||
- rake spec
|
- rake spec
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- name: rebuild-cache
|
- name: rebuild-cache
|
||||||
image: drillster/drone-volume-cache
|
image: drillster/drone-volume-cache
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -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/)
|
||||||
|
|||||||
@@ -7,3 +7,4 @@
|
|||||||
@import "components/forms";
|
@import "components/forms";
|
||||||
@import "components/links";
|
@import "components/links";
|
||||||
@import "components/notifications";
|
@import "components/notifications";
|
||||||
|
@import "components/tables";
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply leading-none
|
@apply leading-none bg-cover bg-fixed;
|
||||||
|
background-image: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(13,79,153,0.8) 100%), url('/img/bg-1.jpg');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* h1, h2, h3 { */
|
body#admin {
|
||||||
/* @apply font-light; */
|
background-image: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(153,12,14,0.9) 100%), url('/img/bg-1.jpg');
|
||||||
/* } */
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@apply text-3xl uppercase;
|
@apply text-3xl uppercase;
|
||||||
@@ -18,4 +19,24 @@
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
main p {
|
||||||
|
@apply mb-4 leading-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
main ul {
|
||||||
|
@apply mb-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
main ul li {
|
||||||
|
@apply leading-6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
app/assets/stylesheets/components/tables.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@layer components {
|
||||||
|
table {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
table thead tr {
|
||||||
|
@apply text-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th {
|
||||||
|
@apply pb-3.5 text-sm font-normal uppercase text-gray-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
table th:not(:last-of-type),
|
||||||
|
table td:not(:last-of-type) {
|
||||||
|
@apply pr-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
table td {
|
||||||
|
@apply py-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
@import "legacy/layout";
|
|
||||||
@import "legacy/main_nav";
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
@import "variables";
|
|
||||||
@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-panel {
|
|
||||||
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 {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> header {
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 4rem 0;
|
|
||||||
text-align: center;
|
|
||||||
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;
|
|
||||||
|
|
||||||
@include media-max(small) {
|
|
||||||
padding: 3rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #fff;
|
|
||||||
|
|
||||||
span.project-name {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.current-user {
|
|
||||||
color: rgba(255,255,255,0.6);
|
|
||||||
|
|
||||||
@include media-max(small) {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: rgba(255,255,255,0.6);
|
|
||||||
transition: color 0.1s linear;
|
|
||||||
|
|
||||||
&:hover, &:active {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flash-msg {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 2rem 0;
|
|
||||||
|
|
||||||
&.notice {
|
|
||||||
background: $background-color-notice;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.alert {
|
|
||||||
background: $background-color-alert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
p {
|
|
||||||
line-height: 1.5rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
&.notice {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
|
|
||||||
li {
|
|
||||||
line-height: 1.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin-bottom: 3rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
th {
|
|
||||||
color: $text-color-discreet;
|
|
||||||
font-weight: normal;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-size: 0.85rem;
|
|
||||||
padding-bottom: 0.825rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
|
||||||
padding-top: 0.5rem;
|
|
||||||
padding-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
display: grid;
|
|
||||||
|
|
||||||
&.services {
|
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
|
||||||
grid-row-gap: 1rem;
|
|
||||||
grid-column-gap: 2rem;
|
|
||||||
|
|
||||||
@include media-max(small) {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
@import "variables";
|
|
||||||
@import "mediaqueries";
|
|
||||||
|
|
||||||
#main-nav {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #efefef;
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
width: $content-width;
|
|
||||||
max-width: $content-max-width;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
@include media-max(large) {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
@include media-min(large) {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-max(large) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 1.5rem 2rem;
|
|
||||||
text-decoration: none;
|
|
||||||
color: $text-color-discreet;
|
|
||||||
|
|
||||||
@include media-max(large) {
|
|
||||||
display: block;
|
|
||||||
text-align: center;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include media-max(small) {
|
|
||||||
font-size: 0.85rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: $text-color-body;
|
|
||||||
border-bottom: 2px solid #4ea2df;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
$breakpoints-max: (
|
|
||||||
small: 600px,
|
|
||||||
medium: 960px,
|
|
||||||
large: 1280px
|
|
||||||
);
|
|
||||||
|
|
||||||
$breakpoints-min: (
|
|
||||||
small: 601px,
|
|
||||||
medium: 961px,
|
|
||||||
large: 1281px
|
|
||||||
);
|
|
||||||
|
|
||||||
@mixin media-max($screen-size) {
|
|
||||||
@if map-has-key($breakpoints-max, $screen-size) {
|
|
||||||
@media (max-width: map-get($breakpoints-max, $screen-size)) {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
// Debugging
|
|
||||||
@warn "'#{$screen-size}' has not been declared as a breakpoint."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@mixin media-min($screen-size) {
|
|
||||||
@if map-has-key($breakpoints-min, $screen-size) {
|
|
||||||
@media (min-width: map-get($breakpoints-min, $screen-size)) {
|
|
||||||
@content;
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
// Debugging
|
|
||||||
@warn "'#{$screen-size}' has not been declared as a breakpoint."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
$content-width: 800px;
|
|
||||||
$content-max-width: 100%;
|
|
||||||
|
|
||||||
$text-color-body: #222;
|
|
||||||
$text-color-discreet: #888;
|
|
||||||
|
|
||||||
$background-color-notice: #efffc4;
|
|
||||||
$background-color-alert: #fff4c2;
|
|
||||||
|
|
||||||
$color-blue: #0d4f99;
|
|
||||||
$color-purple: #8955a0;
|
|
||||||
$color-red-bright: #c00;
|
|
||||||
$color-red-dark: #990c0e;
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<main class="w-full max-w-xl mx-auto pb-12 px-4 sm:px-6 lg:px-8">
|
<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 py-12 sm:px-12">
|
<div class="bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
|
||||||
<%= content %>
|
<%= content %>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<main class="w-full max-w-6xl mx-auto pb-12 px-4 sm:px-6 lg:px-8">
|
<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 py-12 sm:px-12">
|
<div class="bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
|
||||||
<%= content %>
|
<%= content %>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
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
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="hidden max-w-sm w-full bg-white shadow-lg rounded-lg pointer-events-auto mt-4"
|
<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-turbo="false"
|
||||||
data-notification-action-url="<%= @data.dig(:action, :url) %>"
|
data-notification-action-url="<%= @data.dig(:action, :url) %>"
|
||||||
data-notification-action-method="<%= @data.dig(:action, :method) %>"
|
data-notification-action-method="<%= @data.dig(:action, :method) %>"
|
||||||
|
|||||||
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
|
||||||
18
app/components/wallet_summary_component.html.erb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<section class="w-full grid grid-cols-1 md:grid-cols-12 md:mb-0">
|
||||||
|
<div class="md:col-span-8">
|
||||||
|
<p>
|
||||||
|
Send and receive sats via the Bitcoin Lightning Network.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="md:col-span-4 mt-4 md:mt-0">
|
||||||
|
<p class="font-mono md:text-right mb-0 p-4 border border-gray-300 rounded-lg overflow-hidden">
|
||||||
|
<% if @balance %>
|
||||||
|
<span class="text-xl"><%= number_with_delimiter @balance %> sats</span><br>
|
||||||
|
<span class="text-sm text-gray-500">Available balance</span>
|
||||||
|
<% else %>
|
||||||
|
<span class="text-xl">n/a sats</span><br>
|
||||||
|
<span class="text-sm text-gray-500">Balance unavailable</span>
|
||||||
|
<% end %>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
8
app/components/wallet_summary_component.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class WalletSummaryComponent < ViewComponent::Base
|
||||||
|
def initialize(balance:)
|
||||||
|
@balance = balance
|
||||||
|
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,6 +3,7 @@ class LnurlpayController < ApplicationController
|
|||||||
|
|
||||||
MIN_SATS = 100
|
MIN_SATS = 100
|
||||||
MAX_SATS = 1_000_000
|
MAX_SATS = 1_000_000
|
||||||
|
MAX_COMMENT_CHARS = 100
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: {
|
render json: {
|
||||||
@@ -12,22 +13,32 @@ class LnurlpayController < ApplicationController
|
|||||||
maxSendable: MAX_SATS * 1000, # msat
|
maxSendable: MAX_SATS * 1000, # msat
|
||||||
minSendable: MIN_SATS * 1000, # msat
|
minSendable: MIN_SATS * 1000, # msat
|
||||||
metadata: metadata(@user.address),
|
metadata: metadata(@user.address),
|
||||||
commentAllowed: 0
|
commentAllowed: MAX_COMMENT_CHARS
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def invoice
|
def invoice
|
||||||
amount = params[:amount].to_i / 1000 # msats
|
amount = params[:amount].to_i / 1000 # msats
|
||||||
address = params[:address]
|
address = params[:address]
|
||||||
|
comment = params[:comment] || ""
|
||||||
|
|
||||||
if !valid_amount?(amount)
|
if !valid_amount?(amount)
|
||||||
render json: { status: "ERROR", reason: "Invalid amount" }
|
render json: { status: "ERROR", reason: "Invalid amount" }
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if !valid_comment?(comment)
|
||||||
|
render json: { status: "ERROR", reason: "Comment too long" }
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
memo = "Sats for #{address}"
|
||||||
|
memo = "#{memo}: \"#{comment}\"" if comment.present?
|
||||||
|
|
||||||
payment_request = @user.ln_create_invoice({
|
payment_request = @user.ln_create_invoice({
|
||||||
amount: amount, # we create invoices in sats
|
amount: amount, # we create invoices in sats
|
||||||
description_hash: Digest::SHA2.hexdigest(metadata(address))
|
memo: memo,
|
||||||
|
description_hash: Digest::SHA2.hexdigest(metadata(address)),
|
||||||
})
|
})
|
||||||
|
|
||||||
render json: {
|
render json: {
|
||||||
@@ -57,4 +68,8 @@ class LnurlpayController < ApplicationController
|
|||||||
amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS
|
amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_comment?(comment)
|
||||||
|
comment.length <= MAX_COMMENT_CHARS
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ require "rqrcode"
|
|||||||
class WalletController < ApplicationController
|
class WalletController < ApplicationController
|
||||||
before_action :require_user_signed_in
|
before_action :require_user_signed_in
|
||||||
before_action :authenticate_with_lndhub
|
before_action :authenticate_with_lndhub
|
||||||
|
before_action :set_current_section
|
||||||
|
before_action :fetch_balance
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@current_section = :wallet
|
|
||||||
|
|
||||||
@wallet_url = "lndhub://#{current_user.ln_login}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
|
@wallet_url = "lndhub://#{current_user.ln_login}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
|
||||||
|
|
||||||
qrcode = RQRCode::QRCode.new(@wallet_url)
|
qrcode = RQRCode::QRCode.new(@wallet_url)
|
||||||
@@ -20,8 +20,10 @@ class WalletController < ApplicationController
|
|||||||
class: 'inline-block'
|
class: 'inline-block'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
|
||||||
@balance = fetch_balance rescue nil
|
def transactions
|
||||||
|
@transactions = fetch_transactions
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -39,9 +41,41 @@ class WalletController < ApplicationController
|
|||||||
# TODO add exception tracking
|
# TODO add exception tracking
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_current_section
|
||||||
|
@current_section = :wallet
|
||||||
|
end
|
||||||
|
|
||||||
def fetch_balance
|
def fetch_balance
|
||||||
lndhub = Lndhub.new
|
lndhub = Lndhub.new
|
||||||
data = lndhub.balance @ln_auth_token
|
data = lndhub.balance @ln_auth_token
|
||||||
data["BTC"]["AvailableBalance"]
|
@balance = data["BTC"]["AvailableBalance"] rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch_transactions
|
||||||
|
lndhub = Lndhub.new
|
||||||
|
txs = lndhub.gettxs @ln_auth_token
|
||||||
|
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
|
||||||
|
|
||||||
|
process_transactions(txs + invoices)
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_transactions(txs)
|
||||||
|
txs.collect do |tx|
|
||||||
|
if tx["type"] == "bitcoind_tx"
|
||||||
|
tx["amount_sats"] = (tx["amount"] * 100000000).to_i
|
||||||
|
tx["datetime"] = Time.at(tx["time"].to_i)
|
||||||
|
tx["title"] = "Received"
|
||||||
|
tx["description"] = "On-chain topup"
|
||||||
|
tx["received"] = true
|
||||||
|
else
|
||||||
|
tx["amount_sats"] = tx["value"] || tx["amt"]
|
||||||
|
tx["datetime"] = Time.at(tx["timestamp"].to_i)
|
||||||
|
tx["title"] = tx["type"] == "paid_invoice" ? "Sent" : "Received"
|
||||||
|
tx["description"] = tx["memo"] || tx["description"]
|
||||||
|
tx["received"] = tx["type"] == "user_invoice"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
txs.sort{ |a,b| b["datetime"] <=> a["datetime"] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ module ApplicationHelper
|
|||||||
|
|
||||||
def main_nav_class(current_section, link_to_section)
|
def main_nav_class(current_section, link_to_section)
|
||||||
if current_section == link_to_section
|
if current_section == link_to_section
|
||||||
"bg-gray-900/50 text-white px-3 py-2 rounded-md text-sm font-medium"
|
"bg-gray-900/50 text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block"
|
||||||
else
|
else
|
||||||
"text-gray-300 hover:bg-gray-900/30 hover:text-white px-3 py-2 rounded-md text-sm font-medium"
|
"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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,9 +46,18 @@ class Lndhub
|
|||||||
get "balance", user_token || auth_token
|
get "balance", user_token || auth_token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def gettxs(user_token)
|
||||||
|
get "gettxs", user_token || auth_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def getuserinvoices(user_token)
|
||||||
|
get "getuserinvoices", user_token || auth_token
|
||||||
|
end
|
||||||
|
|
||||||
def addinvoice(payload)
|
def addinvoice(payload)
|
||||||
invoice = post "addinvoice", {
|
invoice = post "addinvoice", {
|
||||||
amt: payload[:amount],
|
amt: payload[:amount],
|
||||||
|
memo: payload[:memo],
|
||||||
description_hash: payload[:description_hash]
|
description_hash: payload[:description_hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
<%= render MainSimpleComponent.new do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<% if @donations.any? %>
|
<% if @donations.any? %>
|
||||||
<table class="w-full">
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
<th>Amount BTC</th>
|
<th class="text-right">Amount BTC</th>
|
||||||
<th>in EUR</th>
|
<th class="text-right">in EUR</th>
|
||||||
<th>in USD</th>
|
<th class="text-right">in USD</th>
|
||||||
<th>Public name</th>
|
<th class="pl-2">Public name</th>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th colspan="3"></th>
|
<th colspan="3"></th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -19,15 +19,15 @@
|
|||||||
<% @donations.each do |donation| %>
|
<% @donations.each do |donation| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= donation.user.address %></td>
|
<td><%= donation.user.address %></td>
|
||||||
<td><%= sats_to_btc donation.amount_sats %> BTC</td>
|
<td class="text-right"><%= sats_to_btc donation.amount_sats %></td>
|
||||||
<td><% if donation.amount_eur.present? %><%= number_to_currency donation.amount_eur / 100, unit: "" %><% end %></td>
|
<td class="text-right"><% if donation.amount_eur.present? %><%= number_to_currency donation.amount_eur / 100, unit: "" %><% end %></td>
|
||||||
<td><% if donation.amount_usd.present? %><%= number_to_currency donation.amount_usd / 100, unit: "" %><% end %></td>
|
<td class="text-right"><% if donation.amount_usd.present? %><%= number_to_currency donation.amount_usd / 100, unit: "" %><% end %></td>
|
||||||
<td><%= donation.public_name %></td>
|
<td class="pl-2"><%= 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',
|
<td><%= link_to 'Destroy', admin_donation_path(donation), class: 'btn btn-sm btn-red',
|
||||||
data: { turbo_method: :delete, confirm: 'Are you sure?' } %></td>
|
data: { turbo_method: :delete, turbo_confirm: 'Are you sure?' } %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<h3>Accepted (<%= @invitations_used.length %>)</h3>
|
<h3>Accepted (<%= @invitations_used.length %>)</h3>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr>
|
||||||
<th>Token</th>
|
<th>Token</th>
|
||||||
<th>Accepted</th>
|
<th>Accepted</th>
|
||||||
<th>Invited user</th>
|
<th>Invited user</th>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr>
|
||||||
<th>UID</th>
|
<th>UID</th>
|
||||||
<th>E-Mail</th>
|
<th>E-Mail</th>
|
||||||
<th>Admin</th>
|
<th>Admin</th>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
Your Kosmos account and password currently give you access to these
|
Your Kosmos account and password currently give you access to these
|
||||||
services:
|
services:
|
||||||
</p>
|
</p>
|
||||||
<div class="grid services mt-12">
|
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6 services mt-12">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="mb-3.5">
|
<h3 class="mb-3.5">
|
||||||
<%= link_to "Chat", "https://wiki.kosmos.org/Services:Chat", class: "ks-text-link" %>
|
<%= link_to "Chat", "https://wiki.kosmos.org/Services:Chat", class: "ks-text-link" %>
|
||||||
|
|||||||
@@ -6,14 +6,15 @@
|
|||||||
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
<%= 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,
|
<%= f.email_field :email,
|
||||||
required: true, autofocus: true, autocomplete: "email",
|
required: true, autofocus: true, autocomplete: "email",
|
||||||
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email),
|
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email),
|
||||||
class: "w-full sm:w-4/5" %>
|
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 %>
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,17 @@
|
|||||||
<%= 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 a reset link", 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 %>
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,17 @@
|
|||||||
<%= 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 %>
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,12 @@
|
|||||||
|
|
||||||
<%= render MainSimpleComponent.new do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p class="mb-12">
|
||||||
Your financial contributions to the development and upkeep of Kosmos
|
Your financial contributions to the development and upkeep of Kosmos
|
||||||
software and services.
|
software and services.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<% 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">
|
||||||
@@ -36,7 +33,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>
|
<p class="text-gray-500">
|
||||||
No donations to show.
|
No donations to show.
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1 +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-key"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path></svg>
|
<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-key <%= custom_class %>"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"></path></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 373 B |
@@ -1 +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-link-2"><path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path><line x1="8" y1="12" x2="16" y2="12"></line></svg>
|
<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-link-2 <%= custom_class %>"><path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path><line x1="8" y1="12" x2="16" y2="12"></line></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 355 B After Width: | Height: | Size: 376 B |
@@ -1 +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-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
<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-link <%= custom_class %>"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 371 B After Width: | Height: | Size: 392 B |
@@ -1 +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-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
|
<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-settings <%= custom_class %>"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1011 B After Width: | Height: | Size: 1.0 KiB |
@@ -1 +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-shield"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
|
<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-shield <%= custom_class %>"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 279 B After Width: | Height: | Size: 300 B |
@@ -1 +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-zap"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
|
<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-zap <%= custom_class %>"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 303 B |
@@ -3,17 +3,12 @@
|
|||||||
<%= render MainSimpleComponent.new do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<section>
|
<section>
|
||||||
<% if @invitations_unused.any? %>
|
<% if @invitations_unused.any? %>
|
||||||
<p>
|
<p>
|
||||||
Invite your friends to a Kosmos account by sharing an invitation URL with them:
|
Invite your friends to a Kosmos account by sharing an invitation URL with them:
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<table class="mt-12">
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<% if @invitations_unused.any? %>
|
|
||||||
<table>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr>
|
||||||
<th>URL</th>
|
<th>URL</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -38,7 +33,7 @@
|
|||||||
<h3>Accepted Invitations</h3>
|
<h3>Accepted Invitations</h3>
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="text-left">
|
<tr>
|
||||||
<th class="hidden md:block">ID</th>
|
<th class="hidden md:block">ID</th>
|
||||||
<th>Accepted</th>
|
<th>Accepted</th>
|
||||||
<th>Invited user</th>
|
<th>Invited user</th>
|
||||||
|
|||||||
@@ -1,80 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Admin Panel | Kosmos Accounts</title>
|
|
||||||
<%= csrf_meta_tags %>
|
|
||||||
<%= csp_meta_tag %>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link href="https://assets.kosmos.org/fonts/open-sans/open-sans.css" rel="stylesheet">
|
|
||||||
<%= stylesheet_link_tag 'legacy', "data-turbo-track": "reload" %>
|
|
||||||
<%= stylesheet_link_tag 'application', "data-turbo-track": "reload" %>
|
|
||||||
<%= javascript_importmap_tags %>
|
|
||||||
</head>
|
|
||||||
<body id="admin-panel" class="bg-red-500">
|
|
||||||
<div class="">
|
|
||||||
<nav class="">
|
|
||||||
<div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
|
|
||||||
<div class="border-b border-gray-200/10">
|
|
||||||
<div class="flex items-center justify-between h-16 px-4 sm:px-0">
|
|
||||||
<div class="flex items-center">
|
|
||||||
<div class="ks-site-icon flex-shrink-0">
|
|
||||||
<%= render partial: "shared/icons/comet" %>
|
|
||||||
<!-- <img class="h-8 w-8" src="https://tailwindui.com/img/logos/workflow-mark-indigo-500.svg" alt="Workflow"> -->
|
|
||||||
</div>
|
|
||||||
<% if user_signed_in? && current_user.is_admin? %>
|
|
||||||
<div class="hidden md:block">
|
|
||||||
<div class="ml-10 flex items-baseline space-x-4">
|
|
||||||
<%= render partial: 'shared/admin_nav' %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<div class="hidden md:block">
|
|
||||||
<%= render partial: 'shared/header_account' %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Mobile menu, show/hide based on menu state. -->
|
|
||||||
<div class="border-b border-gray-700 md:hidden" id="mobile-menu">
|
|
||||||
<div class="pt-4 pb-3 border-t border-gray-700">
|
|
||||||
<div class="flex items-center px-5">
|
|
||||||
<div class="flex-shrink-0">
|
|
||||||
<img class="h-10 w-10 rounded-full" src="" alt="">
|
|
||||||
</div>
|
|
||||||
<div class="ml-3">
|
|
||||||
<div class="text-base font-medium leading-none text-white">Tom Cook</div>
|
|
||||||
<div class="text-sm font-medium leading-none text-gray-400">tom@example.com</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="ml-auto bg-gray-800 flex-shrink-0 p-1 text-gray-400 rounded-full hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white">
|
|
||||||
<span class="sr-only">View notifications</span>
|
|
||||||
<!-- Heroicon name: outline/bell -->
|
|
||||||
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="mt-3 px-2 space-y-1">
|
|
||||||
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700">Your Profile</a>
|
|
||||||
|
|
||||||
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700">Settings</a>
|
|
||||||
|
|
||||||
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700">Sign out</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<div class="fixed inset-0 px-4 py-6 pointer-events-none sm:px-6 sm:py-4 sm:items-start sm:justify-end">
|
|
||||||
<div class="flex flex-col items-end justify-center">
|
|
||||||
<% flash.each do |type, data| %>
|
|
||||||
<%= render NotificationComponent.new(type: type, data: data) %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<%= yield %>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,66 +1,90 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html class="h-full">
|
||||||
<head>
|
<head>
|
||||||
<title>Kosmos Accounts</title>
|
<title>Kosmos Accounts</title>
|
||||||
<%= csrf_meta_tags %>
|
<%= csrf_meta_tags %>
|
||||||
<%= csp_meta_tag %>
|
<%= csp_meta_tag %>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="https://assets.kosmos.org/fonts/open-sans/open-sans.css" rel="stylesheet">
|
<link href="https://assets.kosmos.org/fonts/open-sans/open-sans.css" rel="stylesheet">
|
||||||
<%= stylesheet_link_tag 'legacy', "data-turbo-track": "reload" %>
|
|
||||||
<%= stylesheet_link_tag 'application', "data-turbo-track": "reload" %>
|
<%= stylesheet_link_tag 'application', "data-turbo-track": "reload" %>
|
||||||
<%= javascript_importmap_tags %>
|
<%= javascript_importmap_tags %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body <%= @context.present? ? "id=#{@context}" : "" %> class="h-full <%= @context == :admin ? "bg-red-500" : "bg-sky-900" %>">
|
||||||
<div class="">
|
<div class="min-h-full">
|
||||||
<nav class="">
|
<nav data-controller="topbar">
|
||||||
<div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
|
<div class="max-w-6xl mx-auto sm:px-6 lg:px-8">
|
||||||
<div class="border-b border-gray-200/10">
|
<div class="border-b border-gray-200/10">
|
||||||
<div class="flex items-center justify-between h-16 px-4 sm:px-0">
|
<div class="flex items-center justify-between h-16 px-4 sm:px-0">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div class="ks-site-icon flex-shrink-0">
|
<div class="ks-site-icon flex-shrink-0">
|
||||||
<%= render partial: "shared/icons/comet" %>
|
<%= render partial: "shared/icons/comet", locals: { custom_class: "inline-block align-top w-auto h-7" } %>
|
||||||
<!-- <img class="h-8 w-8" src="https://tailwindui.com/img/logos/workflow-mark-indigo-500.svg" alt="Workflow"> -->
|
|
||||||
</div>
|
</div>
|
||||||
<% if user_signed_in? && current_user.confirmed? %>
|
<% if user_signed_in? && current_user.confirmed? %>
|
||||||
<div class="hidden md:block">
|
<div class="hidden md:block">
|
||||||
<div class="ml-10 flex items-baseline space-x-4">
|
<div class="ml-10 flex items-baseline space-x-4">
|
||||||
<%= render partial: 'shared/main_nav' %>
|
<% if @context == :admin %>
|
||||||
|
<%= render partial: 'shared/admin_nav' %>
|
||||||
|
<% else %>
|
||||||
|
<%= render partial: 'shared/main_nav' %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="hidden md:block">
|
<div class="hidden md:block">
|
||||||
<%= render partial: 'shared/header_account' %>
|
<% if user_signed_in? %>
|
||||||
|
<div class="flex items-baseline space-x-4 text-gray-200/80 text-sm font-medium">
|
||||||
|
<span>
|
||||||
|
<strong class="text-white font-normal"><%= current_user.address %></strong>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<%= link_to "Log out", destroy_user_session_path, class: 'underline hover:text-white' %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<div class="-mr-2 flex md:hidden">
|
||||||
|
<% if user_signed_in? && current_user.confirmed? %>
|
||||||
|
<button type="button" id="toggle-mobile-nav"
|
||||||
|
data-action="topbar#toggleMobileNav"
|
||||||
|
class="bg-gray-900/50 inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white" aria-controls="mobile-menu" aria-expanded="false">
|
||||||
|
<span class="sr-only">Open main menu</span>
|
||||||
|
<!-- Heroicon name: outline/menu -->
|
||||||
|
<svg data-topbar-target="iconMobileMenuOpen" class="block h-6 w-6"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||||
|
</svg>
|
||||||
|
<!-- Heroicon name: outline/x -->
|
||||||
|
<svg data-topbar-target="iconMobileMenuClose" class="hidden h-6 w-6"
|
||||||
|
xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile menu, show/hide based on menu state. -->
|
<div data-topbar-target="mobileMenu" class="border-b border-gray-200/10 md:hidden">
|
||||||
<div class="border-b border-gray-700 md:hidden" id="mobile-menu">
|
<% if user_signed_in? %>
|
||||||
<div class="pt-4 pb-3 border-t border-gray-700">
|
<div class="px-2 py-3 space-y-1 sm:px-3">
|
||||||
<div class="flex items-center px-5">
|
<% if @context == :admin %>
|
||||||
<div class="flex-shrink-0">
|
<%= render partial: 'shared/admin_nav' %>
|
||||||
<img class="h-10 w-10 rounded-full" src="" alt="">
|
<% else %>
|
||||||
</div>
|
<%= render partial: 'shared/main_nav' %>
|
||||||
<div class="ml-3">
|
<% end %>
|
||||||
<div class="text-base font-medium leading-none text-white">Tom Cook</div>
|
|
||||||
<div class="text-sm font-medium leading-none text-gray-400">tom@example.com</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="ml-auto bg-gray-800 flex-shrink-0 p-1 text-gray-400 rounded-full hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white">
|
|
||||||
<span class="sr-only">View notifications</span>
|
|
||||||
<!-- Heroicon name: outline/bell -->
|
|
||||||
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 px-2 space-y-1">
|
<div class="pt-4 pb-3 border-t border-gray-200/10">
|
||||||
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700">Your Profile</a>
|
<div class="px-5 text-base font-normal text-white">
|
||||||
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700">Settings</a>
|
<%= current_user.address %></strong>
|
||||||
<a href="#" class="block px-3 py-2 rounded-md text-base font-medium text-gray-400 hover:text-white hover:bg-gray-700">Sign out</a>
|
</div>
|
||||||
|
<div class="mt-3 px-2 space-y-1">
|
||||||
|
<%= link_to "Log out", destroy_user_session_path,
|
||||||
|
class: 'block px-3 py-2 rounded-md text-base font-medium text-gray-300 hover:text-white hover:bg-gray-900/30 active:text-white active:bg-gray-900/30' %>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Sign up | Kosmos Accounts</title>
|
|
||||||
<%= csrf_meta_tags %>
|
|
||||||
<%= csp_meta_tag %>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link href="https://assets.kosmos.org/fonts/open-sans/open-sans.css" rel="stylesheet">
|
|
||||||
<%= stylesheet_link_tag 'legacy', "data-turbo-track": "reload" %>
|
|
||||||
<%= stylesheet_link_tag 'application', "data-turbo-track": "reload" %>
|
|
||||||
<%= javascript_importmap_tags %>
|
|
||||||
</head>
|
|
||||||
<body class="layout-signup">
|
|
||||||
<div id="wrapper">
|
|
||||||
<header>
|
|
||||||
<h1>
|
|
||||||
<span class ="icon"><%= render partial: "shared/icons/comet" %></span>
|
|
||||||
<span class ="project-name">Kosmos</span>
|
|
||||||
<span class ="site-name">Sign Up</span>
|
|
||||||
</h1>
|
|
||||||
<% if user_signed_in? %>
|
|
||||||
<p class="current-user">
|
|
||||||
Signed in as <strong><%= current_user.cn %>@kosmos.org</strong>.
|
|
||||||
<%= link_to "Log out", destroy_user_session_path, method: :delete %>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<% flash.each do |type, msg| %>
|
|
||||||
<div class="flash-msg <%= type %>">
|
|
||||||
<p><%= msg %></p>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<%= yield %>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
<%= render HeaderComponent.new(title: "Account") %>
|
<%= render HeaderComponent.new(title: "Settings") %>
|
||||||
|
|
||||||
<%= render MainSimpleComponent.new do %>
|
<%= render MainWithSidenavComponent.new(sidenav_partial: 'shared/sidenav_settings') do %>
|
||||||
<section>
|
<section>
|
||||||
<h2>Security</h2>
|
<h3>Password</h3>
|
||||||
</section>
|
<p class="mb-12">Use the following button to request an email with a password reset link:</p>
|
||||||
|
|
||||||
<section>
|
|
||||||
<h3>Password change</h3>
|
|
||||||
<p>
|
<p>
|
||||||
<%= form_with(url: settings_reset_password_path, method: :post) do %>
|
<%= form_with(url: settings_reset_password_path, method: :post) do %>
|
||||||
<%= submit_tag("Send me a password reset link", class: 'btn-md btn-gray') %>
|
<%= submit_tag("Send me a password reset link", class: 'btn-md btn-gray w-full sm:w-auto') %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<% if user_signed_in? %>
|
|
||||||
<div class="flex items-baseline space-x-4 text-gray-200/80 text-sm font-medium">
|
|
||||||
<span>
|
|
||||||
Signed in as <strong class="text-white font-normal"><%= current_user.cn %>@kosmos.org</strong>
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<%= link_to "Log out", destroy_user_session_path, class: 'underline hover:text-white' %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
@@ -6,5 +6,5 @@
|
|||||||
class: main_nav_class(@current_section, :contributions) %>
|
class: main_nav_class(@current_section, :contributions) %>
|
||||||
<%= link_to "Wallet", wallet_path,
|
<%= link_to "Wallet", wallet_path,
|
||||||
class: main_nav_class(@current_section, :wallet) %>
|
class: main_nav_class(@current_section, :wallet) %>
|
||||||
<%= link_to "Account", security_path,
|
<%= link_to "Settings", security_path,
|
||||||
class: main_nav_class(@current_section, :security) %>
|
class: main_nav_class(@current_section, :security) %>
|
||||||
|
|||||||
10
app/views/shared/_sidenav_settings.html.erb
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<%= render SidenavLinkComponent.new(
|
||||||
|
name: "Account", path: "#", icon: "settings", disabled: true
|
||||||
|
) %>
|
||||||
|
<%= render SidenavLinkComponent.new(
|
||||||
|
name: "Password", path: security_path, icon: "key",
|
||||||
|
active: current_page?(security_path)
|
||||||
|
) %>
|
||||||
|
<%= render SidenavLinkComponent.new(
|
||||||
|
name: "Security", path: "#", icon: "shield", disabled: true
|
||||||
|
) %>
|
||||||
@@ -1 +1 @@
|
|||||||
<svg id="icon-comet" width="65.364" height="55.773" enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 65.364 55.773" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g id="layer1" transform="translate(28.868 20.259)" fill="#fff"><path id="path2" d="m22.81-9.2546-0.0137-0.0072c-0.0445-0.0196-0.0895-0.04052-0.13335-0.06078l-23.822-10.937s2.0034 9.219 2.914 11.778c0 0-27.292-8.1582-30.623-8.9354 1.0916 4.2618 20.006 40.848 20.006 40.848 3.8225 7.7608 12.677 12.083 21.912 12.083 12.949 0 23.446-10.497 23.446-23.446 6.6e-4 -9.4655-5.609-17.62-13.685-21.323z" fill="#fff" stroke-width=".65365"/></g></svg>
|
<svg id="icon-comet" class="<%= custom_class %>" width="65.364" height="55.773" enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 65.364 55.773" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g id="layer1" transform="translate(28.868 20.259)" fill="#fff"><path id="path2" d="m22.81-9.2546-0.0137-0.0072c-0.0445-0.0196-0.0895-0.04052-0.13335-0.06078l-23.822-10.937s2.0034 9.219 2.914 11.778c0 0-27.292-8.1582-30.623-8.9354 1.0916 4.2618 20.006 40.848 20.006 40.848 3.8225 7.7608 12.677 12.083 21.912 12.083 12.949 0 23.446-10.497 23.446-23.446 6.6e-4 -9.4655-5.609-17.62-13.685-21.323z" fill="#fff" stroke-width=".65365"/></g></svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 627 B After Width: | Height: | Size: 655 B |
@@ -1,6 +1,6 @@
|
|||||||
<%= render partial: "components/header", locals: { page_title: "403" } %>
|
<%= render HeaderCompactComponent.new(title: "403") %>
|
||||||
|
|
||||||
<%= render layout: "components/main_simple" do %>
|
<%= render MainCompactComponent.new do %>
|
||||||
<h2>Access forbidden</h2>
|
<h2>Access forbidden</h2>
|
||||||
<p>Sorry, you're not allowed to access this page.</p>
|
<p>Sorry, you're not allowed to access this page.</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<%= render partial: "components/header", locals: { page_title: "404" } %>
|
<%= render HeaderCompactComponent.new(title: "404") %>
|
||||||
|
|
||||||
<%= render layout: "components/main_simple" do %>
|
<%= render MainCompactComponent.new do %>
|
||||||
<h2>Not found</h2>
|
<h2>Not found</h2>
|
||||||
<p>Sorry, this page does not exist.</p>
|
<p>Sorry, this page does not exist.</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<%= render partial: "components/header", locals: { page_title: "401" } %>
|
<%= render HeaderCompactComponent.new(title: "401") %>
|
||||||
|
|
||||||
<%= render layout: "components/main_simple" do %>
|
<%= render MainCompactComponent.new do %>
|
||||||
<h2>Unauthorized</h2>
|
<h2>Unauthorized</h2>
|
||||||
<p>This page needs authorization to access.</p>
|
<p>This page needs authorization to access.</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
<h2>Welcome</h2>
|
<%= render HeaderCompactComponent.new(title: "Welcome") %>
|
||||||
<p>
|
|
||||||
Hey there! You were invited to sign up for a Kosmos account by
|
<%= render MainCompactComponent.new do %>
|
||||||
<strong><%= @invited_by_name %></strong>.
|
<p>
|
||||||
</p>
|
Hey there! You were invited to sign up for a Kosmos account by
|
||||||
<p>
|
<strong><%= @invited_by_name %></strong>.
|
||||||
This invitation can only be used once, and sign-up is currently only possible
|
</p>
|
||||||
by invitation. Seems like you have good friends!
|
<p>
|
||||||
</p>
|
This invitation can only be used once, and sign-up is currently only possible
|
||||||
<p class="mt-12">
|
by invitation. Seems like you have good friends!
|
||||||
<%= link_to "Get started", signup_steps_path(1), class: "btn btn-md btn-blue" %>
|
</p>
|
||||||
</p>
|
<p class="mt-12">
|
||||||
|
<%= link_to "Get started", signup_steps_path(1),
|
||||||
|
class: "btn-md btn-blue block w-full md:inline-block sm:w-auto" %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|||||||
@@ -1,54 +1,63 @@
|
|||||||
<% case @step %>
|
<%= render HeaderCompactComponent.new(title: "Signup") %>
|
||||||
<% when 1 %>
|
|
||||||
<h2>Choose a username</h2>
|
|
||||||
<%= form_for @user, :url => signup_validate_url do |f| %>
|
|
||||||
<p>
|
|
||||||
<%= f.label :cn, 'Username', class: 'hidden' %>
|
|
||||||
<%= f.text_field :cn, autofocus: true, autocomplete: "username",
|
|
||||||
class: 'text-xl' %>
|
|
||||||
<span class="text-xl ml-1">@</span>
|
|
||||||
<span class="text-xl">kosmos.org</span>
|
|
||||||
</p>
|
|
||||||
<% if @validation_error.present? %>
|
|
||||||
<p class="error-msg">Username <%= @validation_error %></p>
|
|
||||||
<% end %>
|
|
||||||
<p class="mt-12">
|
|
||||||
<%= f.submit "Continue", class: 'btn btn-md btn-blue' %>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% when 2 %>
|
<%= render MainCompactComponent.new do %>
|
||||||
<h2>What's your email?</h2>
|
<% case @step
|
||||||
<%= form_for @user, :url => signup_validate_url do |f| %>
|
when 1 %>
|
||||||
<p>
|
<h2>Choose a username</h2>
|
||||||
<%= f.label :email, 'Email address', class: 'hidden' %>
|
<%= form_for @user, :url => signup_validate_url do |f| %>
|
||||||
<%= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'text-xl' %>
|
<p>
|
||||||
</p>
|
<%= f.label :cn, 'Username', class: 'hidden' %>
|
||||||
<% if @validation_error.present? %>
|
<%= f.text_field :cn, autofocus: true, autocomplete: "username",
|
||||||
<p class="error-msg">Email <%= @validation_error %></p>
|
class: 'text-xl w-full md:w-3/5 mb-1' %>
|
||||||
|
<span class="text-base md:text-xl text-gray-500 ml-1">@</span>
|
||||||
|
<span class="text-base md:text-xl text-gray-500">kosmos.org</span>
|
||||||
|
</p>
|
||||||
|
<% if @validation_error.present? %>
|
||||||
|
<p class="error-msg">Username <%= @validation_error %></p>
|
||||||
|
<% end %>
|
||||||
|
<p class="mt-12">
|
||||||
|
<%= f.submit "Continue",
|
||||||
|
class: "btn-md btn-blue block w-full md:inline-block sm:w-auto" %>
|
||||||
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p class="mt-12">
|
|
||||||
<%= f.submit "Continue", class: 'btn btn-md btn-blue' %>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% when 3 %>
|
<% when 2 %>
|
||||||
<h2>Choose a password</h2>
|
<h2>What's your email?</h2>
|
||||||
|
<%= form_for @user, :url => signup_validate_url do |f| %>
|
||||||
<%= form_for @user, :url => signup_validate_url do |f| %>
|
<p>
|
||||||
<p>
|
<%= f.label :email, 'Email address', class: 'hidden' %>
|
||||||
<%= f.label :password, 'Password', class: 'hidden' %>
|
<%= f.email_field :email, autofocus: true, autocomplete: 'email',
|
||||||
<%= f.password_field :password, autofocus: true, class: 'text-xl' %>
|
class: 'text-xl w-full' %>
|
||||||
</p>
|
</p>
|
||||||
<% if @validation_error.present? %>
|
<% if @validation_error.present? %>
|
||||||
<p class="error-msg">Password <%= @validation_error %></p>
|
<p class="error-msg">Email <%= @validation_error %></p>
|
||||||
|
<% end %>
|
||||||
|
<p class="mt-12">
|
||||||
|
<%= f.submit "Continue",
|
||||||
|
class: "btn-md btn-blue block w-full md:inline-block sm:w-auto" %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<% when 3 %>
|
||||||
|
<h2>Choose a password</h2>
|
||||||
|
|
||||||
|
<%= form_for @user, :url => signup_validate_url do |f| %>
|
||||||
|
<p>
|
||||||
|
<%= f.label :password, 'Password', class: 'hidden' %>
|
||||||
|
<%= f.password_field :password, autofocus: true,
|
||||||
|
class: 'text-xl w-full' %>
|
||||||
|
</p>
|
||||||
|
<% if @validation_error.present? %>
|
||||||
|
<p class="error-msg">Password <%= @validation_error %></p>
|
||||||
|
<% end %>
|
||||||
|
<p class="mt-8 text-sm text-gray-500">
|
||||||
|
By clicking the button below, you accept our future Terms of Service
|
||||||
|
and Privacy Policy. Don't worry, they will be excellent!
|
||||||
|
</p>
|
||||||
|
<p class="mt-8">
|
||||||
|
<%= f.submit "Create account",
|
||||||
|
class: "btn-md btn-blue block w-full sm:inline-block sm:w-auto" %>
|
||||||
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p class="mt-8 text-sm text-gray-500">
|
|
||||||
By clicking the button below, you accept our future Terms of Service
|
|
||||||
and Privacy Policy. Don't worry, they will be excellent!
|
|
||||||
</p>
|
|
||||||
<p class="mt-8">
|
|
||||||
<%= f.submit "Create account", class: 'btn-md btn-blue' %>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
<%= render HeaderComponent.new(title: "Wallet") %>
|
<%= render HeaderComponent.new(title: "Wallet") %>
|
||||||
|
|
||||||
<%= render MainSimpleComponent.new do %>
|
<%= render MainSimpleComponent.new do %>
|
||||||
<section class="w-full grid grid-cols-1 md:grid-cols-12 md:mb-0">
|
<%= render WalletSummaryComponent.new(balance: @balance) %>
|
||||||
<div class="md:col-span-8">
|
|
||||||
<p>
|
<section>
|
||||||
Send and receive sats via the Bitcoin Lightning Network.
|
<div class="border-b border-gray-200">
|
||||||
</p>
|
<nav class="-mb-px flex" aria-label="Tabs">
|
||||||
</div>
|
<%= link_to "Info", wallet_path, class: "border-indigo-500 text-indigo-600 w-1/2 py-4 px-1 text-center border-b-2", "aria-current": "page" %>
|
||||||
<div class="md:col-span-4 mt-4 md:mt-0">
|
<%= link_to "Transactions", wallet_transactions_path, class: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 w-1/2 py-4 px-1 text-center border-b-2" %>
|
||||||
<p class="font-mono md:text-right mb-0 p-4 border border-gray-300 rounded-lg overflow-hidden">
|
</nav>
|
||||||
<% if @balance %>
|
|
||||||
<span class="text-xl"><%= number_with_delimiter @balance %> sats</span><br>
|
|
||||||
<span class="text-sm text-gray-500">Available balance</span>
|
|
||||||
<% else %>
|
|
||||||
<span class="text-xl">n/a sats</span><br>
|
|
||||||
<span class="text-sm text-gray-500">Balance unavailable</span>
|
|
||||||
<% end %>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -42,10 +34,10 @@
|
|||||||
code/URL:
|
code/URL:
|
||||||
</p>
|
</p>
|
||||||
<p class="my-6 text-center md:text-left">
|
<p class="my-6 text-center md:text-left">
|
||||||
<button id="copy-setup-code" class="btn-md btn-blue">Copy setup code/URL</button>
|
<button id="copy-setup-code" class="btn-md btn-blue w-full sm:w-auto">Copy setup code/URL</button>
|
||||||
<span class="mx-2 my-2 md:my-0 block md:inline">or</span>
|
<span class="mx-2 my-2 md:my-0 block md:inline">or</span>
|
||||||
<button id="show-setup-code" class="btn-md btn-blue">Show setup QR code</button>
|
<button id="show-setup-code" class="btn-md btn-blue w-full sm:w-auto">Show setup QR code</button>
|
||||||
<button id="hide-setup-code" class="btn-md btn-blue hidden">Hide setup QR code</button>
|
<button id="hide-setup-code" class="hidden btn-md btn-blue w-full sm:w-auto">Hide setup QR code</button>
|
||||||
</p>
|
</p>
|
||||||
<p id="setup-code" class="hidden my-10 w-full text-center">
|
<p id="setup-code" class="hidden my-10 w-full text-center">
|
||||||
<%= raw @svg %>
|
<%= raw @svg %>
|
||||||
|
|||||||
57
app/views/wallet/transactions.html.erb
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<%= render HeaderComponent.new(title: "Wallet") %>
|
||||||
|
|
||||||
|
<%= render MainSimpleComponent.new do %>
|
||||||
|
<%= render WalletSummaryComponent.new(balance: @balance) %>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<div class="border-b border-gray-200">
|
||||||
|
<nav class="-mb-px flex" aria-label="Tabs">
|
||||||
|
<%= link_to "Info", wallet_path, class: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 w-1/2 py-4 px-1 text-center border-b-2" %>
|
||||||
|
<%= link_to "Transactions", wallet_transactions_path, class: "border-indigo-500 text-indigo-600 w-1/2 py-4 px-1 text-center border-b-2", "aria-current": "page" %>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h3 class="hidden">Transactions</h3>
|
||||||
|
|
||||||
|
<% if @transactions.any? %>
|
||||||
|
<ul class="list-none">
|
||||||
|
<% @transactions.each do |tx| %>
|
||||||
|
<li class="py-4 md:py-4 grid gap-y-1 gap-x-2 grid-cols-4 border-b border-dotted border-gray-300">
|
||||||
|
<h3 class="col-span-2 md:col-span-3 mb-0">
|
||||||
|
<% if tx["type"] == "bitcoind_tx" %>
|
||||||
|
<span class="inline-block">
|
||||||
|
<%= render partial: "icons/link-2", locals: { custom_class: "text-emerald-500 h-4 w-4 mr-0.5" } %>
|
||||||
|
</span>
|
||||||
|
<% else %>
|
||||||
|
<span class="inline-block">
|
||||||
|
<%= render partial: "icons/zap", locals: { custom_class: "text-amber-500 h-4 w-4 mr-0.5" } %>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
<%= tx["title"] %>
|
||||||
|
</h3>
|
||||||
|
<p class="col-span-2 md:col-span-1 mb-0 text-right">
|
||||||
|
<span class="text-xl font-mono <%= tx["received"] ? "text-emerald-600" : "" %>">
|
||||||
|
<%= tx["received"] ? "+" : "" %><%= number_with_delimiter tx["amount_sats"] %>
|
||||||
|
<span class="hidden md:inline">sats</span>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p class="col-span-4 md:col-span-3 mb-0 text-gray-500">
|
||||||
|
<%= tx["description"].present? ? tx["description"] : raw("<span class='text-gray-400'>No memo</span>") %>
|
||||||
|
</p>
|
||||||
|
<p class="col-span-4 md:col-span-1 md:text-right mb-0">
|
||||||
|
<span class="col-span-2 md:col-span-1 text-sm text-gray-500">
|
||||||
|
<%= tx["datetime"].strftime("%B %e, %H:%M") %>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
<% else %>
|
||||||
|
<p class="text-gray-500">
|
||||||
|
No transactions yet. As soon as you start receiving sats, you will find some entries here.
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
</section>
|
||||||
|
<% end %>
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
<%= render MainCompactComponent.new do %>
|
<%= render MainCompactComponent.new do %>
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
You can close this window or tab now.
|
Please check your inbox!
|
||||||
|
</p>
|
||||||
|
<p class="text-center text-gray-500">
|
||||||
|
(You can close this window or tab now.)
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
<p>
|
|
||||||
<%=link_to "Sign up for a new account" %>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<%=link_to "Manage your existing account", new_user_session_path %>
|
|
||||||
</p>
|
|
||||||
@@ -20,6 +20,7 @@ Rails.application.routes.draw do
|
|||||||
resources :donations
|
resources :donations
|
||||||
|
|
||||||
get 'wallet', to: 'wallet#index'
|
get 'wallet', to: 'wallet#index'
|
||||||
|
get 'wallet/transactions', to: 'wallet#transactions'
|
||||||
|
|
||||||
get 'lnurlpay/:address', to: 'lnurlpay#index', constraints: { address: /[^\/]+/}
|
get 'lnurlpay/:address', to: 'lnurlpay#index', constraints: { address: /[^\/]+/}
|
||||||
get 'lnurlpay/:address/invoice', to: 'lnurlpay#invoice', constraints: { address: /[^\/]+/}
|
get 'lnurlpay/:address/invoice', to: 'lnurlpay#invoice', constraints: { address: /[^\/]+/}
|
||||||
|
|||||||
@@ -9,13 +9,11 @@
|
|||||||
"postcss-import": "^14.0.2",
|
"postcss-import": "^14.0.2",
|
||||||
"postcss-nested": "^5.0.6",
|
"postcss-nested": "^5.0.6",
|
||||||
"postcss-preset-env": "^7.3.1",
|
"postcss-preset-env": "^7.3.1",
|
||||||
"sass": "^1.49.7",
|
|
||||||
"tailwindcss": "^3.0.22"
|
"tailwindcss": "^3.0.22"
|
||||||
},
|
},
|
||||||
"version": "0.2.0",
|
"version": "0.4.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:css:sass": "sass ./app/assets/stylesheets/legacy.sass.scss ./app/assets/builds/legacy.css --no-source-map --load-path=node_modules",
|
|
||||||
"build:css:tailwind": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css",
|
"build:css:tailwind": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css",
|
||||||
"build:css": "yarn run build:css:sass && yarn run build:css:tailwind"
|
"build:css": "yarn run build:css:tailwind"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
RSpec.describe HeaderCompactComponent, type: :component do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
|
|
||||||
# it "renders something useful" do
|
|
||||||
# expect(
|
|
||||||
# render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html
|
|
||||||
# ).to include(
|
|
||||||
# "Hello, components!"
|
|
||||||
# )
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
RSpec.describe HeaderComponent, type: :component do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
|
|
||||||
# it "renders something useful" do
|
|
||||||
# expect(
|
|
||||||
# render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html
|
|
||||||
# ).to include(
|
|
||||||
# "Hello, components!"
|
|
||||||
# )
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
RSpec.describe MainCompactComponent, type: :component do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
|
|
||||||
# it "renders something useful" do
|
|
||||||
# expect(
|
|
||||||
# render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html
|
|
||||||
# ).to include(
|
|
||||||
# "Hello, components!"
|
|
||||||
# )
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
RSpec.describe MainSimpleComponent, type: :component do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
|
|
||||||
# it "renders something useful" do
|
|
||||||
# expect(
|
|
||||||
# render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html
|
|
||||||
# ).to include(
|
|
||||||
# "Hello, components!"
|
|
||||||
# )
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
RSpec.describe NotificationComponent, type: :component do
|
|
||||||
pending "add some examples to (or delete) #{__FILE__}"
|
|
||||||
|
|
||||||
# it "renders something useful" do
|
|
||||||
# expect(
|
|
||||||
# render_inline(described_class.new(attr: "value")) { "Hello, components!" }.css("p").to_html
|
|
||||||
# ).to include(
|
|
||||||
# "Hello, components!"
|
|
||||||
# )
|
|
||||||
# end
|
|
||||||
end
|
|
||||||
11
spec/components/wallet_summary_component_spec.rb
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
RSpec.describe WalletSummaryComponent, type: :component do
|
||||||
|
it "renders the balance as a human-readable number" do
|
||||||
|
expect(
|
||||||
|
render_inline(described_class.new(balance: 2301000)) {}.css("section").to_html
|
||||||
|
).to include(
|
||||||
|
"2,301,000 sats"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -10,6 +10,8 @@ require 'capybara'
|
|||||||
require 'devise'
|
require 'devise'
|
||||||
require 'support/controller_macros'
|
require 'support/controller_macros'
|
||||||
require 'support/database_cleaner'
|
require 'support/database_cleaner'
|
||||||
|
require "view_component/test_helpers"
|
||||||
|
require "capybara/rspec"
|
||||||
|
|
||||||
# Requires supporting ruby files with custom matchers and macros, etc, in
|
# Requires supporting ruby files with custom matchers and macros, etc, in
|
||||||
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
|
||||||
@@ -70,5 +72,8 @@ RSpec.configure do |config|
|
|||||||
config.include Warden::Test::Helpers
|
config.include Warden::Test::Helpers
|
||||||
config.include FactoryBot::Syntax::Methods
|
config.include FactoryBot::Syntax::Methods
|
||||||
config.include ActiveJob::TestHelper, type: :job
|
config.include ActiveJob::TestHelper, type: :job
|
||||||
|
config.include ViewComponent::TestHelpers, type: :component
|
||||||
|
config.include Capybara::RSpecMatchers, type: :component
|
||||||
|
|
||||||
config.extend ControllerMacros, :type => :controller
|
config.extend ControllerMacros, :type => :controller
|
||||||
end
|
end
|
||||||
|
|||||||
18
yarn.lock
@@ -202,7 +202,7 @@ chalk@^4.1.2:
|
|||||||
ansi-styles "^4.1.0"
|
ansi-styles "^4.1.0"
|
||||||
supports-color "^7.1.0"
|
supports-color "^7.1.0"
|
||||||
|
|
||||||
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
|
chokidar@^3.5.3:
|
||||||
version "3.5.3"
|
version "3.5.3"
|
||||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
|
||||||
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
|
||||||
@@ -398,11 +398,6 @@ has@^1.0.3:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind "^1.1.1"
|
function-bind "^1.1.1"
|
||||||
|
|
||||||
immutable@^4.0.0:
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
|
|
||||||
integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
|
|
||||||
|
|
||||||
import-fresh@^3.2.1:
|
import-fresh@^3.2.1:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
|
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
|
||||||
@@ -890,16 +885,7 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
sass@^1.49.7:
|
source-map-js@^1.0.2:
|
||||||
version "1.49.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.7.tgz#22a86a50552b9b11f71404dfad1b9ff44c6b0c49"
|
|
||||||
integrity sha512-13dml55EMIR2rS4d/RDHHP0sXMY3+30e1TKsyXaSz3iLWVoDWEoboY8WzJd5JMnxrRHffKO3wq2mpJ0jxRJiEQ==
|
|
||||||
dependencies:
|
|
||||||
chokidar ">=3.0.0 <4.0.0"
|
|
||||||
immutable "^4.0.0"
|
|
||||||
source-map-js ">=0.6.2 <2.0.0"
|
|
||||||
|
|
||||||
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2:
|
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz"
|
||||||
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
|
||||||
|
|||||||