23 Commits

Author SHA1 Message Date
4e0d4bf86d 0.4.0
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-17 14:59:07 -06:00
333bcbfe7e Remove Sass dependency
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-17 13:30:10 -06:00
875af6d14c Merge pull request 'Add transaction history view to wallet' (#66) from feature/wallet_history into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #66
2022-03-17 19:28:58 +00:00
8f87a03060 Merge pull request 'Finish Tailwind migration' (#67) from chore/finish_tailwind_migration into feature/wallet_history
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #67
2022-03-17 19:27:52 +00:00
7838fe5f34 Remove legacy CSS build from task
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-03-17 13:26:36 -06:00
512798d122 Port last remaining styles from legacy to Tailwind
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2022-03-17 13:24:13 -06:00
384c28aaaa Build PRs for all branches
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-03-17 13:06:33 -06:00
8e5d6dabdc Port most remaining legacy styles to Tailwind
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-03-11 10:15:09 -06:00
ade9261c2c Remove obsolete CSS 2022-03-11 09:52:11 -06:00
bd2a161306 Add tab menu to wallet pages
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-03-02 19:18:28 -06:00
78c243c985 Add wallet transactions
All checks were successful
continuous-integration/drone/push Build is passing
2022-03-02 18:43:22 -06:00
cf62bfc5c2 WIP Add wallet transactions route, view
All checks were successful
continuous-integration/drone/push Build is passing
Adds a new component for the wallet summary as well, and makes the
component tests work with RSpec.
2022-03-02 15:31:39 -06:00
10f179a095 Port shared CSS for tables to Tailwind 2022-03-02 15:30:50 -06:00
f7d0a0ba85 0.3.0
Some checks failed
continuous-integration/drone/push Build is failing
2022-03-02 10:41:54 -06:00
83e4dfa18f Merge pull request 'Allow comments for LNURL-PAY invoices' (#65) from feature/lnurlp_memos into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #65
2022-03-02 14:13:40 +00:00
4c70600d1f Re-add description_hash
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Necessary for lnurlpay-enabled wallets
2022-03-01 13:53:22 -06:00
9903683536 Remove desc hash, always add memo to invoices
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-03-01 13:26:44 -06:00
4c51b9c966 Allow comments for LNURL-PAY invoices
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Allows senders to add a short message to payments, which will be stored
as invoice memo by LND/LndHub.
2022-03-01 11:20:23 -06:00
6790e8383d Merge pull request 'Redesign layout and navigation' (#64) from feature/new_layout into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #64
2022-02-26 15:45:12 +00:00
ed886d8182 Introduce sidebar nav components, settings nav
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-24 18:56:07 -06:00
ca940ec35d Consolidate some styles
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-24 17:24:59 -06:00
5751c0338a Nicer buttons on small screens
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-24 13:59:51 -06:00
b9ec363f36 Remove caveat from README 2022-02-24 13:59:15 -06:00
51 changed files with 349 additions and 342 deletions

View File

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

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

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

View File

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

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

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

View File

@@ -1,2 +0,0 @@
@import "legacy/layout";
@import "legacy/main_nav";

View File

@@ -1,122 +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 {
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;
}
}
}
}
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;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

@@ -0,0 +1,8 @@
# frozen_string_literal: true
class WalletSummaryComponent < ViewComponent::Base
def initialize(balance:)
@balance = balance
end
end

View File

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

View File

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

View File

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

View File

@@ -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,10 +19,10 @@
<% @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>

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@
</p> </p>
<p class="mt-8"> <p class="mt-8">
<%= f.submit "Resend confirmation link", <%= f.submit "Resend confirmation link",
class: 'btn-md btn-blue w-full md:w-auto' %> class: 'btn-md btn-blue w-full sm:w-auto' %>
</p> </p>
<% end %> <% end %>

View File

@@ -17,7 +17,7 @@
class: "w-full md:w-3/5"%> 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 w-full md:w-auto' %> <%= f.submit "Send me a reset link", class: 'btn-md btn-blue w-full sm:w-auto' %>
</p> </p>
<% end %> <% end %>

View File

@@ -15,7 +15,7 @@
class: "w-full md:w-3/5"%> 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 w-full md:w-auto' %> <%= f.submit "Log in", class: 'btn-md btn-blue w-full sm:w-auto' %>
</p> </p>
<% end %> <% end %>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,6 @@
<%= 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>
@@ -18,7 +17,7 @@
<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" } %>
</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">

View File

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

View File

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

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

View File

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

View File

@@ -10,6 +10,7 @@
by invitation. Seems like you have good friends! by invitation. Seems like you have good friends!
</p> </p>
<p class="mt-12"> <p class="mt-12">
<%= link_to "Get started", signup_steps_path(1), class: "btn btn-md btn-blue" %> <%= link_to "Get started", signup_steps_path(1),
class: "btn-md btn-blue block w-full md:inline-block sm:w-auto" %>
</p> </p>
<% end %> <% end %>

View File

@@ -1,8 +1,8 @@
<%= render HeaderCompactComponent.new(title: "Signup") %> <%= render HeaderCompactComponent.new(title: "Signup") %>
<%= render MainCompactComponent.new do %> <%= render MainCompactComponent.new do %>
<% case @step %> <% case @step
<% when 1 %> when 1 %>
<h2>Choose a username</h2> <h2>Choose a username</h2>
<%= form_for @user, :url => signup_validate_url do |f| %> <%= form_for @user, :url => signup_validate_url do |f| %>
<p> <p>
@@ -16,7 +16,8 @@
<p class="error-msg">Username <%= @validation_error %></p> <p class="error-msg">Username <%= @validation_error %></p>
<% end %> <% end %>
<p class="mt-12"> <p class="mt-12">
<%= f.submit "Continue", class: 'btn btn-md btn-blue' %> <%= f.submit "Continue",
class: "btn-md btn-blue block w-full md:inline-block sm:w-auto" %>
</p> </p>
<% end %> <% end %>
@@ -32,7 +33,8 @@
<p class="error-msg">Email <%= @validation_error %></p> <p class="error-msg">Email <%= @validation_error %></p>
<% end %> <% end %>
<p class="mt-12"> <p class="mt-12">
<%= f.submit "Continue", class: 'btn btn-md btn-blue' %> <%= f.submit "Continue",
class: "btn-md btn-blue block w-full md:inline-block sm:w-auto" %>
</p> </p>
<% end %> <% end %>
@@ -53,7 +55,8 @@
and Privacy Policy. Don't worry, they will be excellent! and Privacy Policy. Don't worry, they will be excellent!
</p> </p>
<p class="mt-8"> <p class="mt-8">
<%= f.submit "Create account", class: 'btn-md btn-blue' %> <%= f.submit "Create account",
class: "btn-md btn-blue block w-full sm:inline-block sm:w-auto" %>
</p> </p>
<% end %> <% end %>
<% end %> <% end %>

View File

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

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

View File

@@ -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: /[^\/]+/}

View File

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

View 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

View File

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

View File

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