18 Commits

Author SHA1 Message Date
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
417768a30c Fix specs, markup
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-23 18:27:33 -06:00
9824dcd2c6 Remove unused specs
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 18:17:43 -06:00
5a784b5fa6 Improve devise views
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 18:16:14 -06:00
f36f6866a7 Port signup to new layout
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 18:07:54 -06:00
1fecfe57de Fix status views 2022-02-23 17:50:16 -06:00
3165714957 Implement proper mobile navigation
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 14:16:51 -06:00
4ccf43cf4a Layout classes 2022-02-23 12:13:14 -06:00
c0e79918ea Fix confirm dialog missing
All checks were successful
continuous-integration/drone/push Build is passing
2022-02-21 11:20:58 -06:00
48 changed files with 319 additions and 377 deletions

View File

@@ -45,11 +45,6 @@ manual LDIF imports etc. (or provide a staging instance)
* [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
* [RSpec](https://rspec.info/documentation/)

View File

@@ -18,4 +18,12 @@
h3 {
@apply text-xl mb-6;
}
main section {
@apply pt-8 sm:pt-12;
}
main section:first-of-type {
@apply pt-0;
}
}

View File

@@ -1,6 +1,6 @@
@layer components {
.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;
}

View File

@@ -8,7 +8,7 @@ body {
background-attachment: fixed;
}
body#admin-panel {
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;
@@ -67,20 +67,6 @@ body#admin-panel {
}
}
.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;
@@ -99,10 +85,6 @@ main {
}
}
section {
margin-bottom: 3rem;
}
table {
width: 100%;

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">
<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 %>
</div>
</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">
<div class="bg-white rounded-lg shadow px-6 py-12 sm:px-12">
<main class="w-full max-w-6xl mx-auto pb-12 px-4 md:px-6 lg:px-8">
<div class="bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
<%= content %>
</div>
</main>

View File

@@ -0,0 +1,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

@@ -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-notification-action-url="<%= @data.dig(:action, :url) %>"
data-notification-action-method="<%= @data.dig(:action, :method) %>"

View File

@@ -0,0 +1,4 @@
<%= link_to @path, class: @link_class do %>
<%= render partial: "icons/#{@icon}", locals: { custom_class: @icon_class } %>
<span class="truncate"><%= @name %></span>
<% end %>

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
class SidenavLinkComponent < ViewComponent::Base
def initialize(name:, path:, icon:, active: false, disabled: false)
@name = name
@path = path
@icon = icon
@active = active
@disabled = disabled
@link_class = class_names_link(path)
@icon_class = class_names_icon(path)
end
def class_names_link(path)
if @active
"bg-teal-50 border-teal-500 text-teal-700 hover:bg-teal-50 hover:text-teal-700 group border-l-4 px-4 py-2 flex items-center text-base font-medium"
elsif @disabled
"border-transparent text-gray-400 hover:bg-gray-50 group border-l-4 px-4 py-2 flex items-center text-base font-medium"
else
"border-transparent text-gray-900 hover:bg-gray-50 hover:text-gray-900 group border-l-4 px-4 py-2 flex items-center text-base font-medium"
end
end
def class_names_icon(path)
if @active
"text-teal-500 group-hover:text-teal-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
elsif @disabled
"text-gray-300 group-hover:text-gray-300 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
else
"text-gray-400 group-hover:text-gray-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
end
end
end

View File

@@ -2,7 +2,10 @@ class Admin::BaseController < ApplicationController
before_action :authenticate_user!
before_action :authorize_admin
before_action :set_context
layout "admin"
def set_context
@context = :admin
end
end

View File

@@ -2,8 +2,6 @@ class InvitationsController < ApplicationController
before_action :require_user_signed_in, except: ["show"]
before_action :require_user_signed_out, only: ["show"]
layout "signup", only: ["show"]
# GET /invitations
def index
@invitations_unused = current_user.invitations.unused

View File

@@ -3,6 +3,7 @@ class LnurlpayController < ApplicationController
MIN_SATS = 100
MAX_SATS = 1_000_000
MAX_COMMENT_CHARS = 100
def index
render json: {
@@ -12,22 +13,32 @@ class LnurlpayController < ApplicationController
maxSendable: MAX_SATS * 1000, # msat
minSendable: MIN_SATS * 1000, # msat
metadata: metadata(@user.address),
commentAllowed: 0
commentAllowed: MAX_COMMENT_CHARS
}
end
def invoice
amount = params[:amount].to_i / 1000 # msats
address = params[:address]
comment = params[:comment] || ""
if !valid_amount?(amount)
render json: { status: "ERROR", reason: "Invalid amount" }
return
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({
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: {
@@ -57,4 +68,8 @@ class LnurlpayController < ApplicationController
amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS
end
def valid_comment?(comment)
comment.length <= MAX_COMMENT_CHARS
end
end

View File

@@ -3,8 +3,7 @@ class SignupController < ApplicationController
before_action :require_invitation
before_action :set_invitation
before_action :set_new_user, only: ["steps", "validate"]
layout "signup"
before_action :set_context
def index
@invited_by_name = @invitation.user.address
@@ -105,4 +104,8 @@ class SignupController < ApplicationController
invitation: @invitation
)
end
def set_context
@context = :signup
end
end

View File

@@ -5,9 +5,10 @@ module ApplicationHelper
def main_nav_class(current_section, link_to_section)
if current_section == link_to_section
"bg-gray-900/50 text-white px-3 py-2 rounded-md 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
"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

View File

@@ -0,0 +1,31 @@
import { Controller } from "@hotwired/stimulus"
function show (element) {
element.classList.add('block');
element.classList.remove('hidden');
}
function hide (element) {
element.classList.remove('block');
element.classList.add('hidden');
}
export default class extends Controller {
static targets = [ 'mobileMenu', 'iconMobileMenuOpen', 'iconMobileMenuClose' ];
connect() {
this.mobileMenuTarget.classList.add('hidden');
}
toggleMobileNav() {
if (this.mobileMenuTarget.classList.contains('hidden')) {
show(this.mobileMenuTarget);
show(this.iconMobileMenuCloseTarget);
hide(this.iconMobileMenuOpenTarget);
} else {
hide(this.mobileMenuTarget);
hide(this.iconMobileMenuCloseTarget);
show(this.iconMobileMenuOpenTarget);
}
}
}

View File

@@ -49,6 +49,7 @@ class Lndhub
def addinvoice(payload)
invoice = post "addinvoice", {
amt: payload[:amount],
memo: payload[:memo],
description_hash: payload[:description_hash]
}

View File

@@ -27,7 +27,7 @@
<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 '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>
<% end %>
</tbody>

View File

@@ -6,14 +6,15 @@
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<p>
<%= f.label :email, 'Email address', class: 'block mb-1' %>
<%= f.label :email, 'Email address', class: 'block mb-1 w-full' %>
<%= f.email_field :email,
required: true, autofocus: true, autocomplete: "email",
value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email),
class: "w-full sm:w-4/5" %>
class: "w-full" %>
</p>
<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>
<% end %>

View File

@@ -7,14 +7,17 @@
<%= render "devise/shared/error_messages", resource: resource %>
<p>
<%= 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>
<%= 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 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>
<% end %>

View File

@@ -5,14 +5,17 @@
<%= render "devise/shared/error_messages", resource: resource %>
<p>
<%= 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>
<%= 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 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>
<% end %>

View File

@@ -2,15 +2,12 @@
<%= render MainSimpleComponent.new do %>
<section>
<p>
<p class="mb-12">
Your financial contributions to the development and upkeep of Kosmos
software and services.
</p>
</section>
<section>
<% if @donations.any? %>
<ul class="donations list-none">
<ul class="list-none">
<% @donations.each do |donation| %>
<li class="mb-8 grid gap-y-2 gap-x-8 grid-cols-2 items-center">
<h3 class="mb-0">
@@ -36,7 +33,7 @@
<% end %>
</ul>
<% else %>
<p>
<p class="text-gray-500">
No donations to show.
</p>
<% 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-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

@@ -3,15 +3,10 @@
<%= render MainSimpleComponent.new do %>
<section>
<% if @invitations_unused.any? %>
<p>
Invite your friends to a Kosmos account by sharing an invitation URL with them:
</p>
<% end %>
</section>
<section>
<% if @invitations_unused.any? %>
<table>
<p>
Invite your friends to a Kosmos account by sharing an invitation URL with them:
</p>
<table class="mt-12">
<thead>
<tr class="text-left">
<th>URL</th>

View File

@@ -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&#45;8 w&#45;8" src="https://tailwindui.com/img/logos/workflow&#45;mark&#45;indigo&#45;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>

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html class="h-full">
<head>
<title>Kosmos Accounts</title>
<%= csrf_meta_tags %>
@@ -10,57 +10,82 @@
<%= stylesheet_link_tag 'application', "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>
<body>
<div class="">
<nav class="">
<body <%= @context.present? ? "id=#{@context}" : "" %> class="h-full <%= @context == :admin ? "bg-red-500" : "bg-sky-900" %>">
<div class="min-h-full">
<nav data-controller="topbar">
<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&#45;8 w&#45;8" src="https://tailwindui.com/img/logos/workflow&#45;mark&#45;indigo&#45;500.svg" alt="Workflow"> -->
</div>
<% if user_signed_in? && current_user.confirmed? %>
<div class="hidden md:block">
<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>
<% end %>
</div>
<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>
<!-- 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 data-topbar-target="mobileMenu" class="border-b border-gray-200/10 md:hidden">
<% if user_signed_in? %>
<div class="px-2 py-3 space-y-1 sm:px-3">
<% if @context == :admin %>
<%= render partial: 'shared/admin_nav' %>
<% else %>
<%= render partial: 'shared/main_nav' %>
<% end %>
</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 class="pt-4 pb-3 border-t border-gray-200/10">
<div class="px-5 text-base font-normal text-white">
<%= current_user.address %></strong>
</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>
<% end %>
</div>
</nav>

View File

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

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>
<h2>Security</h2>
</section>
<section>
<h3>Password change</h3>
<h3>Password</h3>
<p class="mb-12">Use the following button to request an email with a password reset link:</p>
<p>
<%= 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 %>
</p>
</section>

View File

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

View File

@@ -6,5 +6,5 @@
class: main_nav_class(@current_section, :contributions) %>
<%= link_to "Wallet", wallet_path,
class: main_nav_class(@current_section, :wallet) %>
<%= link_to "Account", security_path,
<%= link_to "Settings", security_path,
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,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>
<p>Sorry, you're not allowed to access this page.</p>
<% end %>

View File

@@ -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>
<p>Sorry, this page does not exist.</p>
<% end %>

View File

@@ -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>
<p>This page needs authorization to access.</p>
<% end %>

View File

@@ -1,12 +1,16 @@
<h2>Welcome</h2>
<p>
Hey there! You were invited to sign up for a Kosmos account by
<strong><%= @invited_by_name %></strong>.
</p>
<p>
This invitation can only be used once, and sign-up is currently only possible
by invitation. Seems like you have good friends!
</p>
<p class="mt-12">
<%= link_to "Get started", signup_steps_path(1), class: "btn btn-md btn-blue" %>
</p>
<%= render HeaderCompactComponent.new(title: "Welcome") %>
<%= render MainCompactComponent.new do %>
<p>
Hey there! You were invited to sign up for a Kosmos account by
<strong><%= @invited_by_name %></strong>.
</p>
<p>
This invitation can only be used once, and sign-up is currently only possible
by invitation. Seems like you have good friends!
</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 %>

View File

@@ -1,54 +1,63 @@
<% case @step %>
<% 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 %>
<%= render HeaderCompactComponent.new(title: "Signup") %>
<% when 2 %>
<h2>What's your email?</h2>
<%= form_for @user, :url => signup_validate_url do |f| %>
<p>
<%= f.label :email, 'Email address', class: 'hidden' %>
<%= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'text-xl' %>
</p>
<% if @validation_error.present? %>
<p class="error-msg">Email <%= @validation_error %></p>
<%= render MainCompactComponent.new do %>
<% case @step
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 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 %>
<p class="mt-12">
<%= f.submit "Continue", class: 'btn btn-md btn-blue' %>
</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' %>
</p>
<% if @validation_error.present? %>
<p class="error-msg">Password <%= @validation_error %></p>
<% when 2 %>
<h2>What's your email?</h2>
<%= form_for @user, :url => signup_validate_url do |f| %>
<p>
<%= f.label :email, 'Email address', class: 'hidden' %>
<%= f.email_field :email, autofocus: true, autocomplete: 'email',
class: 'text-xl w-full' %>
</p>
<% if @validation_error.present? %>
<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 %>
<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 %>

View File

@@ -42,10 +42,10 @@
code/URL:
</p>
<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>
<button id="show-setup-code" class="btn-md btn-blue">Show setup QR code</button>
<button id="hide-setup-code" class="btn-md btn-blue hidden">Hide 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="hidden btn-md btn-blue w-full sm:w-auto">Hide setup QR code</button>
</p>
<p id="setup-code" class="hidden my-10 w-full text-center">
<%= raw @svg %>

View File

@@ -2,6 +2,9 @@
<%= render MainCompactComponent.new do %>
<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>
<% end %>

View File

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

View File

@@ -12,7 +12,7 @@
"sass": "^1.49.7",
"tailwindcss": "^3.0.22"
},
"version": "0.2.0",
"version": "0.3.0",
"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",

View File

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

View File

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

View File

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

View File

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

View File

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