master -> develop (#20)

* Squash merge develop into master

* feat: add automated production release workflow

* feat: add Gitflow workflow for syncing branches

* ci: update workflow runner to latest ubuntu version

* feat: enable buf.build publishing on master and develop branches

---------

Co-authored-by: Prad Nukala <prad@sonr.io>
This commit is contained in:
github-actions[bot] 2024-09-23 12:39:59 -04:00 committed by GitHub
parent 7b0693ef67
commit 228adb7f93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
146 changed files with 16786 additions and 123 deletions

50
.air.toml Normal file
View File

@ -0,0 +1,50 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
delay = 1000
cmd = "devbox run build:motr"
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = true
follow_symlink = false
full_bin = "bunx wrangler -c ./cmd/motr/wrangler.toml dev"
include_dir = ["cmd/dwn", "cmd/motr", "internal", "models", "pkl"]
include_ext = ["go", "templ", "html", "pkl", "js", "mjs"]
include_file = [
"wrangler.toml",
"Dockerfile",
".goreleaser.yaml",
"go.mod",
"devbox.json",
".air.toml",
]
kill_delay = "2s"
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
pre_cmd = ["templ generate"]
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_error = false
[color]
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = true
time = true
[misc]
clean_on_exit = true
[screen]
clear_on_rebuild = true
keep_scroll = true

View File

@ -1,6 +1,9 @@
name: Publish to buf.build/didao/sonr
on:
push:
branches:
- master
- develop
permissions:
contents: write

View File

@ -1,45 +1,24 @@
name: Sync Branches
name: Gitflow Sync
on:
# To create pull requests.
push:
tags:
- "*"
# To merge pull requests if not possible during the push run. Remove if `auto-merge` is `false`.
pull_request_review:
check_run:
types: [completed]
permissions:
contents: write
contents: read
pull-requests: write
jobs:
sync-branches:
build:
name: Gitflow
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: Logerfo/gitflow-action@0.0.5
with:
fetch-depth: 0
- name: Check if tag is on develop or master
id: check-branch
run: |
if git branch -r --contains ${{ github.ref }} | grep -q 'origin/develop\|origin/master'; then
echo "SYNC_NEEDED=true" >> $GITHUB_OUTPUT
else
echo "SYNC_NEEDED=false" >> $GITHUB_OUTPUT
fi
- name: Sync develop to master
if: steps.check-branch.outputs.SYNC_NEEDED == 'true'
uses: devmasx/merge-branch@master
with:
type: now
from_branch: develop
target_branch: master
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Sync master back to develop
if: steps.check-branch.outputs.SYNC_NEEDED == 'true'
uses: devmasx/merge-branch@master
with:
type: now
from_branch: master
target_branch: develop
github_token: ${{ secrets.GITHUB_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }} # The `GITHUB_TOKEN` secret.
dev: develop
master: master
release: release

View File

@ -18,12 +18,14 @@ import (
var (
md_GenesisState protoreflect.MessageDescriptor
fd_GenesisState_params protoreflect.FieldDescriptor
fd_GenesisState_global_integrity protoreflect.FieldDescriptor
)
func init() {
file_did_v1_genesis_proto_init()
md_GenesisState = File_did_v1_genesis_proto.Messages().ByName("GenesisState")
fd_GenesisState_params = md_GenesisState.Fields().ByName("params")
fd_GenesisState_global_integrity = md_GenesisState.Fields().ByName("global_integrity")
}
var _ protoreflect.Message = (*fastReflection_GenesisState)(nil)
@ -97,6 +99,12 @@ func (x *fastReflection_GenesisState) Range(f func(protoreflect.FieldDescriptor,
return
}
}
if x.GlobalIntegrity != nil {
value := protoreflect.ValueOfMessage(x.GlobalIntegrity.ProtoReflect())
if !f(fd_GenesisState_global_integrity, value) {
return
}
}
}
// Has reports whether a field is populated.
@ -114,6 +122,8 @@ func (x *fastReflection_GenesisState) Has(fd protoreflect.FieldDescriptor) bool
switch fd.FullName() {
case "did.v1.GenesisState.params":
return x.Params != nil
case "did.v1.GenesisState.global_integrity":
return x.GlobalIntegrity != nil
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GenesisState"))
@ -132,6 +142,8 @@ func (x *fastReflection_GenesisState) Clear(fd protoreflect.FieldDescriptor) {
switch fd.FullName() {
case "did.v1.GenesisState.params":
x.Params = nil
case "did.v1.GenesisState.global_integrity":
x.GlobalIntegrity = nil
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GenesisState"))
@ -151,6 +163,9 @@ func (x *fastReflection_GenesisState) Get(descriptor protoreflect.FieldDescripto
case "did.v1.GenesisState.params":
value := x.Params
return protoreflect.ValueOfMessage(value.ProtoReflect())
case "did.v1.GenesisState.global_integrity":
value := x.GlobalIntegrity
return protoreflect.ValueOfMessage(value.ProtoReflect())
default:
if descriptor.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GenesisState"))
@ -173,6 +188,8 @@ func (x *fastReflection_GenesisState) Set(fd protoreflect.FieldDescriptor, value
switch fd.FullName() {
case "did.v1.GenesisState.params":
x.Params = value.Message().Interface().(*Params)
case "did.v1.GenesisState.global_integrity":
x.GlobalIntegrity = value.Message().Interface().(*GlobalIntegrity)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GenesisState"))
@ -198,6 +215,11 @@ func (x *fastReflection_GenesisState) Mutable(fd protoreflect.FieldDescriptor) p
x.Params = new(Params)
}
return protoreflect.ValueOfMessage(x.Params.ProtoReflect())
case "did.v1.GenesisState.global_integrity":
if x.GlobalIntegrity == nil {
x.GlobalIntegrity = new(GlobalIntegrity)
}
return protoreflect.ValueOfMessage(x.GlobalIntegrity.ProtoReflect())
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GenesisState"))
@ -214,6 +236,9 @@ func (x *fastReflection_GenesisState) NewField(fd protoreflect.FieldDescriptor)
case "did.v1.GenesisState.params":
m := new(Params)
return protoreflect.ValueOfMessage(m.ProtoReflect())
case "did.v1.GenesisState.global_integrity":
m := new(GlobalIntegrity)
return protoreflect.ValueOfMessage(m.ProtoReflect())
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GenesisState"))
@ -287,6 +312,10 @@ func (x *fastReflection_GenesisState) ProtoMethods() *protoiface.Methods {
l = options.Size(x.Params)
n += 1 + l + runtime.Sov(uint64(l))
}
if x.GlobalIntegrity != nil {
l = options.Size(x.GlobalIntegrity)
n += 1 + l + runtime.Sov(uint64(l))
}
if x.unknownFields != nil {
n += len(x.unknownFields)
}
@ -316,6 +345,20 @@ func (x *fastReflection_GenesisState) ProtoMethods() *protoiface.Methods {
i -= len(x.unknownFields)
copy(dAtA[i:], x.unknownFields)
}
if x.GlobalIntegrity != nil {
encoded, err := options.Marshal(x.GlobalIntegrity)
if err != nil {
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded)))
i--
dAtA[i] = 0x12
}
if x.Params != nil {
encoded, err := options.Marshal(x.Params)
if err != nil {
@ -415,6 +458,640 @@ func (x *fastReflection_GenesisState) ProtoMethods() *protoiface.Methods {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field GlobalIntegrity", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if x.GlobalIntegrity == nil {
x.GlobalIntegrity = &GlobalIntegrity{}
}
if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.GlobalIntegrity); err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := runtime.Skip(dAtA[iNdEx:])
if err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if (iNdEx + skippy) > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if !options.DiscardUnknown {
x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...)
}
iNdEx += skippy
}
}
if iNdEx > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil
}
return &protoiface.Methods{
NoUnkeyedLiterals: struct{}{},
Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown,
Size: size,
Marshal: marshal,
Unmarshal: unmarshal,
Merge: nil,
CheckInitialized: nil,
}
}
var (
md_GlobalIntegrity protoreflect.MessageDescriptor
fd_GlobalIntegrity_controller protoreflect.FieldDescriptor
fd_GlobalIntegrity_seed protoreflect.FieldDescriptor
fd_GlobalIntegrity_accumulator protoreflect.FieldDescriptor
fd_GlobalIntegrity_count protoreflect.FieldDescriptor
)
func init() {
file_did_v1_genesis_proto_init()
md_GlobalIntegrity = File_did_v1_genesis_proto.Messages().ByName("GlobalIntegrity")
fd_GlobalIntegrity_controller = md_GlobalIntegrity.Fields().ByName("controller")
fd_GlobalIntegrity_seed = md_GlobalIntegrity.Fields().ByName("seed")
fd_GlobalIntegrity_accumulator = md_GlobalIntegrity.Fields().ByName("accumulator")
fd_GlobalIntegrity_count = md_GlobalIntegrity.Fields().ByName("count")
}
var _ protoreflect.Message = (*fastReflection_GlobalIntegrity)(nil)
type fastReflection_GlobalIntegrity GlobalIntegrity
func (x *GlobalIntegrity) ProtoReflect() protoreflect.Message {
return (*fastReflection_GlobalIntegrity)(x)
}
func (x *GlobalIntegrity) slowProtoReflect() protoreflect.Message {
mi := &file_did_v1_genesis_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
var _fastReflection_GlobalIntegrity_messageType fastReflection_GlobalIntegrity_messageType
var _ protoreflect.MessageType = fastReflection_GlobalIntegrity_messageType{}
type fastReflection_GlobalIntegrity_messageType struct{}
func (x fastReflection_GlobalIntegrity_messageType) Zero() protoreflect.Message {
return (*fastReflection_GlobalIntegrity)(nil)
}
func (x fastReflection_GlobalIntegrity_messageType) New() protoreflect.Message {
return new(fastReflection_GlobalIntegrity)
}
func (x fastReflection_GlobalIntegrity_messageType) Descriptor() protoreflect.MessageDescriptor {
return md_GlobalIntegrity
}
// Descriptor returns message descriptor, which contains only the protobuf
// type information for the message.
func (x *fastReflection_GlobalIntegrity) Descriptor() protoreflect.MessageDescriptor {
return md_GlobalIntegrity
}
// Type returns the message type, which encapsulates both Go and protobuf
// type information. If the Go type information is not needed,
// it is recommended that the message descriptor be used instead.
func (x *fastReflection_GlobalIntegrity) Type() protoreflect.MessageType {
return _fastReflection_GlobalIntegrity_messageType
}
// New returns a newly allocated and mutable empty message.
func (x *fastReflection_GlobalIntegrity) New() protoreflect.Message {
return new(fastReflection_GlobalIntegrity)
}
// Interface unwraps the message reflection interface and
// returns the underlying ProtoMessage interface.
func (x *fastReflection_GlobalIntegrity) Interface() protoreflect.ProtoMessage {
return (*GlobalIntegrity)(x)
}
// Range iterates over every populated field in an undefined order,
// calling f for each field descriptor and value encountered.
// Range returns immediately if f returns false.
// While iterating, mutating operations may only be performed
// on the current field descriptor.
func (x *fastReflection_GlobalIntegrity) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
if x.Controller != "" {
value := protoreflect.ValueOfString(x.Controller)
if !f(fd_GlobalIntegrity_controller, value) {
return
}
}
if x.Seed != "" {
value := protoreflect.ValueOfString(x.Seed)
if !f(fd_GlobalIntegrity_seed, value) {
return
}
}
if len(x.Accumulator) != 0 {
value := protoreflect.ValueOfBytes(x.Accumulator)
if !f(fd_GlobalIntegrity_accumulator, value) {
return
}
}
if x.Count != uint64(0) {
value := protoreflect.ValueOfUint64(x.Count)
if !f(fd_GlobalIntegrity_count, value) {
return
}
}
}
// Has reports whether a field is populated.
//
// Some fields have the property of nullability where it is possible to
// distinguish between the default value of a field and whether the field
// was explicitly populated with the default value. Singular message fields,
// member fields of a oneof, and proto2 scalar fields are nullable. Such
// fields are populated only if explicitly set.
//
// In other cases (aside from the nullable cases above),
// a proto3 scalar field is populated if it contains a non-zero value, and
// a repeated field is populated if it is non-empty.
func (x *fastReflection_GlobalIntegrity) Has(fd protoreflect.FieldDescriptor) bool {
switch fd.FullName() {
case "did.v1.GlobalIntegrity.controller":
return x.Controller != ""
case "did.v1.GlobalIntegrity.seed":
return x.Seed != ""
case "did.v1.GlobalIntegrity.accumulator":
return len(x.Accumulator) != 0
case "did.v1.GlobalIntegrity.count":
return x.Count != uint64(0)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GlobalIntegrity"))
}
panic(fmt.Errorf("message did.v1.GlobalIntegrity does not contain field %s", fd.FullName()))
}
}
// Clear clears the field such that a subsequent Has call reports false.
//
// Clearing an extension field clears both the extension type and value
// associated with the given field number.
//
// Clear is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_GlobalIntegrity) Clear(fd protoreflect.FieldDescriptor) {
switch fd.FullName() {
case "did.v1.GlobalIntegrity.controller":
x.Controller = ""
case "did.v1.GlobalIntegrity.seed":
x.Seed = ""
case "did.v1.GlobalIntegrity.accumulator":
x.Accumulator = nil
case "did.v1.GlobalIntegrity.count":
x.Count = uint64(0)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GlobalIntegrity"))
}
panic(fmt.Errorf("message did.v1.GlobalIntegrity does not contain field %s", fd.FullName()))
}
}
// Get retrieves the value for a field.
//
// For unpopulated scalars, it returns the default value, where
// the default value of a bytes scalar is guaranteed to be a copy.
// For unpopulated composite types, it returns an empty, read-only view
// of the value; to obtain a mutable reference, use Mutable.
func (x *fastReflection_GlobalIntegrity) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value {
switch descriptor.FullName() {
case "did.v1.GlobalIntegrity.controller":
value := x.Controller
return protoreflect.ValueOfString(value)
case "did.v1.GlobalIntegrity.seed":
value := x.Seed
return protoreflect.ValueOfString(value)
case "did.v1.GlobalIntegrity.accumulator":
value := x.Accumulator
return protoreflect.ValueOfBytes(value)
case "did.v1.GlobalIntegrity.count":
value := x.Count
return protoreflect.ValueOfUint64(value)
default:
if descriptor.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GlobalIntegrity"))
}
panic(fmt.Errorf("message did.v1.GlobalIntegrity does not contain field %s", descriptor.FullName()))
}
}
// Set stores the value for a field.
//
// For a field belonging to a oneof, it implicitly clears any other field
// that may be currently set within the same oneof.
// For extension fields, it implicitly stores the provided ExtensionType.
// When setting a composite type, it is unspecified whether the stored value
// aliases the source's memory in any way. If the composite value is an
// empty, read-only value, then it panics.
//
// Set is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_GlobalIntegrity) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) {
switch fd.FullName() {
case "did.v1.GlobalIntegrity.controller":
x.Controller = value.Interface().(string)
case "did.v1.GlobalIntegrity.seed":
x.Seed = value.Interface().(string)
case "did.v1.GlobalIntegrity.accumulator":
x.Accumulator = value.Bytes()
case "did.v1.GlobalIntegrity.count":
x.Count = value.Uint()
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GlobalIntegrity"))
}
panic(fmt.Errorf("message did.v1.GlobalIntegrity does not contain field %s", fd.FullName()))
}
}
// Mutable returns a mutable reference to a composite type.
//
// If the field is unpopulated, it may allocate a composite value.
// For a field belonging to a oneof, it implicitly clears any other field
// that may be currently set within the same oneof.
// For extension fields, it implicitly stores the provided ExtensionType
// if not already stored.
// It panics if the field does not contain a composite type.
//
// Mutable is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_GlobalIntegrity) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.FullName() {
case "did.v1.GlobalIntegrity.controller":
panic(fmt.Errorf("field controller of message did.v1.GlobalIntegrity is not mutable"))
case "did.v1.GlobalIntegrity.seed":
panic(fmt.Errorf("field seed of message did.v1.GlobalIntegrity is not mutable"))
case "did.v1.GlobalIntegrity.accumulator":
panic(fmt.Errorf("field accumulator of message did.v1.GlobalIntegrity is not mutable"))
case "did.v1.GlobalIntegrity.count":
panic(fmt.Errorf("field count of message did.v1.GlobalIntegrity is not mutable"))
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GlobalIntegrity"))
}
panic(fmt.Errorf("message did.v1.GlobalIntegrity does not contain field %s", fd.FullName()))
}
}
// NewField returns a new value that is assignable to the field
// for the given descriptor. For scalars, this returns the default value.
// For lists, maps, and messages, this returns a new, empty, mutable value.
func (x *fastReflection_GlobalIntegrity) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.FullName() {
case "did.v1.GlobalIntegrity.controller":
return protoreflect.ValueOfString("")
case "did.v1.GlobalIntegrity.seed":
return protoreflect.ValueOfString("")
case "did.v1.GlobalIntegrity.accumulator":
return protoreflect.ValueOfBytes(nil)
case "did.v1.GlobalIntegrity.count":
return protoreflect.ValueOfUint64(uint64(0))
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: did.v1.GlobalIntegrity"))
}
panic(fmt.Errorf("message did.v1.GlobalIntegrity does not contain field %s", fd.FullName()))
}
}
// WhichOneof reports which field within the oneof is populated,
// returning nil if none are populated.
// It panics if the oneof descriptor does not belong to this message.
func (x *fastReflection_GlobalIntegrity) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
switch d.FullName() {
default:
panic(fmt.Errorf("%s is not a oneof field in did.v1.GlobalIntegrity", d.FullName()))
}
panic("unreachable")
}
// GetUnknown retrieves the entire list of unknown fields.
// The caller may only mutate the contents of the RawFields
// if the mutated bytes are stored back into the message with SetUnknown.
func (x *fastReflection_GlobalIntegrity) GetUnknown() protoreflect.RawFields {
return x.unknownFields
}
// SetUnknown stores an entire list of unknown fields.
// The raw fields must be syntactically valid according to the wire format.
// An implementation may panic if this is not the case.
// Once stored, the caller must not mutate the content of the RawFields.
// An empty RawFields may be passed to clear the fields.
//
// SetUnknown is a mutating operation and unsafe for concurrent use.
func (x *fastReflection_GlobalIntegrity) SetUnknown(fields protoreflect.RawFields) {
x.unknownFields = fields
}
// IsValid reports whether the message is valid.
//
// An invalid message is an empty, read-only value.
//
// An invalid message often corresponds to a nil pointer of the concrete
// message type, but the details are implementation dependent.
// Validity is not part of the protobuf data model, and may not
// be preserved in marshaling or other operations.
func (x *fastReflection_GlobalIntegrity) IsValid() bool {
return x != nil
}
// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations.
// This method may return nil.
//
// The returned methods type is identical to
// "google.golang.org/protobuf/runtime/protoiface".Methods.
// Consult the protoiface package documentation for details.
func (x *fastReflection_GlobalIntegrity) ProtoMethods() *protoiface.Methods {
size := func(input protoiface.SizeInput) protoiface.SizeOutput {
x := input.Message.Interface().(*GlobalIntegrity)
if x == nil {
return protoiface.SizeOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Size: 0,
}
}
options := runtime.SizeInputToOptions(input)
_ = options
var n int
var l int
_ = l
l = len(x.Controller)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
l = len(x.Seed)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
l = len(x.Accumulator)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
if x.Count != 0 {
n += 1 + runtime.Sov(uint64(x.Count))
}
if x.unknownFields != nil {
n += len(x.unknownFields)
}
return protoiface.SizeOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Size: n,
}
}
marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) {
x := input.Message.Interface().(*GlobalIntegrity)
if x == nil {
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, nil
}
options := runtime.MarshalInputToOptions(input)
_ = options
size := options.Size(x)
dAtA := make([]byte, size)
i := len(dAtA)
_ = i
var l int
_ = l
if x.unknownFields != nil {
i -= len(x.unknownFields)
copy(dAtA[i:], x.unknownFields)
}
if x.Count != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.Count))
i--
dAtA[i] = 0x20
}
if len(x.Accumulator) > 0 {
i -= len(x.Accumulator)
copy(dAtA[i:], x.Accumulator)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Accumulator)))
i--
dAtA[i] = 0x1a
}
if len(x.Seed) > 0 {
i -= len(x.Seed)
copy(dAtA[i:], x.Seed)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Seed)))
i--
dAtA[i] = 0x12
}
if len(x.Controller) > 0 {
i -= len(x.Controller)
copy(dAtA[i:], x.Controller)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Controller)))
i--
dAtA[i] = 0xa
}
if input.Buf != nil {
input.Buf = append(input.Buf, dAtA...)
} else {
input.Buf = dAtA
}
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, nil
}
unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) {
x := input.Message.Interface().(*GlobalIntegrity)
if x == nil {
return protoiface.UnmarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Flags: input.Flags,
}, nil
}
options := runtime.UnmarshalInputToOptions(input)
_ = options
dAtA := input.Buf
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: GlobalIntegrity: wiretype end group for non-group")
}
if fieldNum <= 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: GlobalIntegrity: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Controller", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Controller = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Seed", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Seed = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Accumulator", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
byteLen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + byteLen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Accumulator = append(x.Accumulator[:0], dAtA[iNdEx:postIndex]...)
if x.Accumulator == nil {
x.Accumulator = []byte{}
}
iNdEx = postIndex
case 4:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Count", wireType)
}
x.Count = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
x.Count |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := runtime.Skip(dAtA[iNdEx:])
@ -667,7 +1344,7 @@ func (x *Params) ProtoReflect() protoreflect.Message {
}
func (x *Params) slowProtoReflect() protoreflect.Message {
mi := &file_did_v1_genesis_proto_msgTypes[1]
mi := &file_did_v1_genesis_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -6936,6 +7613,8 @@ type GenesisState struct {
// Params defines all the parameters of the module.
Params *Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params,omitempty"`
// GlobalIntegrity defines a zkp integrity proof for the entire DID namespace
GlobalIntegrity *GlobalIntegrity `protobuf:"bytes,2,opt,name=global_integrity,json=globalIntegrity,proto3" json:"global_integrity,omitempty"`
}
func (x *GenesisState) Reset() {
@ -6965,6 +7644,73 @@ func (x *GenesisState) GetParams() *Params {
return nil
}
func (x *GenesisState) GetGlobalIntegrity() *GlobalIntegrity {
if x != nil {
return x.GlobalIntegrity
}
return nil
}
// GlobalIntegrity defines a zkp integrity proof for the entire DID namespace
type GlobalIntegrity struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Controller string `protobuf:"bytes,1,opt,name=controller,proto3" json:"controller,omitempty"`
Seed string `protobuf:"bytes,2,opt,name=seed,proto3" json:"seed,omitempty"`
Accumulator []byte `protobuf:"bytes,3,opt,name=accumulator,proto3" json:"accumulator,omitempty"`
Count uint64 `protobuf:"varint,4,opt,name=count,proto3" json:"count,omitempty"`
}
func (x *GlobalIntegrity) Reset() {
*x = GlobalIntegrity{}
if protoimpl.UnsafeEnabled {
mi := &file_did_v1_genesis_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *GlobalIntegrity) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GlobalIntegrity) ProtoMessage() {}
// Deprecated: Use GlobalIntegrity.ProtoReflect.Descriptor instead.
func (*GlobalIntegrity) Descriptor() ([]byte, []int) {
return file_did_v1_genesis_proto_rawDescGZIP(), []int{1}
}
func (x *GlobalIntegrity) GetController() string {
if x != nil {
return x.Controller
}
return ""
}
func (x *GlobalIntegrity) GetSeed() string {
if x != nil {
return x.Seed
}
return ""
}
func (x *GlobalIntegrity) GetAccumulator() []byte {
if x != nil {
return x.Accumulator
}
return nil
}
func (x *GlobalIntegrity) GetCount() uint64 {
if x != nil {
return x.Count
}
return 0
}
// Params defines the set of module parameters.
type Params struct {
state protoimpl.MessageState
@ -6988,7 +7734,7 @@ type Params struct {
func (x *Params) Reset() {
*x = Params{}
if protoimpl.UnsafeEnabled {
mi := &file_did_v1_genesis_proto_msgTypes[1]
mi := &file_did_v1_genesis_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -7002,7 +7748,7 @@ func (*Params) ProtoMessage() {}
// Deprecated: Use Params.ProtoReflect.Descriptor instead.
func (*Params) Descriptor() ([]byte, []int) {
return file_did_v1_genesis_proto_rawDescGZIP(), []int{1}
return file_did_v1_genesis_proto_rawDescGZIP(), []int{2}
}
func (x *Params) GetWhitelistedAssets() []*AssetInfo {
@ -7718,6 +8464,18 @@ func file_did_v1_genesis_proto_init() {
}
}
file_did_v1_genesis_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*GlobalIntegrity); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_did_v1_genesis_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Params); i {
case 0:
return &v.state

View File

@ -31,15 +31,15 @@ func init() {
fd_MsgUpdateParams_token = md_MsgUpdateParams.Fields().ByName("token")
}
var _ protoreflect.Message = (*fastReflection_MsgUpdateParams)(nil)
var _ protoreflect.Message = (*fastReflection_MsgAllocateVault)(nil)
type fastReflection_MsgUpdateParams MsgUpdateParams
type fastReflection_MsgAllocateVault MsgAllocateVault
func (x *MsgUpdateParams) ProtoReflect() protoreflect.Message {
return (*fastReflection_MsgUpdateParams)(x)
func (x *MsgAllocateVault) ProtoReflect() protoreflect.Message {
return (*fastReflection_MsgAllocateVault)(x)
}
func (x *MsgUpdateParams) slowProtoReflect() protoreflect.Message {
func (x *MsgAllocateVault) slowProtoReflect() protoreflect.Message {
mi := &file_did_v1_tx_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -51,43 +51,43 @@ func (x *MsgUpdateParams) slowProtoReflect() protoreflect.Message {
return mi.MessageOf(x)
}
var _fastReflection_MsgUpdateParams_messageType fastReflection_MsgUpdateParams_messageType
var _ protoreflect.MessageType = fastReflection_MsgUpdateParams_messageType{}
var _fastReflection_MsgAllocateVault_messageType fastReflection_MsgAllocateVault_messageType
var _ protoreflect.MessageType = fastReflection_MsgAllocateVault_messageType{}
type fastReflection_MsgUpdateParams_messageType struct{}
type fastReflection_MsgAllocateVault_messageType struct{}
func (x fastReflection_MsgUpdateParams_messageType) Zero() protoreflect.Message {
return (*fastReflection_MsgUpdateParams)(nil)
func (x fastReflection_MsgAllocateVault_messageType) Zero() protoreflect.Message {
return (*fastReflection_MsgAllocateVault)(nil)
}
func (x fastReflection_MsgUpdateParams_messageType) New() protoreflect.Message {
return new(fastReflection_MsgUpdateParams)
func (x fastReflection_MsgAllocateVault_messageType) New() protoreflect.Message {
return new(fastReflection_MsgAllocateVault)
}
func (x fastReflection_MsgUpdateParams_messageType) Descriptor() protoreflect.MessageDescriptor {
return md_MsgUpdateParams
func (x fastReflection_MsgAllocateVault_messageType) Descriptor() protoreflect.MessageDescriptor {
return md_MsgAllocateVault
}
// Descriptor returns message descriptor, which contains only the protobuf
// type information for the message.
func (x *fastReflection_MsgUpdateParams) Descriptor() protoreflect.MessageDescriptor {
return md_MsgUpdateParams
func (x *fastReflection_MsgAllocateVault) Descriptor() protoreflect.MessageDescriptor {
return md_MsgAllocateVault
}
// Type returns the message type, which encapsulates both Go and protobuf
// type information. If the Go type information is not needed,
// it is recommended that the message descriptor be used instead.
func (x *fastReflection_MsgUpdateParams) Type() protoreflect.MessageType {
return _fastReflection_MsgUpdateParams_messageType
func (x *fastReflection_MsgAllocateVault) Type() protoreflect.MessageType {
return _fastReflection_MsgAllocateVault_messageType
}
// New returns a newly allocated and mutable empty message.
func (x *fastReflection_MsgUpdateParams) New() protoreflect.Message {
return new(fastReflection_MsgUpdateParams)
func (x *fastReflection_MsgAllocateVault) New() protoreflect.Message {
return new(fastReflection_MsgAllocateVault)
}
// Interface unwraps the message reflection interface and
// returns the underlying ProtoMessage interface.
func (x *fastReflection_MsgUpdateParams) Interface() protoreflect.ProtoMessage {
return (*MsgUpdateParams)(x)
func (x *fastReflection_MsgAllocateVault) Interface() protoreflect.ProtoMessage {
return (*MsgAllocateVault)(x)
}
// Range iterates over every populated field in an undefined order,
@ -95,10 +95,10 @@ func (x *fastReflection_MsgUpdateParams) Interface() protoreflect.ProtoMessage {
// Range returns immediately if f returns false.
// While iterating, mutating operations may only be performed
// on the current field descriptor.
func (x *fastReflection_MsgUpdateParams) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
func (x *fastReflection_MsgAllocateVault) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
if x.Authority != "" {
value := protoreflect.ValueOfString(x.Authority)
if !f(fd_MsgUpdateParams_authority, value) {
if !f(fd_MsgAllocateVault_authority, value) {
return
}
}
@ -5951,15 +5951,13 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// MsgUpdateParams is the Msg/UpdateParams request type.
//
// Since: cosmos-sdk 0.47
type MsgUpdateParams struct {
// MsgAllocateVault is the message type for the AllocateVault RPC.
type MsgAllocateVault struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// authority is the address of the governance account.
// authority is the address of the service account.
Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"`
// params defines the parameters to update.
Params *Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params,omitempty"`
@ -5967,8 +5965,8 @@ type MsgUpdateParams struct {
Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"`
}
func (x *MsgUpdateParams) Reset() {
*x = MsgUpdateParams{}
func (x *MsgAllocateVault) Reset() {
*x = MsgAllocateVault{}
if protoimpl.UnsafeEnabled {
mi := &file_did_v1_tx_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -5976,29 +5974,29 @@ func (x *MsgUpdateParams) Reset() {
}
}
func (x *MsgUpdateParams) String() string {
func (x *MsgAllocateVault) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MsgUpdateParams) ProtoMessage() {}
func (*MsgAllocateVault) ProtoMessage() {}
// Deprecated: Use MsgUpdateParams.ProtoReflect.Descriptor instead.
func (*MsgUpdateParams) Descriptor() ([]byte, []int) {
// Deprecated: Use MsgAllocateVault.ProtoReflect.Descriptor instead.
func (*MsgAllocateVault) Descriptor() ([]byte, []int) {
return file_did_v1_tx_proto_rawDescGZIP(), []int{0}
}
func (x *MsgUpdateParams) GetAuthority() string {
func (x *MsgAllocateVault) GetAuthority() string {
if x != nil {
return x.Authority
}
return ""
}
func (x *MsgUpdateParams) GetParams() *Params {
func (x *MsgAllocateVault) GetSubject() string {
if x != nil {
return x.Params
return x.Subject
}
return nil
return ""
}
func (x *MsgUpdateParams) GetToken() string {
@ -6016,10 +6014,19 @@ type MsgUpdateParamsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// CID is the content identifier of the vault.
Cid string `protobuf:"bytes,1,opt,name=cid,proto3" json:"cid,omitempty"`
// ExpiryBlock is the block number at which the vault will expire.
ExpiryBlock int64 `protobuf:"varint,2,opt,name=expiry_block,json=expiryBlock,proto3" json:"expiry_block,omitempty"`
// RegistrationOptions is a json string of the PublicKeyCredentialCreationOptions for WebAuthn
Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"`
// IsLocalhost is a flag to indicate if the vault is localhost
Localhost bool `protobuf:"varint,4,opt,name=localhost,proto3" json:"localhost,omitempty"`
}
func (x *MsgUpdateParamsResponse) Reset() {
*x = MsgUpdateParamsResponse{}
func (x *MsgAllocateVaultResponse) Reset() {
*x = MsgAllocateVaultResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_did_v1_tx_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@ -6027,14 +6034,14 @@ func (x *MsgUpdateParamsResponse) Reset() {
}
}
func (x *MsgUpdateParamsResponse) String() string {
func (x *MsgAllocateVaultResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*MsgUpdateParamsResponse) ProtoMessage() {}
func (*MsgAllocateVaultResponse) ProtoMessage() {}
// Deprecated: Use MsgUpdateParamsResponse.ProtoReflect.Descriptor instead.
func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) {
// Deprecated: Use MsgAllocateVaultResponse.ProtoReflect.Descriptor instead.
func (*MsgAllocateVaultResponse) Descriptor() ([]byte, []int) {
return file_did_v1_tx_proto_rawDescGZIP(), []int{1}
}
@ -6675,7 +6682,7 @@ func file_did_v1_tx_proto_init() {
file_did_v1_genesis_proto_init()
if !protoimpl.UnsafeEnabled {
file_did_v1_tx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MsgUpdateParams); i {
switch v := v.(*MsgAllocateVault); i {
case 0:
return &v.state
case 1:
@ -6687,7 +6694,7 @@ func file_did_v1_tx_proto_init() {
}
}
file_did_v1_tx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MsgUpdateParamsResponse); i {
switch v := v.(*MsgAllocateVaultResponse); i {
case 0:
return &v.state
case 1:
@ -6794,6 +6801,30 @@ func file_did_v1_tx_proto_init() {
return nil
}
}
file_did_v1_tx_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MsgUpdateParams); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_did_v1_tx_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*MsgUpdateParamsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{

40
cmd/dwn/main.go Normal file
View File

@ -0,0 +1,40 @@
//go:build js && wasm
// +build js,wasm
package main
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/vfs/wasm"
"github.com/onsonr/sonr/internal/db"
)
var dwn *DWN
type DWN struct {
*echo.Echo
DB *db.DB
}
func main() {
dwn = initRails()
wasm.Serve(dwn.Echo)
}
// initRails initializes the Rails application
func initRails() *DWN {
// Open the database
e := echo.New()
db, err := db.New()
if err != nil {
panic(err.Error())
}
db.ServeEcho(e.Group("/dwn"))
// Initialize the htmx handler
return &DWN{
Echo: e,
DB: db,
}
}

61
cmd/motr/main.go Normal file
View File

@ -0,0 +1,61 @@
//go:build wasm
package main
import (
"github.com/labstack/echo/v4"
"github.com/syumai/workers"
"github.com/onsonr/sonr/internal/db"
"github.com/onsonr/sonr/internal/gui/views"
"github.com/onsonr/sonr/internal/mdw"
"github.com/onsonr/sonr/internal/svc"
)
func main() {
// Configure the server
e := echo.New()
// Use Middlewares
e.Use(mdw.UseSession)
// Setup routes
registerFrontend(e)
registerOpenID(e.Group("/authorize"))
registerVault(e.Group("/vault"))
// Serve Worker
workers.Serve(e)
}
func registerFrontend(e *echo.Echo) {
// Add Public Pages
e.GET("/", views.HomeView)
e.GET("/login", views.LoginView)
e.POST("/login/:identifier", svc.HandleCredentialAssertion)
e.GET("/register", views.RegisterView)
e.POST("/register/:subject", svc.HandleCredentialCreation)
e.POST("/register/:subject/check", svc.CheckSubjectIsValid)
e.GET("/profile", views.ProfileView)
}
func registerOpenID(g *echo.Group) {
// Add Authenticated Pages
g.Use(mdw.MacaroonMiddleware("test", "test"))
g.GET("/", views.AuthorizeView)
g.GET("/discovery", svc.GetDiscovery)
g.GET("/jwks", svc.GetJWKS)
g.GET("/token", svc.GetToken)
g.POST("/:origin/grant/:subject", svc.GrantAuthorization)
}
func registerVault(g *echo.Group) {
// Add Authenticated Pages
g.Use(mdw.MacaroonMiddleware("test", "test"))
vault, err := db.New(db.WitDir("vault"))
if err != nil {
// panic(err)
}
vault.ServeEcho(g)
}

10
cmd/motr/wrangler.toml Normal file
View File

@ -0,0 +1,10 @@
name = "sonr-id"
main = "./build/worker.mjs"
compatibility_date = "2024-07-26"
[dev]
ip = "localhost"
port = 4202
[build]
command = "devbox run build:motr"

30
docker-compose.yaml Normal file
View File

@ -0,0 +1,30 @@
version: "3"
services:
sonr-node:
build:
context: .
dockerfile: Dockerfile
volumes:
- /home/prad/.scnr:/root/.sonr
ports:
- "26657:26657"
- "1317:1317"
- "9090:9090"
environment:
- CHAIN_ID=local-1
- MONIKER=localvalidator
- KEYRING=test
- KEY=user1
- KEY2=user2
- DENOM=usnr
- CLEAN=true
- BLOCK_TIME=5s
command: "start --pruning=nothing"
restart: always
networks:
- sonr-network
networks:
sonr-network:
name: sonr-network

10
go.mod
View File

@ -54,6 +54,7 @@ require (
github.com/charmbracelet/huh v0.5.3
github.com/charmbracelet/lipgloss v0.13.0
github.com/cometbft/cometbft v0.38.8
github.com/cosmos/btcutil v1.0.5
github.com/cosmos/cosmos-db v1.0.2
github.com/cosmos/cosmos-proto v1.0.0-beta.5
github.com/cosmos/cosmos-sdk v0.50.5
@ -95,6 +96,7 @@ require (
cloud.google.com/go/iam v1.1.6 // indirect
cloud.google.com/go/storage v1.38.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.1 // indirect
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
@ -129,7 +131,6 @@ require (
github.com/cometbft/cometbft-db v0.9.1 // indirect
github.com/consensys/bavard v0.1.13 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/iavl v1.1.2 // indirect
@ -226,6 +227,8 @@ require (
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
@ -261,7 +264,6 @@ require (
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
@ -275,6 +277,7 @@ require (
github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/ncruces/julianday v1.0.0 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect
@ -306,6 +309,7 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tetratelabs/wazero v1.8.0 // indirect
github.com/tidwall/btree v1.7.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
@ -344,11 +348,11 @@ require (
google.golang.org/api v0.169.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240617180043-68d350f18fd4 // indirect
gopkg.in/errgo.v1 v1.0.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
lukechampine.com/blake3 v1.3.0 // indirect
nhooyr.io/websocket v1.8.10 // indirect
pgregory.net/rapid v1.1.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect

35
go.sum
View File

@ -803,6 +803,9 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc=
git.sr.ht/~sircmpwn/getopt v0.0.0-20191230200459-23622cc906b3/go.mod h1:wMEGFFFNuPos7vHmWXfszqImLppbc0wEhh6JBfJIUgw=
git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9 h1:Ahny8Ud1LjVMMAlt8utUFKhhxJtwBAualvsbc/Sk7cE=
git.sr.ht/~sircmpwn/go-bare v0.0.0-20210406120253-ab86bc2846d9/go.mod h1:BVJwbDfVjCjoFiKrhkei6NdGcZYpkDkdyCdg1ukytRA=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
@ -1192,6 +1195,7 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-macaroon-bakery/macaroonpb v1.0.0/go.mod h1:UzrGOcbiwTXISFP2XDLDPjfhMINZa+fX/7A2lMd31zc=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -1278,6 +1282,7 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@ -1578,6 +1583,10 @@ github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jhump/protoreflect v1.15.3 h1:6SFRuqU45u9hIZPJAoZ8c28T3nK64BNdp9w6jFonzls=
github.com/jhump/protoreflect v1.15.3/go.mod h1:4ORHmSBmlCW8fh3xHmJMGyul1zNqZK4Elxc8qKP+p1k=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
@ -1594,6 +1603,12 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/mgotest v1.0.1/go.mod h1:vTaDufYul+Ps8D7bgseHjq87X8eu0ivlKLp9mVc/Bfc=
github.com/juju/postgrestest v1.1.0/go.mod h1:/n17Y2T6iFozzXwSCO0JYJ5gSiz2caEtSwAjh/uLXDM=
github.com/juju/qthttptest v0.0.1/go.mod h1://LCf/Ls22/rPw2u1yWukUJvYtfPY4nYpWUl2uZhryo=
github.com/juju/schema v1.0.0/go.mod h1:Y+ThzXpUJ0E7NYYocAbuvJ7vTivXfrof/IfRPq/0abI=
github.com/juju/webbrowser v0.0.0-20160309143629-54b8c57083b4/go.mod h1:G6PCelgkM6cuvyD10iYJsjLBsSadVXtJ+nBxFAxE2BU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
@ -1636,6 +1651,8 @@ github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
@ -1806,6 +1823,12 @@ github.com/nats-io/nats.go v1.30.2/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzD
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/ncruces/go-sqlite3 v0.18.2 h1:m7QXhBWIwXsp84HE11t+ze0n1v3LRU+zGFg4uHjBeFA=
github.com/ncruces/go-sqlite3 v0.18.2/go.mod h1:4sZHOm+b/FM8FJRVGN4TemkPPDq5JXGK/1EHIEWxsYo=
github.com/ncruces/go-sqlite3/gormlite v0.18.0 h1:KqP9a9wlX/Ba+yG+aeVX4pnNBNdaSO6xHdNDWzPxPnk=
github.com/ncruces/go-sqlite3/gormlite v0.18.0/go.mod h1:RXeT1hknrz3A0tBDL6IfluDHuNkHdJeImn5TBMQg9zc=
github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nlepage/go-js-promise v1.0.0 h1:K7OmJ3+0BgWJ2LfXchg2sI6RDr7AW/KWR8182epFwGQ=
github.com/nlepage/go-js-promise v1.0.0/go.mod h1:bdOP0wObXu34euibyK39K1hoBCtlgTKXGc56AGflaRo=
@ -2052,6 +2075,8 @@ github.com/syumai/workers v0.26.3 h1:AF+IBaRccbR4JIj2kNJLJblruPFMD/pAbzkopejGcP8
github.com/syumai/workers v0.26.3/go.mod h1:ZnqmdiHNBrbxOLrZ/HJ5jzHy6af9cmiNZk10R9NrIEA=
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g=
github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
@ -2186,6 +2211,7 @@ go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEb
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -2421,6 +2447,7 @@ golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -3007,8 +3034,12 @@ gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk=
gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/httprequest.v1 v1.2.0/go.mod h1:T61ZUaJLpMnzvoJDO03ZD8yRXD4nZzBeDoW5e9sffjg=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=
@ -3029,6 +3060,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@ -3039,6 +3072,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
lukechampine.com/adiantum v1.1.1 h1:4fp6gTxWCqpEbLy40ExiYDDED3oUNWx5cTqBCtPdZqA=
lukechampine.com/adiantum v1.1.1/go.mod h1:LrAYVnTYLnUtE/yMp5bQr0HstAf060YUF8nM0B6+rUw=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=

330
internal/db/actions.go Normal file
View File

@ -0,0 +1,330 @@
package db
import (
"fmt"
"github.com/onsonr/sonr/internal/db/orm"
"gorm.io/gorm"
)
// createInitialTables creates the initial tables in the database.
func createInitialTables(db *gorm.DB) (*DB, error) {
err := db.AutoMigrate(
&orm.Account{},
&orm.Asset{},
&orm.Credential{},
&orm.Keyshare{},
&orm.Permission{},
&orm.Profile{},
&orm.Property{},
)
if err != nil {
return nil, fmt.Errorf("failed to create table: %w", err)
}
return &DB{db}, nil
}
// AddAccount adds a new account to the database
func (db *DB) AddAccount(account *orm.Account) error {
tx := db.Create(account)
if tx.Error != nil {
return fmt.Errorf("failed to add account: %w", tx.Error)
}
return nil
}
// GetAccount gets an account from the database
func (db *DB) GetAccount(account *orm.Account) error {
tx := db.First(account)
if tx.Error != nil {
return fmt.Errorf("failed to get account: %w", tx.Error)
}
return nil
}
// UpdateAccount updates an existing account in the database
func (db *DB) UpdateAccount(account *orm.Account) error {
tx := db.Save(account)
if tx.Error != nil {
return fmt.Errorf("failed to update account: %w", tx.Error)
}
return nil
}
// DeleteAccount deletes an existing account from the database
func (db *DB) DeleteAccount(account *orm.Account) error {
tx := db.Delete(account)
if tx.Error != nil {
return fmt.Errorf("failed to delete account: %w", tx.Error)
}
return nil
}
// AddAsset adds a new asset to the database
func (db *DB) AddAsset(asset *orm.Asset) error {
tx := db.Create(asset)
if tx.Error != nil {
return fmt.Errorf("failed to add asset: %w", tx.Error)
}
return nil
}
// GetAsset gets an asset from the database
func (db *DB) GetAsset(asset *orm.Asset) error {
tx := db.First(asset)
if tx.Error != nil {
return fmt.Errorf("failed to get asset: %w", tx.Error)
}
return nil
}
// UpdateAsset updates an existing asset in the database
func (db *DB) UpdateAsset(asset *orm.Asset) error {
tx := db.Save(asset)
if tx.Error != nil {
return fmt.Errorf("failed to update asset: %w", tx.Error)
}
return nil
}
// DeleteAsset deletes an existing asset from the database
func (db *DB) DeleteAsset(asset *orm.Asset) error {
tx := db.Delete(asset)
if tx.Error != nil {
return fmt.Errorf("failed to delete asset: %w", tx.Error)
}
return nil
}
// AddCredential adds a new credential to the database
func (db *DB) AddCredential(credential *orm.Credential) error {
tx := db.Create(credential)
if tx.Error != nil {
return fmt.Errorf("failed to add credential: %w", tx.Error)
}
return nil
}
// GetCredential gets an credential from the database
func (db *DB) GetCredential(credential *orm.Credential) error {
tx := db.First(credential)
if tx.Error != nil {
return fmt.Errorf("failed to get credential: %w", tx.Error)
}
return nil
}
// UpdateCredential updates an existing credential in the database
func (db *DB) UpdateCredential(credential *orm.Credential) error {
tx := db.Save(credential)
if tx.Error != nil {
return fmt.Errorf("failed to update credential: %w", tx.Error)
}
return nil
}
// DeleteCredential deletes an existing credential from the database
func (db *DB) DeleteCredential(credential *orm.Credential) error {
tx := db.Delete(credential)
if tx.Error != nil {
return fmt.Errorf("failed to delete credential: %w", tx.Error)
}
return nil
}
// AddKeyshare adds a new keyshare to the database
func (db *DB) AddKeyshare(keyshare *orm.Keyshare) error {
tx := db.Create(keyshare)
if tx.Error != nil {
return fmt.Errorf("failed to add keyshare: %w", tx.Error)
}
return nil
}
// GetKeyshare gets an keyshare from the database
func (db *DB) GetKeyshare(keyshare *orm.Keyshare) error {
tx := db.First(keyshare)
if tx.Error != nil {
return fmt.Errorf("failed to get keyshare: %w", tx.Error)
}
return nil
}
// UpdateKeyshare updates an existing keyshare in the database
func (db *DB) UpdateKeyshare(keyshare *orm.Keyshare) error {
tx := db.Save(keyshare)
if tx.Error != nil {
return fmt.Errorf("failed to update keyshare: %w", tx.Error)
}
return nil
}
// DeleteKeyshare deletes an existing keyshare from the database
func (db *DB) DeleteKeyshare(keyshare *orm.Keyshare) error {
tx := db.Delete(keyshare)
if tx.Error != nil {
return fmt.Errorf("failed to delete keyshare: %w", tx.Error)
}
return nil
}
// AddPermission adds a new permission to the database
func (db *DB) AddPermission(permission *orm.Permission) error {
tx := db.Create(permission)
if tx.Error != nil {
return fmt.Errorf("failed to add permission: %w", tx.Error)
}
return nil
}
// GetPermission gets an permission from the database
func (db *DB) GetPermission(permission *orm.Permission) error {
tx := db.First(permission)
if tx.Error != nil {
return fmt.Errorf("failed to get permission: %w", tx.Error)
}
return nil
}
// UpdatePermission updates an existing permission in the database
func (db *DB) UpdatePermission(permission *orm.Permission) error {
tx := db.Save(permission)
if tx.Error != nil {
return fmt.Errorf("failed to update permission: %w", tx.Error)
}
return nil
}
// DeletePermission deletes an existing permission from the database
func (db *DB) DeletePermission(permission *orm.Permission) error {
tx := db.Delete(permission)
if tx.Error != nil {
return fmt.Errorf("failed to delete permission: %w", tx.Error)
}
return nil
}
// AddProfile adds a new profile to the database
func (db *DB) AddProfile(profile *orm.Profile) error {
tx := db.Create(profile)
if tx.Error != nil {
return fmt.Errorf("failed to add profile: %w", tx.Error)
}
return nil
}
// GetProfile gets an profile from the database
func (db *DB) GetProfile(profile *orm.Profile) error {
tx := db.First(profile)
if tx.Error != nil {
return fmt.Errorf("failed to get profile: %w", tx.Error)
}
return nil
}
// UpdateProfile updates an existing profile in the database
func (db *DB) UpdateProfile(profile *orm.Profile) error {
tx := db.Save(profile)
if tx.Error != nil {
return fmt.Errorf("failed to update profile: %w", tx.Error)
}
return nil
}
// DeleteProfile deletes an existing profile from the database
func (db *DB) DeleteProfile(profile *orm.Profile) error {
tx := db.Delete(profile)
if tx.Error != nil {
return fmt.Errorf("failed to delete profile: %w", tx.Error)
}
return nil
}
// AddProperty adds a new property to the database
func (db *DB) AddProperty(property *orm.Property) error {
tx := db.Create(property)
if tx.Error != nil {
return fmt.Errorf("failed to add property: %w", tx.Error)
}
return nil
}
// GetProperty gets an property from the database
func (db *DB) GetProperty(property *orm.Property) error {
tx := db.First(property)
if tx.Error != nil {
return fmt.Errorf("failed to get property: %w", tx.Error)
}
return nil
}
// UpdateProperty updates an existing property in the database
func (db *DB) UpdateProperty(property *orm.Property) error {
tx := db.Save(property)
if tx.Error != nil {
return fmt.Errorf("failed to update property: %w", tx.Error)
}
return nil
}
// DeleteProperty deletes an existing property from the database
func (db *DB) DeleteProperty(property *orm.Property) error {
tx := db.Delete(property)
if tx.Error != nil {
return fmt.Errorf("failed to delete property: %w", tx.Error)
}
return nil
}

54
internal/db/database.go Normal file
View File

@ -0,0 +1,54 @@
package db
import (
"crypto/rand"
"github.com/ncruces/go-sqlite3/gormlite"
"golang.org/x/crypto/argon2"
"gorm.io/gorm"
"lukechampine.com/adiantum/hbsh"
"lukechampine.com/adiantum/hpolyc"
)
type DB struct {
*gorm.DB
}
func New(opts ...DBOption) (*DB, error) {
config := &DBConfig{
fileName: "vault.db",
}
for _, opt := range opts {
opt(config)
}
gormdb, err := gorm.Open(gormlite.Open(config.ConnectionString()))
if err != nil {
return nil, err
}
db, err := createInitialTables(gormdb)
if err != nil {
return nil, err
}
return db, nil
}
// HBSH creates an HBSH cipher given a key.
func (c *DB) HBSH(key []byte) *hbsh.HBSH {
if len(key) != 32 {
// Key is not appropriate, return nil.
return nil
}
return hpolyc.New(key)
}
// KDF gets a key from a secret.
func (c *DB) KDF(secret string) []byte {
if secret == "" {
// No secret is given, generate a random key.
key := make([]byte, 32)
n, _ := rand.Read(key)
return key[:n]
}
// Hash the secret with a KDF.
return argon2.IDKey([]byte(secret), []byte("hpolyc"), 3, 64*1024, 4, 32)
}

195
internal/db/handlers.go Normal file
View File

@ -0,0 +1,195 @@
package db
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/db/orm"
)
func (db *DB) ServeEcho(e *echo.Group) {
e.GET("/accounts", db.HandleAccount)
e.GET("/assets", db.HandleAsset)
e.GET("/credentials", db.HandleCredential)
e.GET("/keyshares", db.HandleKeyshare)
e.GET("/permissions", db.HandlePermission)
e.GET("/profiles", db.HandleProfile)
e.GET("/properties", db.HandleProperty)
}
func (db *DB) HandleAccount(c echo.Context) error {
data := new(orm.Account)
if err := c.Bind(data); err != nil {
return err
}
// Check the method for GET, POST, PUT, DELETE
switch c.Request().Method {
case echo.POST:
if err := db.AddAccount(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdateAccount(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeleteAccount(data); err != nil {
return err
}
return c.JSON(200, nil)
}
return c.JSON(200, data)
}
func (db *DB) HandleAsset(c echo.Context) error {
data := new(orm.Asset)
if err := c.Bind(data); err != nil {
return err
}
switch c.Request().Method {
case echo.POST:
if err := db.AddAsset(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdateAsset(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeleteAsset(data); err != nil {
return err
}
return c.JSON(200, "OK")
}
return c.JSON(200, data)
}
func (db *DB) HandleCredential(c echo.Context) error {
data := new(orm.Credential)
if err := c.Bind(data); err != nil {
return err
}
switch c.Request().Method {
case echo.POST:
if err := db.AddCredential(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdateCredential(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeleteCredential(data); err != nil {
return err
}
}
return c.JSON(200, data)
}
func (db *DB) HandleKeyshare(c echo.Context) error {
data := new(orm.Keyshare)
if err := c.Bind(data); err != nil {
return err
}
switch c.Request().Method {
case echo.POST:
if err := db.AddKeyshare(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdateKeyshare(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeleteKeyshare(data); err != nil {
return err
}
}
return c.JSON(200, data)
}
func (db *DB) HandlePermission(c echo.Context) error {
data := new(orm.Permission)
if err := c.Bind(data); err != nil {
return err
}
switch c.Request().Method {
case echo.POST:
if err := db.AddPermission(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdatePermission(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeletePermission(data); err != nil {
return err
}
}
return c.JSON(200, data)
}
func (db *DB) HandleProfile(c echo.Context) error {
data := new(orm.Profile)
if err := c.Bind(data); err != nil {
return err
}
switch c.Request().Method {
case echo.POST:
if err := db.AddProfile(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdateProfile(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeleteProfile(data); err != nil {
return err
}
}
return c.JSON(200, data)
}
func (db *DB) HandleProperty(c echo.Context) error {
data := new(orm.Property)
if err := c.Bind(data); err != nil {
return err
}
switch c.Request().Method {
case echo.POST:
if err := db.AddProperty(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.PUT:
if err := db.UpdateProperty(data); err != nil {
return err
}
return c.JSON(200, "OK")
case echo.DELETE:
if err := db.DeleteProperty(data); err != nil {
return err
}
}
return c.JSON(200, data)
}

131
internal/db/idb/idb.go Normal file
View File

@ -0,0 +1,131 @@
//go:build js && wasm
// +build js,wasm
package idb
import (
"context"
"encoding/json"
"errors"
"syscall/js"
"github.com/hack-pad/go-indexeddb/idb"
)
// Model is an interface that must be implemented by types used with Table
type Model interface {
Table() string
}
// Table is a generic wrapper around IDB for easier database operations on a specific table
type Table[T Model] struct {
db *idb.Database
dbName string
keyPath string
}
// NewTable creates a new Table instance
func NewTable[T Model](dbName string, version uint, keyPath string) (*Table[T], error) {
ctx := context.Background()
factory := idb.Global()
var model T
tableName := model.Table()
openRequest, err := factory.Open(ctx, dbName, version, func(db *idb.Database, oldVersion, newVersion uint) error {
_, err := db.CreateObjectStore(tableName, idb.ObjectStoreOptions{
KeyPath: js.ValueOf(keyPath),
})
return err
})
if err != nil {
return nil, err
}
db, err := openRequest.Await(ctx)
if err != nil {
return nil, err
}
return &Table[T]{
db: db,
dbName: dbName,
keyPath: keyPath,
}, nil
}
// Insert adds a new record to the table
func (t *Table[T]) Insert(data T) error {
tx, err := t.db.Transaction(idb.TransactionReadWrite, data.Table())
if err != nil {
return err
}
defer tx.Commit()
objectStore, err := tx.ObjectStore(data.Table())
if err != nil {
return err
}
jsonData, err := json.Marshal(data)
if err != nil {
return err
}
_, err = objectStore.Add(js.ValueOf(string(jsonData)))
return err
}
// Query retrieves a record from the table based on a key
func (t *Table[T]) Query(key interface{}) (T, error) {
var result T
tx, err := t.db.Transaction(idb.TransactionReadOnly, result.Table())
if err != nil {
return result, err
}
defer tx.Commit()
objectStore, err := tx.ObjectStore(result.Table())
if err != nil {
return result, err
}
request, err := objectStore.Get(js.ValueOf(key))
if err != nil {
return result, err
}
value, err := request.Await(context.Background())
if err != nil {
return result, err
}
if value.IsUndefined() || value.IsNull() {
return result, errors.New("record not found")
}
err = json.Unmarshal([]byte(value.String()), &result)
return result, err
}
// Delete removes a record from the table based on a key
func (t *Table[T]) Delete(key interface{}) error {
var model T
tx, err := t.db.Transaction(idb.TransactionReadWrite, model.Table())
if err != nil {
return err
}
defer tx.Commit()
objectStore, err := tx.ObjectStore(model.Table())
if err != nil {
return err
}
_, err = objectStore.Delete(js.ValueOf(key))
return err
}
// Close closes the database connection
func (t *Table[T]) Close() error {
return t.db.Close()
}

40
internal/db/options.go Normal file
View File

@ -0,0 +1,40 @@
package db
import (
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/onsonr/sonr/internal/db/orm"
)
type DBOption func(config *DBConfig)
func WitDir(dir string) DBOption {
return func(config *DBConfig) {
config.Dir = dir
}
}
func WithSecretKey(secretKey string) DBOption {
return func(config *DBConfig) {
config.SecretKey = secretKey
}
}
type DBConfig struct {
Dir string
SecretKey string
fileName string
initialAccounts []*orm.Account
initialAssets []*orm.Asset
initialCredentials []*orm.Credential
initialKeyshares []*orm.Keyshare
initialPermissions []*orm.Permission
initialProfiles []*orm.Profile
initialProperties []*orm.Property
}
func (config *DBConfig) ConnectionString() string {
connStr := "file:"
connStr += config.fileName
return connStr
}

View File

@ -0,0 +1,14 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Account struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
Name string `pkl:"name" json:"name,omitempty" param:"name"`
Address string `pkl:"address" json:"address,omitempty" param:"address"`
PublicKey string `pkl:"publicKey" json:"publicKey,omitempty" param:"publicKey"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
}

View File

@ -0,0 +1,16 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Asset struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
Name string `pkl:"name" json:"name,omitempty" param:"name"`
Symbol string `pkl:"symbol" json:"symbol,omitempty" param:"symbol"`
Decimals int `pkl:"decimals" json:"decimals,omitempty" param:"decimals"`
ChainId *int `pkl:"chainId" json:"chainId,omitempty" param:"chainId"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
}

View File

@ -0,0 +1,12 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Chain struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
Name string `pkl:"name" json:"name,omitempty" param:"name"`
NetworkId string `pkl:"networkId" json:"networkId,omitempty" param:"networkId"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
}

View File

@ -0,0 +1,36 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Credential struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
Subject string `pkl:"subject" json:"subject,omitempty" param:"subject"`
Controller string `pkl:"controller" json:"controller,omitempty" param:"controller"`
AttestationType string `pkl:"attestationType" json:"attestationType,omitempty" param:"attestationType"`
Origin string `pkl:"origin" json:"origin,omitempty" param:"origin"`
CredentialId string `pkl:"credentialId" json:"credentialId,omitempty" param:"credentialId"`
PublicKey string `pkl:"publicKey" json:"publicKey,omitempty" param:"publicKey"`
Transport string `pkl:"transport" json:"transport,omitempty" param:"transport"`
SignCount uint `pkl:"signCount" json:"signCount,omitempty" param:"signCount"`
UserPresent bool `pkl:"userPresent" json:"userPresent,omitempty" param:"userPresent"`
UserVerified bool `pkl:"userVerified" json:"userVerified,omitempty" param:"userVerified"`
BackupEligible bool `pkl:"backupEligible" json:"backupEligible,omitempty" param:"backupEligible"`
BackupState bool `pkl:"backupState" json:"backupState,omitempty" param:"backupState"`
CloneWarning bool `pkl:"cloneWarning" json:"cloneWarning,omitempty" param:"cloneWarning"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
UpdatedAt *string `pkl:"updatedAt" json:"updatedAt,omitempty" param:"updatedAt"`
}

View File

@ -0,0 +1,12 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Keyshare struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
Data string `pkl:"data" json:"data,omitempty" param:"data"`
Role int `pkl:"role" json:"role,omitempty" param:"role"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
}

View File

@ -0,0 +1,36 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
import (
"context"
"github.com/apple/pkl-go/pkl"
)
type Orm struct {
}
// LoadFromPath loads the pkl module at the given path and evaluates it into a Orm
func LoadFromPath(ctx context.Context, path string) (ret *Orm, err error) {
evaluator, err := pkl.NewEvaluator(ctx, pkl.PreconfiguredOptions)
if err != nil {
return nil, err
}
defer func() {
cerr := evaluator.Close()
if err == nil {
err = cerr
}
}()
ret, err = Load(ctx, evaluator, pkl.FileSource(path))
return ret, err
}
// Load loads the pkl module at the given source and evaluates it with the given evaluator into a Orm
func Load(ctx context.Context, evaluator pkl.Evaluator, source *pkl.ModuleSource) (*Orm, error) {
var ret Orm
if err := evaluator.EvaluateModule(ctx, source, &ret); err != nil {
return nil, err
}
return &ret, nil
}

View File

@ -0,0 +1,16 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Permission struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
ServiceId string `pkl:"serviceId" json:"serviceId,omitempty" param:"serviceId"`
Grants string `pkl:"grants" json:"grants,omitempty" param:"grants"`
Scopes string `pkl:"scopes" json:"scopes,omitempty" param:"scopes"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
UpdatedAt *string `pkl:"updatedAt" json:"updatedAt,omitempty" param:"updatedAt"`
}

View File

@ -0,0 +1,20 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Profile struct {
Id string `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
Subject string `pkl:"subject" json:"subject,omitempty" param:"subject"`
Controller string `pkl:"controller" json:"controller,omitempty" param:"controller"`
OriginUri *string `pkl:"originUri" json:"originUri,omitempty" param:"originUri"`
PublicMetadata *string `pkl:"publicMetadata" json:"publicMetadata,omitempty" param:"publicMetadata"`
PrivateMetadata *string `pkl:"privateMetadata" json:"privateMetadata,omitempty" param:"privateMetadata"`
CreatedAt *string `pkl:"createdAt" json:"createdAt,omitempty" param:"createdAt"`
UpdatedAt *string `pkl:"updatedAt" json:"updatedAt,omitempty" param:"updatedAt"`
}

View File

@ -0,0 +1,14 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
type Property struct {
Id uint `pkl:"id" gorm:"primaryKey,autoIncrement" json:"id,omitempty" query:"id"`
ProfileId string `pkl:"profileId" json:"profileId,omitempty" param:"profileId"`
Key string `pkl:"key" json:"key,omitempty" param:"key"`
Accumulator string `pkl:"accumulator" json:"accumulator,omitempty" param:"accumulator"`
PropertyKey string `pkl:"propertyKey" json:"propertyKey,omitempty" param:"propertyKey"`
}

View File

@ -0,0 +1,16 @@
// Code generated from Pkl module `orm`. DO NOT EDIT.
package orm
import "github.com/apple/pkl-go/pkl"
func init() {
pkl.RegisterMapping("orm", Orm{})
pkl.RegisterMapping("orm#Account", Account{})
pkl.RegisterMapping("orm#Asset", Asset{})
pkl.RegisterMapping("orm#Chain", Chain{})
pkl.RegisterMapping("orm#Credential", Credential{})
pkl.RegisterMapping("orm#Profile", Profile{})
pkl.RegisterMapping("orm#Property", Property{})
pkl.RegisterMapping("orm#Keyshare", Keyshare{})
pkl.RegisterMapping("orm#Permission", Permission{})
}

29
internal/db/orm/orm.go Normal file
View File

@ -0,0 +1,29 @@
package orm
func (a *Account) Table() string {
return "accounts"
}
func (a *Asset) Table() string {
return "assets"
}
func (a *Credential) Table() string {
return "credentials"
}
func (a *Keyshare) Table() string {
return "keyshares"
}
func (a *Permission) Table() string {
return "permissions"
}
func (a *Profile) Table() string {
return "profiles"
}
func (a *Property) Table() string {
return "properties"
}

View File

@ -0,0 +1,67 @@
package elements
func Alert(variant Variant, icon Icon, title, message string) templ.Component {
return alertElement(variant.Attributes(), title, message, icon.Render())
}
templ alertElement(attrs templ.Attributes, title, message string, icon templ.Component) {
<div { attrs... }>
@icon
<h5 class="mb-1 font-medium leading-none tracking-tight">{ title }</h5>
<div class="text-sm opacity-70">{ message }</div>
</div>
}
type AlertVariant int
const (
AlertVariant_Default AlertVariant = iota
AlertVariant_Info
AlertVariant_Error
AlertVariant_Success
AlertVariant_Warning
AlertVariant_Subtle_Info
AlertVariant_Subtle_Error
AlertVariant_Subtle_Success
AlertVariant_Subtle_Warning
)
func (v AlertVariant) Attributes() templ.Attributes {
switch v {
case AlertVariant_Info:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-blue-600 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Error:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-red-600 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Success:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-green-500 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Warning:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-yellow-500 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Subtle_Info:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-blue-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-blue-600",
}
case AlertVariant_Subtle_Error:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-red-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-red-600",
}
case AlertVariant_Subtle_Success:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-green-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-green-600",
}
case AlertVariant_Subtle_Warning:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-yellow-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-yellow-600",
}
}
return templ.Attributes{
"class": "relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-neutral-900",
}
}

View File

@ -0,0 +1,140 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Alert(variant Variant, icon Icon, title, message string) templ.Component {
return alertElement(variant.Attributes(), title, message, icon.Render())
}
func alertElement(attrs templ.Attributes, title, message string, icon templ.Component) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = icon.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h5 class=\"mb-1 font-medium leading-none tracking-tight\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/alert.templ`, Line: 10, Col: 66}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h5><div class=\"text-sm opacity-70\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(message)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/alert.templ`, Line: 11, Col: 43}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
type AlertVariant int
const (
AlertVariant_Default AlertVariant = iota
AlertVariant_Info
AlertVariant_Error
AlertVariant_Success
AlertVariant_Warning
AlertVariant_Subtle_Info
AlertVariant_Subtle_Error
AlertVariant_Subtle_Success
AlertVariant_Subtle_Warning
)
func (v AlertVariant) Attributes() templ.Attributes {
switch v {
case AlertVariant_Info:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-blue-600 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Error:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-red-600 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Success:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-green-500 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Warning:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-yellow-500 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-white",
}
case AlertVariant_Subtle_Info:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-blue-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-blue-600",
}
case AlertVariant_Subtle_Error:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-red-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-red-600",
}
case AlertVariant_Subtle_Success:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-green-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-green-600",
}
case AlertVariant_Subtle_Warning:
return templ.Attributes{
"class": "relative w-full rounded-lg border border-transparent bg-yellow-50 p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-yellow-600",
}
}
return templ.Attributes{
"class": "relative w-full rounded-lg border bg-white p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11 text-neutral-900",
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,5 @@
package elements
templ Animation() {
<lottie-player src="https://assets5.lottiefiles.com/packages/lf20_0c0a2a8a.json" background="transparent" speed="1" style="width: 100%; height: 100%;" loop autoplay></lottie-player>
}

View File

@ -0,0 +1,40 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Animation() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<lottie-player src=\"https://assets5.lottiefiles.com/packages/lf20_0c0a2a8a.json\" background=\"transparent\" speed=\"1\" style=\"width: 100%; height: 100%;\" loop autoplay></lottie-player>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,59 @@
package elements
templ PoweredBySonr() {
<div class="mx-auto w-fit pt-8">
<div class="pt-2 pb-3 pl-4 pr-4 gap-x-3 text-sm text-gray-500 border-t border-neutral-200/70">
<div
x-data="{
hoverCardHovered: false,
hoverCardDelay: 600,
hoverCardLeaveDelay: 500,
hoverCardTimout: null,
hoverCardLeaveTimeout: null,
hoverCardEnter () {
clearTimeout(this.hoverCardLeaveTimeout);
if(this.hoverCardHovered) return;
clearTimeout(this.hoverCardTimout);
this.hoverCardTimout = setTimeout(() => {
this.hoverCardHovered = true;
}, this.hoverCardDelay);
},
hoverCardLeave () {
clearTimeout(this.hoverCardTimout);
if(!this.hoverCardHovered) return;
clearTimeout(this.hoverCardLeaveTimeout);
this.hoverCardLeaveTimeout = setTimeout(() => {
this.hoverCardHovered = false;
}, this.hoverCardLeaveDelay);
}
}"
class="relative"
@mouseover="hoverCardEnter()"
@mouseleave="hoverCardLeave()"
>
<span class="bg-transparent text-gray-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full">
<span class="mr-1">Powered by </span>
<svg class="w-3 h-3" width="164" height="164" viewBox="0 0 164 164" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M71.8077 133.231C74.5054 135.928 78.1636 137.443 81.978 137.443C85.7924 137.443 89.4506 135.928 92.1483 133.231L133.219 92.1638C135.909 89.4654 137.42 85.8102 137.42 81.9998C137.42 78.1895 135.909 74.5345 133.219 71.8361L112.886 51.5272L131.665 32.7499L152.031 53.1143C159.696 60.7963 164 71.2046 164 82.0559C164 92.9072 159.696 103.315 152.031 110.997L110.95 152.065C107.154 155.869 102.642 158.883 97.6739 160.931C92.7059 162.98 87.3809 164.023 82.0071 164L82.0052 164C76.622 164.019 71.2886 162.969 66.3145 160.91C61.3405 158.852 56.8247 155.826 53.0294 152.009L53.0289 152.008L48.7187 147.699L67.4974 128.921L71.8077 133.231Z" fill="currentColor"></path>
<path d="M110.95 11.9912L115.26 16.3011L96.481 35.0785L92.1707 30.7685C89.4731 28.072 85.8148 26.5572 82.0004 26.5572C78.186 26.5572 74.5277 28.072 71.8301 30.7685L30.7597 71.8359C29.4247 73.1706 28.3658 74.7552 27.6433 76.4991C26.9208 78.2431 26.549 80.1122 26.549 81.9999C26.549 83.8876 26.9208 85.7567 27.6433 87.5007C28.3658 89.2446 29.4247 90.8292 30.7597 92.1639L51.1256 112.528L32.3138 131.306L11.9923 110.941C8.19043 107.141 5.17433 102.629 3.1167 97.6635C1.05907 92.6976 0 87.3751 0 81.9999C0 76.6247 1.05907 71.3022 3.1167 66.3363C5.17433 61.3705 8.19021 56.8587 11.9921 53.0586L53.0625 11.9912C56.8629 8.18964 61.3751 5.17395 66.3413 3.11647C71.3075 1.05899 76.6304 0 82.006 0C87.3816 0 92.7045 1.05899 97.6707 3.11647C102.637 5.17395 107.149 8.18964 110.95 11.9912Z" fill="currentColor"></path>
<path d="M55.603 76.6744L76.6993 55.5798C79.6327 52.6465 84.3888 52.6465 87.3223 55.5797L108.419 76.6744C111.352 79.6077 111.352 84.3634 108.419 87.2966L87.3223 108.391C84.3888 111.325 79.6327 111.325 76.6993 108.391L55.603 87.2966C52.6696 84.3634 52.6696 79.6077 55.603 76.6744Z" fill="currentColor"></path>
</svg>
</span>
<div x-show="hoverCardHovered" class="absolute top-0 w-[365px] max-w-lg mt-5 z-30 -translate-x-1/2 translate-y-3 left-1/2" x-cloak>
<div x-show="hoverCardHovered" class="w-[full] h-auto bg-white space-x-3 p-5 flex items-start rounded-md shadow-sm border border-neutral-200/70" x-transition>
<img src="https://cdn.sonr.io/logo.svg" alt="sonr image" class="rounded-full w-14 h-14"/>
<div class="relative">
<p class="mb-1 text-sm text-gray-600">The creative platform for developers. Community, tools, products, and more</p>
<p class="flex items-center space-x-1 text-xs text-gray-400">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z"></path>
</svg>
<span>Joined June 2020</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
}

View File

@ -0,0 +1,40 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func PoweredBySonr() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"mx-auto w-fit pt-8\"><div class=\"pt-2 pb-3 pl-4 pr-4 gap-x-3 text-sm text-gray-500 border-t border-neutral-200/70\"><div x-data=\"{ \n hoverCardHovered: false,\n hoverCardDelay: 600,\n hoverCardLeaveDelay: 500,\n hoverCardTimout: null,\n hoverCardLeaveTimeout: null,\n hoverCardEnter () {\n clearTimeout(this.hoverCardLeaveTimeout);\n if(this.hoverCardHovered) return;\n clearTimeout(this.hoverCardTimout);\n this.hoverCardTimout = setTimeout(() =&gt; {\n this.hoverCardHovered = true;\n }, this.hoverCardDelay);\n },\n hoverCardLeave () {\n clearTimeout(this.hoverCardTimout);\n if(!this.hoverCardHovered) return;\n clearTimeout(this.hoverCardLeaveTimeout);\n this.hoverCardLeaveTimeout = setTimeout(() =&gt; {\n this.hoverCardHovered = false;\n }, this.hoverCardLeaveDelay);\n }\n }\" class=\"relative\" @mouseover=\"hoverCardEnter()\" @mouseleave=\"hoverCardLeave()\"><span class=\"bg-transparent text-gray-500 border border-neutral-300 flex items-center text-xs font-semibold px-2.5 py-0.5 rounded-full\"><span class=\"mr-1\">Powered by </span> <svg class=\"w-3 h-3\" width=\"164\" height=\"164\" viewBox=\"0 0 164 164\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M71.8077 133.231C74.5054 135.928 78.1636 137.443 81.978 137.443C85.7924 137.443 89.4506 135.928 92.1483 133.231L133.219 92.1638C135.909 89.4654 137.42 85.8102 137.42 81.9998C137.42 78.1895 135.909 74.5345 133.219 71.8361L112.886 51.5272L131.665 32.7499L152.031 53.1143C159.696 60.7963 164 71.2046 164 82.0559C164 92.9072 159.696 103.315 152.031 110.997L110.95 152.065C107.154 155.869 102.642 158.883 97.6739 160.931C92.7059 162.98 87.3809 164.023 82.0071 164L82.0052 164C76.622 164.019 71.2886 162.969 66.3145 160.91C61.3405 158.852 56.8247 155.826 53.0294 152.009L53.0289 152.008L48.7187 147.699L67.4974 128.921L71.8077 133.231Z\" fill=\"currentColor\"></path> <path d=\"M110.95 11.9912L115.26 16.3011L96.481 35.0785L92.1707 30.7685C89.4731 28.072 85.8148 26.5572 82.0004 26.5572C78.186 26.5572 74.5277 28.072 71.8301 30.7685L30.7597 71.8359C29.4247 73.1706 28.3658 74.7552 27.6433 76.4991C26.9208 78.2431 26.549 80.1122 26.549 81.9999C26.549 83.8876 26.9208 85.7567 27.6433 87.5007C28.3658 89.2446 29.4247 90.8292 30.7597 92.1639L51.1256 112.528L32.3138 131.306L11.9923 110.941C8.19043 107.141 5.17433 102.629 3.1167 97.6635C1.05907 92.6976 0 87.3751 0 81.9999C0 76.6247 1.05907 71.3022 3.1167 66.3363C5.17433 61.3705 8.19021 56.8587 11.9921 53.0586L53.0625 11.9912C56.8629 8.18964 61.3751 5.17395 66.3413 3.11647C71.3075 1.05899 76.6304 0 82.006 0C87.3816 0 92.7045 1.05899 97.6707 3.11647C102.637 5.17395 107.149 8.18964 110.95 11.9912Z\" fill=\"currentColor\"></path> <path d=\"M55.603 76.6744L76.6993 55.5798C79.6327 52.6465 84.3888 52.6465 87.3223 55.5797L108.419 76.6744C111.352 79.6077 111.352 84.3634 108.419 87.2966L87.3223 108.391C84.3888 111.325 79.6327 111.325 76.6993 108.391L55.603 87.2966C52.6696 84.3634 52.6696 79.6077 55.603 76.6744Z\" fill=\"currentColor\"></path></svg></span><div x-show=\"hoverCardHovered\" class=\"absolute top-0 w-[365px] max-w-lg mt-5 z-30 -translate-x-1/2 translate-y-3 left-1/2\" x-cloak><div x-show=\"hoverCardHovered\" class=\"w-[full] h-auto bg-white space-x-3 p-5 flex items-start rounded-md shadow-sm border border-neutral-200/70\" x-transition><img src=\"https://cdn.sonr.io/logo.svg\" alt=\"sonr image\" class=\"rounded-full w-14 h-14\"><div class=\"relative\"><p class=\"mb-1 text-sm text-gray-600\">The creative platform for developers. Community, tools, products, and more</p><p class=\"flex items-center space-x-1 text-xs text-gray-400\"><svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-5 h-5\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 012.25-2.25h13.5A2.25 2.25 0 0121 7.5v11.25m-18 0A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75m-18 0v-7.5A2.25 2.25 0 015.25 9h13.5A2.25 2.25 0 0121 11.25v7.5m-9-6h.008v.008H12v-.008zM12 15h.008v.008H12V15zm0 2.25h.008v.008H12v-.008zM9.75 15h.008v.008H9.75V15zm0 2.25h.008v.008H9.75v-.008zM7.5 15h.008v.008H7.5V15zm0 2.25h.008v.008H7.5v-.008zm6.75-4.5h.008v.008h-.008v-.008zm0 2.25h.008v.008h-.008V15zm0 2.25h.008v.008h-.008v-.008zm2.25-4.5h.008v.008H16.5v-.008zm0 2.25h.008v.008H16.5V15z\"></path></svg> <span>Joined June 2020</span></p></div></div></div></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,35 @@
package elements
templ Breadcrumbs() {
<nav class="flex justify-between px-3.5 py-1 rounded-md pb-3">
<ol class="inline-flex items-center mb-3 space-x-1 text-xs text-neutral-500 [&_.active-breadcrumb]:text-neutral-600 [&_.active-breadcrumb]:font-medium sm:mb-0">
<li class="flex items-center h-full">
<a href="#_" class="py-1 hover:text-neutral-900">
@breadcrumbIcon()
</a>
</li>
<svg class="w-5 h-5 text-gray-400/70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
@breadcrumbItem("Policy", false)
<svg class="w-5 h-5 text-gray-400/70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
@breadcrumbItem("About You", true)
<svg class="w-5 h-5 text-gray-400/70" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="none"><path d="M10 8.013l4 4-4 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g></svg>
@breadcrumbItem("Generate", false)
</ol>
</nav>
}
templ breadcrumbItem(title string, active bool) {
if (active) {
<li><a class="inline-flex items-center py-1 font-normal rounded cursor-default active-breadcrumb focus:outline-none">{ title }</a></li>
} else {
<li><a href="#_" class="inline-flex items-center py-1 font-normal hover:text-neutral-900 focus:outline-none">{ title }</a></li>
}
}
templ breadcrumbIcon() {
<svg class="w-4 w-4" viewBox="0 0 164 164" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M71.8077 133.231C74.5054 135.928 78.1636 137.443 81.978 137.443C85.7924 137.443 89.4506 135.928 92.1483 133.231L133.219 92.1638C135.909 89.4654 137.42 85.8102 137.42 81.9998C137.42 78.1895 135.909 74.5345 133.219 71.8361L112.886 51.5272L131.665 32.7499L152.031 53.1143C159.696 60.7963 164 71.2046 164 82.0559C164 92.9072 159.696 103.315 152.031 110.997L110.95 152.065C107.154 155.869 102.642 158.883 97.6739 160.931C92.7059 162.98 87.3809 164.023 82.0071 164L82.0052 164C76.622 164.019 71.2886 162.969 66.3145 160.91C61.3405 158.852 56.8247 155.826 53.0294 152.009L53.0289 152.008L48.7187 147.699L67.4974 128.921L71.8077 133.231Z" fill="currentColor"></path>
<path d="M110.95 11.9912L115.26 16.3011L96.481 35.0785L92.1707 30.7685C89.4731 28.072 85.8148 26.5572 82.0004 26.5572C78.186 26.5572 74.5277 28.072 71.8301 30.7685L30.7597 71.8359C29.4247 73.1706 28.3658 74.7552 27.6433 76.4991C26.9208 78.2431 26.549 80.1122 26.549 81.9999C26.549 83.8876 26.9208 85.7567 27.6433 87.5007C28.3658 89.2446 29.4247 90.8292 30.7597 92.1639L51.1256 112.528L32.3138 131.306L11.9923 110.941C8.19043 107.141 5.17433 102.629 3.1167 97.6635C1.05907 92.6976 0 87.3751 0 81.9999C0 76.6247 1.05907 71.3022 3.1167 66.3363C5.17433 61.3705 8.19021 56.8587 11.9921 53.0586L53.0625 11.9912C56.8629 8.18964 61.3751 5.17395 66.3413 3.11647C71.3075 1.05899 76.6304 0 82.006 0C87.3816 0 92.7045 1.05899 97.6707 3.11647C102.637 5.17395 107.149 8.18964 110.95 11.9912Z" fill="currentColor"></path>
<path d="M55.603 76.6744L76.6993 55.5798C79.6327 52.6465 84.3888 52.6465 87.3223 55.5797L108.419 76.6744C111.352 79.6077 111.352 84.3634 108.419 87.2966L87.3223 108.391C84.3888 111.325 79.6327 111.325 76.6993 108.391L55.603 87.2966C52.6696 84.3634 52.6696 79.6077 55.603 76.6744Z" fill="currentColor"></path>
</svg>
}

View File

@ -0,0 +1,163 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Breadcrumbs() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<nav class=\"flex justify-between px-3.5 py-1 rounded-md pb-3\"><ol class=\"inline-flex items-center mb-3 space-x-1 text-xs text-neutral-500 [&amp;_.active-breadcrumb]:text-neutral-600 [&amp;_.active-breadcrumb]:font-medium sm:mb-0\"><li class=\"flex items-center h-full\"><a href=\"#_\" class=\"py-1 hover:text-neutral-900\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumbIcon().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li><svg class=\"w-5 h-5 text-gray-400/70\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><g fill=\"none\" stroke=\"none\"><path d=\"M10 8.013l4 4-4 4\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></g></svg>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumbItem("Policy", false).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-5 h-5 text-gray-400/70\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><g fill=\"none\" stroke=\"none\"><path d=\"M10 8.013l4 4-4 4\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></g></svg>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumbItem("About You", true).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-5 h-5 text-gray-400/70\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><g fill=\"none\" stroke=\"none\"><path d=\"M10 8.013l4 4-4 4\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"></path></g></svg>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = breadcrumbItem("Generate", false).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</ol></nav>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func breadcrumbItem(title string, active bool) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
if active {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<li><a class=\"inline-flex items-center py-1 font-normal rounded cursor-default active-breadcrumb focus:outline-none\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/breadcrumbs.templ`, Line: 23, Col: 126}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<li><a href=\"#_\" class=\"inline-flex items-center py-1 font-normal hover:text-neutral-900 focus:outline-none\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/breadcrumbs.templ`, Line: 25, Col: 118}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return templ_7745c5c3_Err
})
}
func breadcrumbIcon() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-4 w-4\" viewBox=\"0 0 164 164\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M71.8077 133.231C74.5054 135.928 78.1636 137.443 81.978 137.443C85.7924 137.443 89.4506 135.928 92.1483 133.231L133.219 92.1638C135.909 89.4654 137.42 85.8102 137.42 81.9998C137.42 78.1895 135.909 74.5345 133.219 71.8361L112.886 51.5272L131.665 32.7499L152.031 53.1143C159.696 60.7963 164 71.2046 164 82.0559C164 92.9072 159.696 103.315 152.031 110.997L110.95 152.065C107.154 155.869 102.642 158.883 97.6739 160.931C92.7059 162.98 87.3809 164.023 82.0071 164L82.0052 164C76.622 164.019 71.2886 162.969 66.3145 160.91C61.3405 158.852 56.8247 155.826 53.0294 152.009L53.0289 152.008L48.7187 147.699L67.4974 128.921L71.8077 133.231Z\" fill=\"currentColor\"></path> <path d=\"M110.95 11.9912L115.26 16.3011L96.481 35.0785L92.1707 30.7685C89.4731 28.072 85.8148 26.5572 82.0004 26.5572C78.186 26.5572 74.5277 28.072 71.8301 30.7685L30.7597 71.8359C29.4247 73.1706 28.3658 74.7552 27.6433 76.4991C26.9208 78.2431 26.549 80.1122 26.549 81.9999C26.549 83.8876 26.9208 85.7567 27.6433 87.5007C28.3658 89.2446 29.4247 90.8292 30.7597 92.1639L51.1256 112.528L32.3138 131.306L11.9923 110.941C8.19043 107.141 5.17433 102.629 3.1167 97.6635C1.05907 92.6976 0 87.3751 0 81.9999C0 76.6247 1.05907 71.3022 3.1167 66.3363C5.17433 61.3705 8.19021 56.8587 11.9921 53.0586L53.0625 11.9912C56.8629 8.18964 61.3751 5.17395 66.3413 3.11647C71.3075 1.05899 76.6304 0 82.006 0C87.3816 0 92.7045 1.05899 97.6707 3.11647C102.637 5.17395 107.149 8.18964 110.95 11.9912Z\" fill=\"currentColor\"></path> <path d=\"M55.603 76.6744L76.6993 55.5798C79.6327 52.6465 84.3888 52.6465 87.3223 55.5797L108.419 76.6744C111.352 79.6077 111.352 84.3634 108.419 87.2966L87.3223 108.391C84.3888 111.325 79.6327 111.325 76.6993 108.391L55.603 87.2966C52.6696 84.3634 52.6696 79.6077 55.603 76.6744Z\" fill=\"currentColor\"></path></svg>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,218 @@
package elements
type button struct {
variant Variant
hxGet string
hxPost string
hxTarget string
hxTrigger string
hxSwap string
}
type ButtonOpt func(button *button)
func PrimaryButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantPrimary
}
}
func InfoButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantInfo
}
}
func ErrorButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantError
}
}
func SuccessButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantSuccess
}
}
func WarningButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantWarning
}
}
func GET(action string, target string) ButtonOpt {
return func(button *button) {
button.hxGet = action
button.hxTarget = target
button.hxTrigger = "click"
button.hxSwap = "outerHTML"
}
}
func POST(action string, target string) ButtonOpt {
return func(button *button) {
button.hxPost = action
button.hxTarget = target
button.hxTrigger = "click"
button.hxSwap = "outerHTML"
}
}
func Button(opts ...ButtonOpt) templ.Component {
button := button{
variant: ButtonVariantDefault,
}
for _, opt := range opts {
opt(&button)
}
if button.hxGet != "" {
return renderHxGetButton(&button, button.variant.Attributes())
}
if button.hxPost != "" {
return renderHxPostButton(&button, button.variant.Attributes())
}
return renderButton(button.variant.Attributes())
}
templ renderButton(attrs templ.Attributes) {
<button { attrs... }>
{ children... }
</button>
}
templ renderHxGetButton(c *button, attrs templ.Attributes) {
<button hx-get={ c.hxGet } hx-push-url="true" hx-target={ c.hxTarget } hx-trigger={ c.hxTrigger } hx-swap={ c.hxSwap } { attrs... }>
{ children... }
</button>
}
templ renderHxPostButton(c *button, attrs templ.Attributes) {
<button hx-post={ c.hxPost } hx-target={ c.hxTarget } hx-trigger={ c.hxTrigger } hx-swap={ c.hxSwap } { attrs... }>
{ children... }
</button>
}
type ButtonVariant int
const (
ButtonVariantDefault ButtonVariant = iota
ButtonVariantPrimary
ButtonVariantInfo
ButtonVariantError
ButtonVariantSuccess
ButtonVariantWarning
)
func (v ButtonVariant) Attributes() templ.Attributes {
switch v {
case ButtonVariantPrimary:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantInfo:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantError:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-red-600 hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantSuccess:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-green-600 hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantWarning:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-yellow-600 hover:bg-yellow-700 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
}
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline",
"type": "button",
}
}
type SubtleButtonVariant int
const (
SubtleButtonVariantDefault SubtleButtonVariant = iota
SubtleButtonVariantInfo
SubtleButtonVariantError
SubtleButtonVariantSuccess
SubtleButtonVariantWarning
)
func (v SubtleButtonVariant) Attributes() templ.Attributes {
switch v {
case SubtleButtonVariantInfo:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100",
"type": "button",
}
case SubtleButtonVariantError:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100",
"type": "button",
}
case SubtleButtonVariantSuccess:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100",
"type": "button",
}
case SubtleButtonVariantWarning:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100",
"type": "button",
}
}
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100",
"type": "button",
}
}
type OutlineButtonVariant int
const (
OutlineButtonVariantDefault OutlineButtonVariant = iota
OutlineButtonVariantInfo
OutlineButtonVariantError
OutlineButtonVariantSuccess
OutlineButtonVariantWarning
)
func (v OutlineButtonVariant) Attributes() templ.Attributes {
switch v {
case OutlineButtonVariantInfo:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-600 transition-colors duration-100 bg-white border-2 border-blue-600 rounded-md hover:text-white hover:bg-blue-600",
"type": "button",
}
case OutlineButtonVariantError:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-600 transition-colors duration-100 bg-white border-2 border-red-600 rounded-md hover:text-white hover:bg-red-600",
"type": "button",
}
case OutlineButtonVariantSuccess:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-600 transition-colors duration-100 bg-white border-2 border-green-600 rounded-md hover:text-white hover:bg-green-600",
"type": "button",
}
case OutlineButtonVariantWarning:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 bg-white border-2 border-yellow-500 rounded-md hover:text-white hover:bg-yellow-500",
"type": "button",
}
}
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 bg-white border-2 rounded-md text-neutral-900 hover:text-white border-neutral-900 hover:bg-neutral-900",
"type": "button",
}
}

View File

@ -0,0 +1,449 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
type button struct {
variant Variant
hxGet string
hxPost string
hxTarget string
hxTrigger string
hxSwap string
}
type ButtonOpt func(button *button)
func PrimaryButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantPrimary
}
}
func InfoButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantInfo
}
}
func ErrorButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantError
}
}
func SuccessButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantSuccess
}
}
func WarningButtonStyle() ButtonOpt {
return func(button *button) {
button.variant = ButtonVariantWarning
}
}
func GET(action string, target string) ButtonOpt {
return func(button *button) {
button.hxGet = action
button.hxTarget = target
button.hxTrigger = "click"
button.hxSwap = "outerHTML"
}
}
func POST(action string, target string) ButtonOpt {
return func(button *button) {
button.hxPost = action
button.hxTarget = target
button.hxTrigger = "click"
button.hxSwap = "outerHTML"
}
}
func Button(opts ...ButtonOpt) templ.Component {
button := button{
variant: ButtonVariantDefault,
}
for _, opt := range opts {
opt(&button)
}
if button.hxGet != "" {
return renderHxGetButton(&button, button.variant.Attributes())
}
if button.hxPost != "" {
return renderHxPostButton(&button, button.variant.Attributes())
}
return renderButton(button.variant.Attributes())
}
func renderButton(attrs templ.Attributes) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func renderHxGetButton(c *button, attrs templ.Attributes) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button hx-get=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxGet)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 86, Col: 25}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-push-url=\"true\" hx-target=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxTarget)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 86, Col: 69}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-trigger=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxTrigger)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 86, Col: 96}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-swap=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var6 string
templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxSwap)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 86, Col: 117}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var2.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func renderHxPostButton(c *button, attrs templ.Attributes) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<button hx-post=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxPost)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 92, Col: 27}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-target=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxTarget)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 92, Col: 52}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-trigger=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var10 string
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxTrigger)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 92, Col: 79}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-swap=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(c.hxSwap)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/button.templ`, Line: 92, Col: 100}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var7.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</button>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
type ButtonVariant int
const (
ButtonVariantDefault ButtonVariant = iota
ButtonVariantPrimary
ButtonVariantInfo
ButtonVariantError
ButtonVariantSuccess
ButtonVariantWarning
)
func (v ButtonVariant) Attributes() templ.Attributes {
switch v {
case ButtonVariantPrimary:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-neutral-950 hover:bg-neutral-900 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-900 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantInfo:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 bg-blue-600 rounded-md hover:bg-blue-700 focus:ring-2 focus:ring-offset-2 focus:ring-blue-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantError:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-red-600 hover:bg-red-700 focus:ring-2 focus:ring-offset-2 focus:ring-red-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantSuccess:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-green-600 hover:bg-green-700 focus:ring-2 focus:ring-offset-2 focus:ring-green-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
case ButtonVariantWarning:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-white transition-colors duration-200 rounded-md bg-yellow-600 hover:bg-yellow-700 focus:ring-2 focus:ring-offset-2 focus:ring-yellow-700 focus:shadow-outline focus:outline-none",
"type": "button",
}
}
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-200 bg-white border rounded-md text-neutral-500 hover:text-neutral-700 border-neutral-200/70 hover:bg-neutral-100 active:bg-white focus:bg-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-200/60 focus:shadow-outline",
"type": "button",
}
}
type SubtleButtonVariant int
const (
SubtleButtonVariantDefault SubtleButtonVariant = iota
SubtleButtonVariantInfo
SubtleButtonVariantError
SubtleButtonVariantSuccess
SubtleButtonVariantWarning
)
func (v SubtleButtonVariant) Attributes() templ.Attributes {
switch v {
case SubtleButtonVariantInfo:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-blue-100 bg-blue-50 hover:text-blue-600 hover:bg-blue-100",
"type": "button",
}
case SubtleButtonVariantError:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-red-100 bg-red-50 hover:text-red-600 hover:bg-red-100",
"type": "button",
}
case SubtleButtonVariantSuccess:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-500 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-green-100 bg-green-50 hover:text-green-600 hover:bg-green-100",
"type": "button",
}
case SubtleButtonVariantWarning:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 rounded-md focus:ring-2 focus:ring-offset-2 focus:ring-yellow-100 bg-yellow-50 hover:text-yellow-700 hover:bg-yellow-100",
"type": "button",
}
}
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 rounded-md text-neutral-500 bg-neutral-50 focus:ring-2 focus:ring-offset-2 focus:ring-neutral-100 hover:text-neutral-600 hover:bg-neutral-100",
"type": "button",
}
}
type OutlineButtonVariant int
const (
OutlineButtonVariantDefault OutlineButtonVariant = iota
OutlineButtonVariantInfo
OutlineButtonVariantError
OutlineButtonVariantSuccess
OutlineButtonVariantWarning
)
func (v OutlineButtonVariant) Attributes() templ.Attributes {
switch v {
case OutlineButtonVariantInfo:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-blue-600 transition-colors duration-100 bg-white border-2 border-blue-600 rounded-md hover:text-white hover:bg-blue-600",
"type": "button",
}
case OutlineButtonVariantError:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-red-600 transition-colors duration-100 bg-white border-2 border-red-600 rounded-md hover:text-white hover:bg-red-600",
"type": "button",
}
case OutlineButtonVariantSuccess:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-green-600 transition-colors duration-100 bg-white border-2 border-green-600 rounded-md hover:text-white hover:bg-green-600",
"type": "button",
}
case OutlineButtonVariantWarning:
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide text-yellow-600 transition-colors duration-100 bg-white border-2 border-yellow-500 rounded-md hover:text-white hover:bg-yellow-500",
"type": "button",
}
}
return templ.Attributes{
"class": "inline-flex items-center justify-center px-4 py-2 text-sm font-medium tracking-wide transition-colors duration-100 bg-white border-2 rounded-md text-neutral-900 hover:text-white border-neutral-900 hover:bg-neutral-900",
"type": "button",
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,47 @@
package elements
func Card(id string, size Size) templ.Component {
return renderCard(id, size.CardAttributes())
}
templ renderCard(id string, attrs templ.Attributes) {
<div id={ id } { attrs... }>
<div class="w-full h-full">
<div class="row">
<div class="col-md-12 space-3">
{ children... }
</div>
</div>
</div>
</div>
}
templ ProfileCard() {
<div class="relative max-w-sm overflow-hidden bg-white border rounded-lg shadow-sm border-neutral-200/60">
<img src="https://cdn.devdojo.com/images/august2023/wallpaper.jpeg" class="relative z-20 object-cover w-full h-32"/>
<div class="absolute top-0 z-50 flex items-center w-full mt-2 translate-y-24 px-7 -translate-x-0">
<div class="w-20 h-20 p-1 bg-white rounded-full">
<img src="https://cdn.devdojo.com/images/august2023/adam.jpeg" class="w-full h-full rounded-full"/>
</div>
<a href="https://twitter.com/adamwathan" target="_blank" class="block mt-6 ml-2">
<h5 class="text-lg font-bold leading-none tracking-tight text-neutral-900">Adam Wathan</h5>
<small class="block mt-1 text-sm font-medium leading-none text-neutral-500">adamwathan</small>
</a>
<button class="absolute right-0 inline-flex items-center justify-center w-auto px-5 mt-6 text-sm font-medium transition-colors duration-100 rounded-full h-9 mr-7 hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 bg-neutral-900 disabled:pointer-events-none hover:bg-neutral-800 text-neutral-100">
<span>Follow</span>
</button>
</div>
<div class="relative pb-6 p-7">
<p class="mt-12 mb-6 text-neutral-500 text-">Creator of @tailwindcss. Listener of Slayer. Austin 3:16. BTW, Pines UI is super cool!</p>
<div class="flex items-center justify-between pr-2 text-neutral-500">
<div class="relative flex w-16">
<img src="https://cdn.devdojo.com/images/august2023/caleb.jpeg" class="relative z-30 w-8 h-8 border-2 border-white rounded-full"/>
<img src="https://cdn.devdojo.com/images/august2023/taylor.jpeg" class="z-20 w-8 h-8 -translate-x-4 border-2 border-white rounded-full"/>
<img src="https://cdn.devdojo.com/images/august2023/adam.jpeg" class="z-10 w-8 h-8 border-2 border-white rounded-full -translate-x-7"/>
</div>
<a href="https://twitter.com/adamwathan/following" target="_blank" class="text-sm hover:underline"><strong class="text-neutral-800">673</strong> Following</a>
<a href="https://twitter.com/adamwathan/followers" target="_blank" class="text-sm hover:underline"><strong class="text-neutral-800">168.6K</strong> Followers</a>
</div>
</div>
</div>
}

View File

@ -0,0 +1,102 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Card(id string, size Size) templ.Component {
return renderCard(id, size.CardAttributes())
}
func renderCard(id string, attrs templ.Attributes) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div id=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(id)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/card.templ`, Line: 8, Col: 13}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("><div class=\"w-full h-full\"><div class=\"row\"><div class=\"col-md-12 space-3\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func ProfileCard() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
if templ_7745c5c3_Var3 == nil {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"relative max-w-sm overflow-hidden bg-white border rounded-lg shadow-sm border-neutral-200/60\"><img src=\"https://cdn.devdojo.com/images/august2023/wallpaper.jpeg\" class=\"relative z-20 object-cover w-full h-32\"><div class=\"absolute top-0 z-50 flex items-center w-full mt-2 translate-y-24 px-7 -translate-x-0\"><div class=\"w-20 h-20 p-1 bg-white rounded-full\"><img src=\"https://cdn.devdojo.com/images/august2023/adam.jpeg\" class=\"w-full h-full rounded-full\"></div><a href=\"https://twitter.com/adamwathan\" target=\"_blank\" class=\"block mt-6 ml-2\"><h5 class=\"text-lg font-bold leading-none tracking-tight text-neutral-900\">Adam Wathan</h5><small class=\"block mt-1 text-sm font-medium leading-none text-neutral-500\">adamwathan</small></a> <button class=\"absolute right-0 inline-flex items-center justify-center w-auto px-5 mt-6 text-sm font-medium transition-colors duration-100 rounded-full h-9 mr-7 hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 bg-neutral-900 disabled:pointer-events-none hover:bg-neutral-800 text-neutral-100\"><span>Follow</span></button></div><div class=\"relative pb-6 p-7\"><p class=\"mt-12 mb-6 text-neutral-500 text-\">Creator of @tailwindcss. Listener of Slayer. Austin 3:16. BTW, Pines UI is super cool!</p><div class=\"flex items-center justify-between pr-2 text-neutral-500\"><div class=\"relative flex w-16\"><img src=\"https://cdn.devdojo.com/images/august2023/caleb.jpeg\" class=\"relative z-30 w-8 h-8 border-2 border-white rounded-full\"> <img src=\"https://cdn.devdojo.com/images/august2023/taylor.jpeg\" class=\"z-20 w-8 h-8 -translate-x-4 border-2 border-white rounded-full\"> <img src=\"https://cdn.devdojo.com/images/august2023/adam.jpeg\" class=\"z-10 w-8 h-8 border-2 border-white rounded-full -translate-x-7\"></div><a href=\"https://twitter.com/adamwathan/following\" target=\"_blank\" class=\"text-sm hover:underline\"><strong class=\"text-neutral-800\">673</strong> Following</a> <a href=\"https://twitter.com/adamwathan/followers\" target=\"_blank\" class=\"text-sm hover:underline\"><strong class=\"text-neutral-800\">168.6K</strong> Followers</a></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,47 @@
package elements
import (
"strings"
"github.com/a-h/templ"
)
type Icon interface {
Render() templ.Component
}
type Variant interface {
Attributes() templ.Attributes
}
func clsxMerge(variants ...Variant) templ.Attributes {
combinedAttrs := templ.Attributes{}
var classElements []string
for _, variant := range variants {
attrs := variant.Attributes()
if class, ok := attrs["class"].(string); ok {
classElements = append(classElements, strings.Fields(class)...)
}
for key, value := range attrs {
if key != "class" {
combinedAttrs[key] = value
}
}
}
if len(classElements) > 0 {
combinedAttrs["class"] = strings.Join(classElements, " ")
}
return combinedAttrs
}
func clsxBuilder(classes ...string) templ.Attributes {
if len(classes) == 0 {
return templ.Attributes{}
}
class := strings.Join(classes, " ")
return templ.Attributes{
"class": class,
}
}

View File

@ -0,0 +1,62 @@
package elements
func H1(content string) templ.Component {
return renderText(1, content)
}
func H2(content string) templ.Component {
return renderText(2, content)
}
func H3(content string) templ.Component {
return renderText(3, content)
}
func Text(content string) templ.Component {
return renderText(0, content)
}
templ renderText(level int, text string) {
switch level {
case 1:
<h1 class="text-2xl lg:text-3xl font-bold">
{ text }
</h1>
case 2:
<h2 class="text-xl lg:text-2xl font-bold">
{ text }
</h2>
case 3:
<h3 class="text-md lg:text-xl font-semibold">
{ text }
</h3>
default:
<p class="text-base font-normal">
{ text }
</p>
}
}
templ renderLink(attrs templ.Attributes, text string) {
<a { attrs... }>
{ text }
</a>
}
templ renderStrong(attrs templ.Attributes, text string) {
<strong { attrs... }>
{ text }
</strong>
}
templ renderEmphasis(attrs templ.Attributes, text string) {
<em { attrs... }>
{ text }
</em>
}
templ renderCode(attrs templ.Attributes, text string) {
<code { attrs... }>
{ text }
</code>
}

View File

@ -0,0 +1,326 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func H1(content string) templ.Component {
return renderText(1, content)
}
func H2(content string) templ.Component {
return renderText(2, content)
}
func H3(content string) templ.Component {
return renderText(3, content)
}
func Text(content string) templ.Component {
return renderText(0, content)
}
func renderText(level int, text string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
switch level {
case 1:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h1 class=\"text-2xl lg:text-3xl font-bold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 23, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h1>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 2:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h2 class=\"text-xl lg:text-2xl font-bold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 27, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h2>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case 3:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<h3 class=\"text-md lg:text-xl font-semibold\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 31, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</h3>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
default:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-base font-normal\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 35, Col: 10}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return templ_7745c5c3_Err
})
}
func renderLink(attrs templ.Attributes, text string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<a")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 42, Col: 8}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func renderStrong(attrs templ.Attributes, text string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var8 := templ.GetChildren(ctx)
if templ_7745c5c3_Var8 == nil {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<strong")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 48, Col: 8}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</strong>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func renderEmphasis(attrs templ.Attributes, text string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var10 := templ.GetChildren(ctx)
if templ_7745c5c3_Var10 == nil {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<em")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 54, Col: 8}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</em>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func renderCode(attrs templ.Attributes, text string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var12 := templ.GetChildren(ctx)
if templ_7745c5c3_Var12 == nil {
templ_7745c5c3_Var12 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<code")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ.RenderAttributes(ctx, templ_7745c5c3_Buffer, attrs)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(text)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/fonts.templ`, Line: 60, Col: 8}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</code>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,54 @@
package elements
templ Layout(title string) {
<!DOCTYPE html>
<html>
<head>
@defaultStyles()
<title>{ title }</title>
</head>
<body class="flex items-center justify-center h-full bg-neutral-50 lg:p-24 md:16 p-4">
<main class="flex-row items-center justify-center mx-auto w-fit max-w-screen-sm gap-y-3">
{ children... }
</main>
</body>
</html>
}
templ Spacer() {
<br/>
}
templ ServiceWorker(path string) {
<script>
navigator.serviceWorker.register({ path })
</script>
}
templ defaultStyles() {
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script src="https://cdn.sonr.io/js/htmx.min.js"></script>
<link href="https://cdn.sonr.io/stylesheet.css" rel="stylesheet"/>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/alpinejs" defer></script>
<style>[x-cloak]{display:none}</style>
<style>font-family: R-Flex, system-ui, Inter, Helvetica, Arial, sans-serif;</style>
}
templ Rows() {
<div class="flex flex-row w-full gap-2 md:gap-4">
{ children... }
</div>
}
templ Columns() {
<div class="flex flex-col h-full w-full gap-3 md:gap-6 md:flex-row">
{ children... }
</div>
}
css main() {
font-family: R-Flex, system-ui, Avenir, Helvetica, Arial, sans-serif;
}

View File

@ -0,0 +1,240 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Layout(title string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<!doctype html><html><head>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = defaultStyles().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<title>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/global.templ`, Line: 8, Col: 17}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</title></head><body class=\"flex items-center justify-center h-full bg-neutral-50 lg:p-24 md:16 p-4\"><main class=\"flex-row items-center justify-center mx-auto w-fit max-w-screen-sm gap-y-3\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</main></body></html>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Spacer() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
if templ_7745c5c3_Var3 == nil {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<br>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func ServiceWorker(path string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var4 := templ.GetChildren(ctx)
if templ_7745c5c3_Var4 == nil {
templ_7745c5c3_Var4 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<script>\n\t navigator.serviceWorker.register({ path })\n </script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func defaultStyles() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var5 := templ.GetChildren(ctx)
if templ_7745c5c3_Var5 == nil {
templ_7745c5c3_Var5 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<meta charset=\"UTF-8\"><meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><script src=\"https://cdn.sonr.io/js/htmx.min.js\"></script><link href=\"https://cdn.sonr.io/stylesheet.css\" rel=\"stylesheet\"><script src=\"https://cdn.tailwindcss.com\"></script><script src=\"https://unpkg.com/alpinejs\" defer></script><style>[x-cloak]{display:none}</style><style>font-family: R-Flex, system-ui, Inter, Helvetica, Arial, sans-serif;</style>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Rows() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
if templ_7745c5c3_Var6 == nil {
templ_7745c5c3_Var6 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-row w-full gap-2 md:gap-4\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var6.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Columns() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var7 := templ.GetChildren(ctx)
if templ_7745c5c3_Var7 == nil {
templ_7745c5c3_Var7 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-col h-full w-full gap-3 md:gap-6 md:flex-row\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templ_7745c5c3_Var7.Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func main() templ.CSSClass {
templ_7745c5c3_CSSBuilder := templruntime.GetBuilder()
templ_7745c5c3_CSSBuilder.WriteString(`font-family:R-Flex, system-ui, Avenir, Helvetica, Arial, sans-serif;`)
templ_7745c5c3_CSSID := templ.CSSID(`main`, templ_7745c5c3_CSSBuilder.String())
return templ.ComponentCSSClass{
ID: templ_7745c5c3_CSSID,
Class: templ.SafeCSS(`.` + templ_7745c5c3_CSSID + `{` + templ_7745c5c3_CSSBuilder.String() + `}`),
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,31 @@
package elements
type Icons int
const (
Icons_Info Icons = iota
Icons_Error
Icons_Success
Icons_Warning
)
func (v Icons) Render() templ.Component {
return renderIconVariant(v)
}
templ renderIconVariant(v Icons) {
switch v {
case Icons_Info:
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"></path></svg>
case Icons_Error:
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"></path></svg>
case Icons_Success:
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
case Icons_Warning:
<svg class="w-5 h-5 -translate-y-0.5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"></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-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>
}
templ SonrIcon() {
}

View File

@ -0,0 +1,100 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
type Icons int
const (
Icons_Info Icons = iota
Icons_Error
Icons_Success
Icons_Warning
)
func (v Icons) Render() templ.Component {
return renderIconVariant(v)
}
func renderIconVariant(v Icons) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
switch v {
case Icons_Info:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-5 h-5 -translate-y-0.5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z\"></path></svg> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case Icons_Error:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-5 h-5 -translate-y-0.5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z\"></path></svg> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case Icons_Success:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-5 h-5 -translate-y-0.5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"></path></svg> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case Icons_Warning:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg class=\"w-5 h-5 -translate-y-0.5\" xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"w-6 h-6\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z\"></path></svg> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-right\"><polyline points=\"9 18 15 12 9 6\"></polyline></svg>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func SonrIcon() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,29 @@
package elements
type InputState int
const (
InputStateDefault InputState = iota
InputStateError
InputStateSuccess
)
templ TextInput(state InputState, label string, placeholder string) {
switch (state) {
case InputStateDefault:
<div class="flex flex-col space-y-1.5 p-6">
<label class="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="name">{ label }</label>
<input type="text" placeholder="{label}" id="name" value="{value}" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50"/>
</div>
case InputStateError:
<div class="flex flex-col space-y-1.5 p-6">
<label class="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="name">{ label }</label>
<input type="text" placeholder="{label}" id="name" value="{value}" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50"/>
</div>
case InputStateSuccess:
<div class="flex flex-col space-y-1.5 p-6">
<label class="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="name">{ label }</label>
<input type="text" placeholder="{label}" id="name" value="{value}" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50"/>
</div>
}
}

View File

@ -0,0 +1,100 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
type InputState int
const (
InputStateDefault InputState = iota
InputStateError
InputStateSuccess
)
func TextInput(state InputState, label string, placeholder string) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
switch state {
case InputStateDefault:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-col space-y-1.5 p-6\"><label class=\"text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\" for=\"name\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var2 string
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/inputs.templ`, Line: 15, Col: 128}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <input type=\"text\" placeholder=\"{label}\" id=\"name\" value=\"{value}\" class=\"flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case InputStateError:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-col space-y-1.5 p-6\"><label class=\"text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\" for=\"name\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/inputs.templ`, Line: 20, Col: 128}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <input type=\"text\" placeholder=\"{label}\" id=\"name\" value=\"{value}\" class=\"flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case InputStateSuccess:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-col space-y-1.5 p-6\"><label class=\"text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\" for=\"name\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/gui/elements/inputs.templ`, Line: 25, Col: 128}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</label> <input type=\"text\" placeholder=\"{label}\" id=\"name\" value=\"{value}\" class=\"flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50\"></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,37 @@
package elements
templ RadioGroup() {
<div
x-data="{
radioGroupSelectedValue: null,
radioGroupOptions: [
{
title: 'Email Address',
description: 'Get a login code to your email address.',
value: 'email'
},
{
title: 'Phone Number',
description: 'Get a login code to your phone number.',
value: 'phone'
},
{
title: 'Passkey',
description: 'Sign in with your passkey.',
value: 'passkey'
}
]
}"
class="space-y-3"
>
<template x-for="(option, index) in radioGroupOptions" :key="index">
<label @click="radioGroupSelectedValue=option.value" class="flex items-start p-5 space-x-3 bg-white border rounded-md shadow-sm hover:bg-gray-50 border-neutral-200/70">
<input type="radio" name="radio-group" :value="option.value" class="text-gray-900 translate-y-px focus:ring-gray-700"/>
<span class="relative flex flex-col text-left space-y-1.5 leading-none">
<span x-text="option.title" class="font-semibold"></span>
<span x-text="option.description" class="text-sm opacity-50"></span>
</span>
</label>
</template>
</div>
}

View File

@ -0,0 +1,40 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func RadioGroup() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{\n radioGroupSelectedValue: null,\n radioGroupOptions: [\n {\n title: &#39;Email Address&#39;,\n description: &#39;Get a login code to your email address.&#39;,\n value: &#39;email&#39;\n },\n {\n title: &#39;Phone Number&#39;,\n description: &#39;Get a login code to your phone number.&#39;,\n value: &#39;phone&#39;\n },\n {\n title: &#39;Passkey&#39;,\n description: &#39;Sign in with your passkey.&#39;,\n value: &#39;passkey&#39;\n }\n ]\n}\" class=\"space-y-3\"><template x-for=\"(option, index) in radioGroupOptions\" :key=\"index\"><label @click=\"radioGroupSelectedValue=option.value\" class=\"flex items-start p-5 space-x-3 bg-white border rounded-md shadow-sm hover:bg-gray-50 border-neutral-200/70\"><input type=\"radio\" name=\"radio-group\" :value=\"option.value\" class=\"text-gray-900 translate-y-px focus:ring-gray-700\"> <span class=\"relative flex flex-col text-left space-y-1.5 leading-none\"><span x-text=\"option.title\" class=\"font-semibold\"></span> <span x-text=\"option.description\" class=\"text-sm opacity-50\"></span></span></label></template></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,61 @@
package elements
type Size int
const (
SizeDefault Size = iota
SizeSmall
SizeMedium
SizeLarge
)
func (s Size) CardAttributes() templ.Attributes {
switch s {
case SizeSmall:
return templ.Attributes{
"class": "max-w-lg bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60",
}
case SizeLarge:
return templ.Attributes{
"class": "max-w-2xl bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60",
}
}
return templ.Attributes{
"class": "max-w-xl bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60",
}
}
func (s Size) SvgAttributes() templ.Attributes {
switch s {
case SizeSmall:
return templ.Attributes{
"height": "16",
"width": "16",
}
case SizeLarge:
return templ.Attributes{
"height": "32",
"width": "32",
}
}
return templ.Attributes{
"height": "24",
"width": "24",
}
}
func (s Size) TextAttributes() templ.Attributes {
switch s {
case SizeSmall:
return templ.Attributes{
"class": "text-sm",
}
case SizeLarge:
return templ.Attributes{
"class": "text-lg",
}
}
return templ.Attributes{
"class": "text-md",
}
}

View File

@ -0,0 +1,71 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
type Size int
const (
SizeDefault Size = iota
SizeSmall
SizeMedium
SizeLarge
)
func (s Size) CardAttributes() templ.Attributes {
switch s {
case SizeSmall:
return templ.Attributes{
"class": "max-w-lg bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60",
}
case SizeLarge:
return templ.Attributes{
"class": "max-w-2xl bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60",
}
}
return templ.Attributes{
"class": "max-w-xl bg-white border rounded-lg shadow-sm p-7 border-neutral-200/60",
}
}
func (s Size) SvgAttributes() templ.Attributes {
switch s {
case SizeSmall:
return templ.Attributes{
"height": "16",
"width": "16",
}
case SizeLarge:
return templ.Attributes{
"height": "32",
"width": "32",
}
}
return templ.Attributes{
"height": "24",
"width": "24",
}
}
func (s Size) TextAttributes() templ.Attributes {
switch s {
case SizeSmall:
return templ.Attributes{
"class": "text-sm",
}
case SizeLarge:
return templ.Attributes{
"class": "text-lg",
}
}
return templ.Attributes{
"class": "text-md",
}
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,109 @@
package elements
templ Tabs() {
<div
x-data="{
tabSelected: 1,
tabId: $id('tabs'),
tabButtonClicked(tabButton){
this.tabSelected = tabButton.id.replace(this.tabId + '-', '');
this.tabRepositionMarker(tabButton);
},
tabRepositionMarker(tabButton){
this.$refs.tabMarker.style.width=tabButton.offsetWidth + 'px';
this.$refs.tabMarker.style.height=tabButton.offsetHeight + 'px';
this.$refs.tabMarker.style.left=tabButton.offsetLeft + 'px';
},
tabContentActive(tabContent){
return this.tabSelected == tabContent.id.replace(this.tabId + '-content-', '');
},
tabButtonActive(tabContent){
const tabId = tabContent.id.split('-').slice(-1);
return this.tabSelected == tabId;
}
}"
x-init="tabRepositionMarker($refs.tabButtons.firstElementChild);"
class="relative w-full max-w-sm"
>
<div x-ref="tabButtons" class="relative inline-grid items-center justify-center w-full h-10 grid-cols-3 p-1 text-gray-500 bg-white border border-gray-100 rounded-lg select-none">
<button :id="$id(tabId)" @click="tabButtonClicked($el);" type="button" :class="{ 'bg-gray-100 text-gray-700' : tabButtonActive($el) }" class="relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap">Tab1</button>
<button :id="$id(tabId)" @click="tabButtonClicked($el);" type="button" :class="{ 'bg-gray-100 text-gray-700' : tabButtonActive($el) }" class="relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap">Tab2</button>
<button :id="$id(tabId)" @click="tabButtonClicked($el);" type="button" :class="{ 'bg-gray-100 text-gray-700' : tabButtonActive($el) }" class="relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap">Tab3</button>
<div x-ref="tabMarker" class="absolute left-0 z-10 w-1/2 h-full duration-300 ease-out" x-cloak><div class="w-full h-full bg-gray-100 rounded-md shadow-sm"></div></div>
</div>
<div class="relative flex items-center justify-center w-full p-5 mt-2 text-xs text-gray-400 border rounded-md content border-gray-200/70">
<div :id="$id(tabId + '-content')" x-show="tabContentActive($el)" class="relative">
@Table()
</div>
<div :id="$id(tabId + '-content')" x-show="tabContentActive($el)" class="relative" x-cloak>
And, this is the content for Tab2
</div>
<div :id="$id(tabId + '-content')" x-show="tabContentActive($el)" class="relative" x-cloak>
Finally, this is the content for Tab3
</div>
</div>
</div>
}
templ Table() {
<div class="flex flex-col">
<div class="overflow-x-auto">
<div class="inline-block min-w-full">
<div class="overflow-hidden">
<table class="min-w-full divide-y divide-neutral-200">
<thead>
<tr class="text-neutral-500">
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Name</th>
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Age</th>
<th class="px-5 py-3 text-xs font-medium text-left uppercase">Address</th>
<th class="px-5 py-3 text-xs font-medium text-right uppercase">Action</th>
</tr>
</thead>
<tbody class="divide-y divide-neutral-200">
<tr class="text-neutral-800">
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">Richard Hendricks</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">30</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">Pied Piper HQ, Palo Alto</td>
<td class="px-5 py-4 text-sm font-medium text-right whitespace-nowrap">
<a class="text-blue-600 hover:text-blue-700" href="#">Edit</a>
</td>
</tr>
<tr class="text-neutral-800">
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">Erlich Bachman</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">40</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">5230 Penfield Ave, Woodland Hills</td>
<td class="px-5 py-4 text-sm font-medium text-right whitespace-nowrap">
<a class="text-blue-600 hover:text-blue-700" href="#">Edit</a>
</td>
</tr>
<tr class="text-neutral-800">
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">Monica Hall</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">35</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">2030 Stewart Drive, Sunnyvale</td>
<td class="px-5 py-4 text-sm font-medium text-right whitespace-nowrap">
<a class="text-blue-600 hover:text-blue-700" href="#">Edit</a>
</td>
</tr>
<tr class="text-neutral-800">
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">Dinesh Chugtai</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">28</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">Pied Piper HQ, Palo Alto</td>
<td class="px-5 py-4 text-sm font-medium text-right whitespace-nowrap">
<a class="text-blue-600 hover:text-blue-700" href="#">Edit</a>
</td>
</tr>
<tr class="text-neutral-800">
<td class="px-5 py-4 text-sm font-medium whitespace-nowrap">Gilfoyle</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">32</td>
<td class="px-5 py-4 text-sm whitespace-nowrap">Pied Piper HQ, Palo Alto</td>
<td class="px-5 py-4 text-sm font-medium text-right whitespace-nowrap">
<a class="text-blue-600 hover:text-blue-700" href="#">Edit</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
}

View File

@ -0,0 +1,77 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package elements
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func Tabs() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div x-data=\"{\n tabSelected: 1,\n tabId: $id(&#39;tabs&#39;),\n tabButtonClicked(tabButton){\n this.tabSelected = tabButton.id.replace(this.tabId + &#39;-&#39;, &#39;&#39;);\n this.tabRepositionMarker(tabButton);\n },\n tabRepositionMarker(tabButton){\n this.$refs.tabMarker.style.width=tabButton.offsetWidth + &#39;px&#39;;\n this.$refs.tabMarker.style.height=tabButton.offsetHeight + &#39;px&#39;;\n this.$refs.tabMarker.style.left=tabButton.offsetLeft + &#39;px&#39;;\n },\n tabContentActive(tabContent){\n return this.tabSelected == tabContent.id.replace(this.tabId + &#39;-content-&#39;, &#39;&#39;);\n },\n tabButtonActive(tabContent){\n const tabId = tabContent.id.split(&#39;-&#39;).slice(-1);\n return this.tabSelected == tabId;\n }\n }\" x-init=\"tabRepositionMarker($refs.tabButtons.firstElementChild);\" class=\"relative w-full max-w-sm\"><div x-ref=\"tabButtons\" class=\"relative inline-grid items-center justify-center w-full h-10 grid-cols-3 p-1 text-gray-500 bg-white border border-gray-100 rounded-lg select-none\"><button :id=\"$id(tabId)\" @click=\"tabButtonClicked($el);\" type=\"button\" :class=\"{ &#39;bg-gray-100 text-gray-700&#39; : tabButtonActive($el) }\" class=\"relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap\">Tab1</button> <button :id=\"$id(tabId)\" @click=\"tabButtonClicked($el);\" type=\"button\" :class=\"{ &#39;bg-gray-100 text-gray-700&#39; : tabButtonActive($el) }\" class=\"relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap\">Tab2</button> <button :id=\"$id(tabId)\" @click=\"tabButtonClicked($el);\" type=\"button\" :class=\"{ &#39;bg-gray-100 text-gray-700&#39; : tabButtonActive($el) }\" class=\"relative z-20 inline-flex items-center justify-center w-full h-8 px-3 text-sm font-medium transition-all rounded-md cursor-pointer whitespace-nowrap\">Tab3</button><div x-ref=\"tabMarker\" class=\"absolute left-0 z-10 w-1/2 h-full duration-300 ease-out\" x-cloak><div class=\"w-full h-full bg-gray-100 rounded-md shadow-sm\"></div></div></div><div class=\"relative flex items-center justify-center w-full p-5 mt-2 text-xs text-gray-400 border rounded-md content border-gray-200/70\"><div :id=\"$id(tabId + &#39;-content&#39;)\" x-show=\"tabContentActive($el)\" class=\"relative\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = Table().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div><div :id=\"$id(tabId + &#39;-content&#39;)\" x-show=\"tabContentActive($el)\" class=\"relative\" x-cloak>And, this is the content for Tab2</div><div :id=\"$id(tabId + &#39;-content&#39;)\" x-show=\"tabContentActive($el)\" class=\"relative\" x-cloak>Finally, this is the content for Tab3</div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
func Table() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"flex flex-col\"><div class=\"overflow-x-auto\"><div class=\"inline-block min-w-full\"><div class=\"overflow-hidden\"><table class=\"min-w-full divide-y divide-neutral-200\"><thead><tr class=\"text-neutral-500\"><th class=\"px-5 py-3 text-xs font-medium text-left uppercase\">Name</th><th class=\"px-5 py-3 text-xs font-medium text-left uppercase\">Age</th><th class=\"px-5 py-3 text-xs font-medium text-left uppercase\">Address</th><th class=\"px-5 py-3 text-xs font-medium text-right uppercase\">Action</th></tr></thead> <tbody class=\"divide-y divide-neutral-200\"><tr class=\"text-neutral-800\"><td class=\"px-5 py-4 text-sm font-medium whitespace-nowrap\">Richard Hendricks</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">30</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">Pied Piper HQ, Palo Alto</td><td class=\"px-5 py-4 text-sm font-medium text-right whitespace-nowrap\"><a class=\"text-blue-600 hover:text-blue-700\" href=\"#\">Edit</a></td></tr><tr class=\"text-neutral-800\"><td class=\"px-5 py-4 text-sm font-medium whitespace-nowrap\">Erlich Bachman</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">40</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">5230 Penfield Ave, Woodland Hills</td><td class=\"px-5 py-4 text-sm font-medium text-right whitespace-nowrap\"><a class=\"text-blue-600 hover:text-blue-700\" href=\"#\">Edit</a></td></tr><tr class=\"text-neutral-800\"><td class=\"px-5 py-4 text-sm font-medium whitespace-nowrap\">Monica Hall</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">35</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">2030 Stewart Drive, Sunnyvale</td><td class=\"px-5 py-4 text-sm font-medium text-right whitespace-nowrap\"><a class=\"text-blue-600 hover:text-blue-700\" href=\"#\">Edit</a></td></tr><tr class=\"text-neutral-800\"><td class=\"px-5 py-4 text-sm font-medium whitespace-nowrap\">Dinesh Chugtai</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">28</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">Pied Piper HQ, Palo Alto</td><td class=\"px-5 py-4 text-sm font-medium text-right whitespace-nowrap\"><a class=\"text-blue-600 hover:text-blue-700\" href=\"#\">Edit</a></td></tr><tr class=\"text-neutral-800\"><td class=\"px-5 py-4 text-sm font-medium whitespace-nowrap\">Gilfoyle</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">32</td><td class=\"px-5 py-4 text-sm whitespace-nowrap\">Pied Piper HQ, Palo Alto</td><td class=\"px-5 py-4 text-sm font-medium text-right whitespace-nowrap\"><a class=\"text-blue-600 hover:text-blue-700\" href=\"#\">Edit</a></td></tr></tbody></table></div></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,41 @@
package forms
import (
"bytes"
"github.com/a-h/templ"
"github.com/labstack/echo/v4"
)
func echoFormResponse(c echo.Context, cmp templ.Component, state FormState) error {
// Create a buffer to store the rendered HTML
buf := &bytes.Buffer{}
// Render the component to the buffer
err := cmp.Render(c.Request().Context(), buf)
if err != nil {
return err
}
// Set the content type
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
c.Response().Header().Set("X-Status", string(state))
// Write the buffered content to the response
_, err = c.Response().Write(buf.Bytes())
return err
}
type FormState string
const (
InitialForm FormState = "initial"
ErrorForm FormState = "error"
SuccessForm FormState = "success"
WarningForm FormState = "warning"
)
type Form struct {
State FormState
Title string
Description string
}

View File

@ -0,0 +1,25 @@
package forms
import "github.com/labstack/echo/v4"
templ BasicInfo(c echo.Context, state FormState) {
switch (state) {
default:
<div class="border rounded-lg shadow-sm bg-card text-neutral-900">
<div class="flex flex-col space-y-1.5 p-6">
<h3 class="text-lg font-semibold leading-none tracking-tight">Account</h3>
<p class="text-sm text-neutral-500">Make changes to your account here. Click save when you're done.</p>
</div>
<div class="p-6 pt-0 space-y-2">
<div class="space-y-1"><label class="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="name">Name</label><input type="text" id="name" placeholder="Adam Wathan" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50"/></div>
<div class="space-y-1"><label class="text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" for="username">Handle</label><input type="text" id="handle" placeholder="angelo.snr" class="flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50"/></div>
</div>
</div>
}
}
templ CreateCredentials(state FormState) {
}
templ PrivacyTerms(state FormState) {
}

View File

@ -0,0 +1,95 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package forms
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import "github.com/labstack/echo/v4"
func BasicInfo(c echo.Context, state FormState) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
switch state {
default:
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"border rounded-lg shadow-sm bg-card text-neutral-900\"><div class=\"flex flex-col space-y-1.5 p-6\"><h3 class=\"text-lg font-semibold leading-none tracking-tight\">Account</h3><p class=\"text-sm text-neutral-500\">Make changes to your account here. Click save when you're done.</p></div><div class=\"p-6 pt-0 space-y-2\"><div class=\"space-y-1\"><label class=\"text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\" for=\"name\">Name</label><input type=\"text\" id=\"name\" placeholder=\"Adam Wathan\" class=\"flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50\"></div><div class=\"space-y-1\"><label class=\"text-xs font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\" for=\"username\">Handle</label><input type=\"text\" id=\"handle\" placeholder=\"angelo.snr\" class=\"flex w-full h-10 px-3 py-2 text-sm bg-white border rounded-md peer border-neutral-300 ring-offset-background placeholder:text-neutral-400 focus:border-neutral-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50\"></div></div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
return templ_7745c5c3_Err
})
}
func CreateCredentials(state FormState) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var2 := templ.GetChildren(ctx)
if templ_7745c5c3_Var2 == nil {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
return templ_7745c5c3_Err
})
}
func PrivacyTerms(state FormState) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templ.GetChildren(ctx)
if templ_7745c5c3_Var3 == nil {
templ_7745c5c3_Var3 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,29 @@
package views
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func HomeView(c echo.Context) error {
return echoComponentResponse(c, renderHomeView())
}
templ renderHomeView() {
@elements.Layout("Sonr.ID") {
@elements.Card("home-view", elements.SizeLarge) {
@elements.H1("Sonr.ID")
@elements.Text("A Decentralized Web Node Client for the Sonr Network.")
@elements.Spacer()
<div class="flex flex-col gap-3">
@elements.Button(elements.GET("/register", "#home-view"), elements.PrimaryButtonStyle()) {
@elements.Text("Get Started")
}
@elements.Button(elements.GET("/login", "#home-view")) {
@elements.Text("Login")
}
</div>
@elements.PoweredBySonr()
}
}
}

View File

@ -0,0 +1,157 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func HomeView(c echo.Context) error {
return echoComponentResponse(c, renderHomeView())
}
func renderHomeView() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.H1("Sonr.ID").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Text("A Decentralized Web Node Client for the Sonr Network.").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Spacer().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <div class=\"flex flex-col gap-3\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.Text("Get Started").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Button(elements.GET("/register", "#home-view"), elements.PrimaryButtonStyle()).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var5 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.Text("Login").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Button(elements.GET("/login", "#home-view")).Render(templ.WithChildren(ctx, templ_7745c5c3_Var5), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.PoweredBySonr().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Card("home-view", elements.SizeLarge).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Layout("Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,25 @@
package views
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func LoginView(c echo.Context) error {
return echoComponentResponse(c, renderLoginView())
}
templ renderLoginView() {
@elements.Layout("Login | Sonr.ID") {
@elements.Card("login-view", elements.SizeLarge) {
@elements.H1("Sonr.ID")
@elements.Text("Neo-tree is a file manager for NeoFS.")
@elements.Spacer()
@elements.RadioGroup()
@elements.Spacer()
@elements.Button(elements.GET("/", "#login-view")) {
@elements.Text("Cancel")
}
}
}
}

View File

@ -0,0 +1,143 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func LoginView(c echo.Context) error {
return echoComponentResponse(c, renderLoginView())
}
func renderLoginView() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.H1("Sonr.ID").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Text("Neo-tree is a file manager for NeoFS.").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Spacer().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.RadioGroup().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Spacer().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.Text("Cancel").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Button(elements.GET("/", "#login-view")).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Card("login-view", elements.SizeLarge).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Layout("Login | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,19 @@
package views
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func AuthorizeView(c echo.Context) error {
return echoComponentResponse(c, renderAuthorizeView())
}
templ renderAuthorizeView() {
@elements.Layout("Login | Sonr.ID") {
@elements.Card("authorize-view", elements.SizeMedium) {
@elements.H1("Sonr.ID")
@elements.Text("Neo-tree is a file manager for NeoFS.")
}
}
}

View File

@ -0,0 +1,93 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func AuthorizeView(c echo.Context) error {
return echoComponentResponse(c, renderAuthorizeView())
}
func renderAuthorizeView() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.H1("Sonr.ID").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Text("Neo-tree is a file manager for NeoFS.").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Card("authorize-view", elements.SizeMedium).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Layout("Login | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,19 @@
package views
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func ProfileView(c echo.Context) error {
return echoComponentResponse(c, renderProfileView())
}
templ renderProfileView() {
@elements.Layout("Profile | Sonr.ID") {
@elements.Card("profile-view", elements.SizeLarge) {
@elements.ProfileCard()
@elements.Tabs()
}
}
}

View File

@ -0,0 +1,93 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
)
func ProfileView(c echo.Context) error {
return echoComponentResponse(c, renderProfileView())
}
func renderProfileView() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.ProfileCard().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Tabs().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Card("profile-view", elements.SizeLarge).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Layout("Profile | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,26 @@
package views
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
"github.com/onsonr/sonr/internal/gui/forms"
)
func RegisterView(c echo.Context) error {
return echoComponentResponse(c, renderRegisterView(c))
}
templ renderRegisterView(c echo.Context) {
@elements.Layout("Register | Sonr.ID") {
@elements.Card("register-view", elements.SizeMedium) {
@elements.H2("Account Registration")
@elements.Spacer()
@elements.Breadcrumbs()
@forms.BasicInfo(c, forms.InitialForm)
@elements.Spacer()
@elements.Button(elements.GET("/", "#register-view")) {
@elements.Text("Cancel")
}
}
}
}

View File

@ -0,0 +1,144 @@
// Code generated by templ - DO NOT EDIT.
// templ: version: v0.2.778
package views
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
import (
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/gui/elements"
"github.com/onsonr/sonr/internal/gui/forms"
)
func RegisterView(c echo.Context) error {
return echoComponentResponse(c, renderRegisterView(c))
}
func renderRegisterView(c echo.Context) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var1 := templ.GetChildren(ctx)
if templ_7745c5c3_Var1 == nil {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Var3 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.H2("Account Registration").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Spacer().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Breadcrumbs().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = forms.BasicInfo(c, forms.InitialForm).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = elements.Spacer().Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var4 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
templ_7745c5c3_Err = elements.Text("Cancel").Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Button(elements.GET("/", "#register-view")).Render(templ.WithChildren(ctx, templ_7745c5c3_Var4), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Card("register-view", elements.SizeMedium).Render(templ.WithChildren(ctx, templ_7745c5c3_Var3), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
templ_7745c5c3_Err = elements.Layout("Register | Sonr.ID").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return templ_7745c5c3_Err
})
}
var _ = templruntime.GeneratedTemplate

View File

@ -0,0 +1,27 @@
package views
import (
"bytes"
"github.com/a-h/templ"
"github.com/labstack/echo/v4"
)
// render renders a templ.Component
func echoComponentResponse(c echo.Context, cmp templ.Component) error {
// Create a buffer to store the rendered HTML
buf := &bytes.Buffer{}
// Render the component to the buffer
err := cmp.Render(c.Request().Context(), buf)
if err != nil {
return err
}
// Set the content type
c.Response().Header().Set(echo.HeaderContentType, echo.MIMETextHTML)
// Write the buffered content to the response
_, err = c.Response().Write(buf.Bytes())
return err
}

95
internal/mdw/authz.go Normal file
View File

@ -0,0 +1,95 @@
package mdw
import (
"fmt"
"net/http"
"time"
"github.com/labstack/echo/v4"
"gopkg.in/macaroon.v2"
)
const (
OriginMacroonCaveat MacroonCaveat = "origin"
ScopesMacroonCaveat MacroonCaveat = "scopes"
SubjectMacroonCaveat MacroonCaveat = "subject"
ExpMacroonCaveat MacroonCaveat = "exp"
TokenMacroonCaveat MacroonCaveat = "token"
)
type MacroonCaveat string
func (c MacroonCaveat) Equal(other string) bool {
return string(c) == other
}
func (c MacroonCaveat) String() string {
return string(c)
}
func (c MacroonCaveat) Verify(value string) error {
switch c {
case OriginMacroonCaveat:
return nil
case ScopesMacroonCaveat:
return nil
case SubjectMacroonCaveat:
return nil
case ExpMacroonCaveat:
// Check if the expiration time is still valid
exp, err := time.Parse(time.RFC3339, value)
if err != nil {
return err
}
if time.Now().After(exp) {
return fmt.Errorf("expired")
}
return nil
case TokenMacroonCaveat:
return nil
default:
return fmt.Errorf("unknown caveat: %s", c)
}
}
var MacroonCaveats = []MacroonCaveat{OriginMacroonCaveat, ScopesMacroonCaveat, SubjectMacroonCaveat, ExpMacroonCaveat, TokenMacroonCaveat}
func MacaroonMiddleware(secretKeyStr string, location string) echo.MiddlewareFunc {
secretKey := []byte(secretKeyStr)
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Extract the macaroon from the Authorization header
auth := c.Request().Header.Get("Authorization")
if auth == "" {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Missing Authorization header"})
}
// Decode the macaroon
mac, err := macaroon.Base64Decode([]byte(auth))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid macaroon encoding"})
}
token, err := macaroon.New(secretKey, mac, location, macaroon.LatestVersion)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid macaroon"})
}
// Verify the macaroon
err = token.Verify(secretKey, func(caveat string) error {
for _, c := range MacroonCaveats {
if c.String() == caveat {
return nil
}
}
return nil // Return nil if the caveat is valid
}, nil)
if err != nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Invalid macaroon"})
}
// Macaroon is valid, proceed to the next handler
return next(c)
}
}
}

3
internal/mdw/client.go Normal file
View File

@ -0,0 +1,3 @@
package mdw
type AuthClient struct{}

55
internal/mdw/headers.go Normal file
View File

@ -0,0 +1,55 @@
package mdw
type RequestHeaders struct {
Authorization *string `header:"Authorization"`
CacheControl *string `header:"Cache-Control"`
DeviceMemory *string `header:"Device-Memory"`
Forwarded *string `header:"Forwarded"`
From *string `header:"From"`
Host *string `header:"Host"`
Link *string `header:"Link"`
PermissionsPolicy *string `header:"Permissions-Policy"`
ProxyAuthorization *string `header:"Proxy-Authorization"`
Referer *string `header:"Referer"`
UserAgent *string `header:"User-Agent"`
ViewportWidth *string `header:"Viewport-Width"`
Width *string `header:"Width"`
WWWAuthenticate *string `header:"WWW-Authenticate"`
// HTMX Specific
HXBoosted *string `header:"HX-Boosted"`
HXCurrentURL *string `header:"HX-Current-URL"`
HXHistoryRestoreRequest *string `header:"HX-History-Restore-Request"`
HXPrompt *string `header:"HX-Prompt"`
HXRequest *string `header:"HX-Request"`
HXTarget *string `header:"HX-Target"`
HXTriggerName *string `header:"HX-Trigger-Name"`
HXTrigger *string `header:"HX-Trigger"`
}
type ResponseHeaders struct {
AcceptCH *string `header:"Accept-CH"`
AccessControlAllowCredentials *string `header:"Access-Control-Allow-Credentials"`
AccessControlAllowHeaders *string `header:"Access-Control-Allow-Headers"`
AccessControlAllowMethods *string `header:"Access-Control-Allow-Methods"`
AccessControlExposeHeaders *string `header:"Access-Control-Expose-Headers"`
AccessControlRequestHeaders *string `header:"Access-Control-Request-Headers"`
ContentSecurityPolicy *string `header:"Content-Security-Policy"`
CrossOriginEmbedderPolicy *string `header:"Cross-Origin-Embedder-Policy"`
PermissionsPolicy *string `header:"Permissions-Policy"`
ProxyAuthorization *string `header:"Proxy-Authorization"`
WWWAuthenticate *string `header:"WWW-Authenticate"`
// HTMX Specific
HXLocation *string `header:"HX-Location"`
HXPushURL *string `header:"HX-Push-Url"`
HXRedirect *string `header:"HX-Redirect"`
HXRefresh *string `header:"HX-Refresh"`
HXReplaceURL *string `header:"HX-Replace-Url"`
HXReswap *string `header:"HX-Reswap"`
HXRetarget *string `header:"HX-Retarget"`
HXReselect *string `header:"HX-Reselect"`
HXTrigger *string `header:"HX-Trigger"`
HXTriggerAfterSettle *string `header:"HX-Trigger-After-Settle"`
HXTriggerAfterSwap *string `header:"HX-Trigger-After-Swap"`
}

72
internal/mdw/session.go Normal file
View File

@ -0,0 +1,72 @@
package mdw
import (
"net/http"
"time"
"github.com/donseba/go-htmx"
"github.com/labstack/echo/v4"
"github.com/onsonr/sonr/internal/db"
"github.com/segmentio/ksuid"
)
type Session struct {
echo.Context
htmx *htmx.HTMX
dB *db.DB
}
// GetSession returns the current Session
func GetSession(c echo.Context) *Session {
return c.(*Session)
}
// UseSession establishes a Session Cookie.
func UseSession(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
sc := initSession(c)
headers := new(RequestHeaders)
sc.Bind(headers)
return next(sc)
}
}
func (c *Session) DB() *db.DB {
return c.dB
}
func (c *Session) Htmx() *htmx.HTMX {
return c.htmx
}
func (c *Session) ID() string {
return readCookie(c, "session")
}
func initSession(c echo.Context) *Session {
s := &Session{Context: c}
if val := readCookie(c, "session"); val == "" {
id := ksuid.New().String()
writeCookie(c, "session", id)
}
return s
}
func readCookie(c echo.Context, key string) string {
cookie, err := c.Cookie(key)
if err != nil {
return ""
}
if cookie == nil {
return ""
}
return cookie.Value
}
func writeCookie(c echo.Context, key string, value string) {
cookie := new(http.Cookie)
cookie.Name = key
cookie.Value = value
cookie.Expires = time.Now().Add(24 * time.Hour)
c.SetCookie(cookie)
}

46
internal/svc/openid.go Normal file
View File

@ -0,0 +1,46 @@
package svc
import (
"fmt"
"github.com/labstack/echo/v4"
oidc "github.com/onsonr/sonr/x/did/types/oidc"
)
func GrantAuthorization(e echo.Context) error {
// Implement authorization endpoint using passkey authentication
// Store session data in cache
return nil
}
func GetJWKS(e echo.Context) error {
// Implement token endpoint
// Use cached session data for validation
return nil
}
func GetToken(e echo.Context) error {
// Implement token endpoint
// Use cached session data for validation
return nil
}
func GetDiscovery(e echo.Context) error {
baseURL := "https://" + e.Request().Host // Ensure this is the correct base URL for your service
discoveryDoc := &oidc.DiscoveryDocument{
Issuer: baseURL,
AuthorizationEndpoint: fmt.Sprintf("%s/auth", baseURL),
TokenEndpoint: fmt.Sprintf("%s/token", baseURL),
UserinfoEndpoint: fmt.Sprintf("%s/userinfo", baseURL),
JwksUri: fmt.Sprintf("%s/jwks", baseURL),
RegistrationEndpoint: fmt.Sprintf("%s/register", baseURL),
ScopesSupported: []string{"openid", "profile", "email", "web3", "sonr"},
ResponseTypesSupported: []string{"code"},
ResponseModesSupported: []string{"query", "form_post"},
GrantTypesSupported: []string{"authorization_code", "refresh_token"},
AcrValuesSupported: []string{"passkey"},
SubjectTypesSupported: []string{"public"},
ClaimsSupported: []string{"sub", "iss", "name", "email"},
}
return e.JSON(200, discoveryDoc)
}

43
internal/svc/webauth.go Normal file
View File

@ -0,0 +1,43 @@
package svc
import (
"encoding/json"
"fmt"
"github.com/go-webauthn/webauthn/protocol"
"github.com/labstack/echo/v4"
)
func CheckSubjectIsValid(e echo.Context) error {
credentialID := e.FormValue("credentialID")
return e.JSON(200, credentialID)
}
func HandleCredentialAssertion(e echo.Context) error {
return e.JSON(200, "HandleCredentialAssertion")
}
func HandleCredentialCreation(e echo.Context) error {
// Get the serialized credential data from the form
credentialDataJSON := e.FormValue("credentialData")
// Deserialize the JSON into a temporary struct
var ccr protocol.CredentialCreationResponse
err := json.Unmarshal([]byte(credentialDataJSON), &ccr)
if err != nil {
return e.JSON(500, err.Error())
}
//
// // Parse the CredentialCreationResponse
// parsedData, err := ccr.Parse()
// if err != nil {
// return e.JSON(500, err.Error())
// }
//
// // Create the Credential
// // credential := orm.NewCredential(parsedData, e.Request().Host, "")
//
// // Set additional fields
// credential.Controller = "" // Set this to the appropriate controller value
return e.JSON(200, fmt.Sprintf("REGISTER: %s", string(ccr.ID)))
}

View File

@ -0,0 +1,322 @@
package txmodel
import (
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
const maxWidth = 100
var (
red = lipgloss.AdaptiveColor{Light: "#FE5F86", Dark: "#FE5F86"}
indigo = lipgloss.AdaptiveColor{Light: "#5A56E0", Dark: "#7571F9"}
green = lipgloss.AdaptiveColor{Light: "#02BA84", Dark: "#02BF87"}
)
type Styles struct {
Base,
HeaderText,
Status,
StatusHeader,
Highlight,
ErrorHeaderText,
Help lipgloss.Style
}
func NewStyles(lg *lipgloss.Renderer) *Styles {
s := Styles{}
s.Base = lg.NewStyle().
Padding(1, 2, 0, 1)
s.HeaderText = lg.NewStyle().
Foreground(indigo).
Bold(true).
Padding(0, 1, 0, 1)
s.Status = lg.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(indigo).
PaddingLeft(1).
MarginTop(1)
s.StatusHeader = lg.NewStyle().
Foreground(green).
Bold(true)
s.Highlight = lg.NewStyle().
Foreground(lipgloss.Color("212"))
s.ErrorHeaderText = s.HeaderText.
Foreground(red)
s.Help = lg.NewStyle().
Foreground(lipgloss.Color("240"))
return &s
}
type state int
const (
statusNormal state = iota
stateDone
)
type Model struct {
state state
lg *lipgloss.Renderer
styles *Styles
form *huh.Form
width int
message *tx.TxBody
}
func NewModel() Model {
m := Model{width: maxWidth}
m.lg = lipgloss.DefaultRenderer()
m.styles = NewStyles(m.lg)
m.form = huh.NewForm(
huh.NewGroup(
huh.NewInput().
Key("from").
Title("From Address").
Placeholder("cosmos1...").
Validate(func(s string) error {
if !strings.HasPrefix(s, "cosmos1") {
return fmt.Errorf("invalid address format")
}
return nil
}),
huh.NewInput().
Key("to").
Title("To Address").
Placeholder("cosmos1...").
Validate(func(s string) error {
if !strings.HasPrefix(s, "cosmos1") {
return fmt.Errorf("invalid address format")
}
return nil
}),
huh.NewInput().
Key("amount").
Title("Amount").
Placeholder("100").
Validate(func(s string) error {
if _, err := sdk.ParseCoinNormalized(s + "atom"); err != nil {
return fmt.Errorf("invalid coin amount")
}
return nil
}),
huh.NewSelect[string]().
Key("denom").
Title("Denom").
Options(huh.NewOptions("atom", "osmo", "usnr", "snr")...),
huh.NewInput().
Key("memo").
Title("Memo").
Placeholder("Optional"),
huh.NewConfirm().
Key("done").
Title("Ready to convert?").
Validate(func(v bool) error {
if !v {
return fmt.Errorf("Please confirm when you're ready to convert")
}
return nil
}).
Affirmative("Yes, convert!").
Negative("Not yet"),
),
).
WithWidth(60).
WithShowHelp(false).
WithShowErrors(false)
return m
}
func (m Model) Init() tea.Cmd {
return m.form.Init()
}
func min(x, y int) int {
if x > y {
return y
}
return x
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = min(msg.Width, maxWidth) - m.styles.Base.GetHorizontalFrameSize()
case tea.KeyMsg:
switch msg.String() {
case "esc", "ctrl+c", "q":
return m, tea.Quit
}
}
var cmds []tea.Cmd
form, cmd := m.form.Update(msg)
if f, ok := form.(*huh.Form); ok {
m.form = f
cmds = append(cmds, cmd)
}
if m.form.State == huh.StateCompleted {
m.buildMessage()
cmds = append(cmds, tea.Quit)
}
return m, tea.Batch(cmds...)
}
func (m Model) View() string {
s := m.styles
switch m.form.State {
case huh.StateCompleted:
pklCode := m.generatePkl()
messageView := m.getMessageView()
var b strings.Builder
fmt.Fprintf(&b, "Final Tx:\n\n%s\n\n%s", pklCode, messageView)
return s.Status.Margin(0, 1).Padding(1, 2).Width(80).Render(b.String()) + "\n\n"
default:
var schemaType string
if m.form.GetString("schemaType") != "" {
schemaType = "Schema Type: " + m.form.GetString("schemaType")
}
v := strings.TrimSuffix(m.form.View(), "\n\n")
form := m.lg.NewStyle().Margin(1, 0).Render(v)
var status string
{
preview := "(Preview will appear here)"
if m.form.GetString("schema") != "" {
preview = m.generatePkl()
}
const statusWidth = 40
statusMarginLeft := m.width - statusWidth - lipgloss.Width(form) - s.Status.GetMarginRight()
status = s.Status.
Height(lipgloss.Height(form)).
Width(statusWidth).
MarginLeft(statusMarginLeft).
Render(s.StatusHeader.Render("Pkl Preview") + "\n" +
schemaType + "\n\n" +
preview)
}
errors := m.form.Errors()
header := m.appBoundaryView("Sonr TX Builder")
if len(errors) > 0 {
header = m.appErrorBoundaryView(m.errorView())
}
body := lipgloss.JoinHorizontal(lipgloss.Top, form, status)
footer := m.appBoundaryView(m.form.Help().ShortHelpView(m.form.KeyBinds()))
if len(errors) > 0 {
footer = m.appErrorBoundaryView("")
}
return s.Base.Render(header + "\n" + body + "\n\n" + footer)
}
}
func (m Model) errorView() string {
var s string
for _, err := range m.form.Errors() {
s += err.Error()
}
return s
}
func (m Model) appBoundaryView(text string) string {
return lipgloss.PlaceHorizontal(
m.width,
lipgloss.Left,
m.styles.HeaderText.Render(text),
lipgloss.WithWhitespaceChars("="),
lipgloss.WithWhitespaceForeground(indigo),
)
}
func (m Model) appErrorBoundaryView(text string) string {
return lipgloss.PlaceHorizontal(
m.width,
lipgloss.Left,
m.styles.ErrorHeaderText.Render(text),
lipgloss.WithWhitespaceChars("="),
lipgloss.WithWhitespaceForeground(red),
)
}
func (m Model) generatePkl() string {
schemaType := m.form.GetString("schemaType")
schema := m.form.GetString("schema")
// This is a placeholder for the actual conversion logic
// In a real implementation, you would parse the schema and generate Pkl code
return fmt.Sprintf("// Converted from %s\n\nclass ConvertedSchema {\n // TODO: Implement conversion from %s\n // Original schema:\n /*\n%s\n */\n}", schemaType, schemaType, schema)
}
func (m *Model) buildMessage() {
from := m.form.GetString("from")
to := m.form.GetString("to")
amount := m.form.GetString("amount")
denom := m.form.GetString("denom")
memo := m.form.GetString("memo")
coin, _ := sdk.ParseCoinNormalized(fmt.Sprintf("%s%s", amount, denom))
sendMsg := &banktypes.MsgSend{
FromAddress: from,
ToAddress: to,
Amount: sdk.NewCoins(coin),
}
anyMsg, _ := codectypes.NewAnyWithValue(sendMsg)
m.message = &tx.TxBody{
Messages: []*codectypes.Any{anyMsg},
Memo: memo,
}
}
func (m Model) getMessageView() string {
if m.message == nil {
return "Current Message: None"
}
interfaceRegistry := codectypes.NewInterfaceRegistry()
marshaler := codec.NewProtoCodec(interfaceRegistry)
jsonBytes, _ := marshaler.MarshalJSON(m.message)
return fmt.Sprintf("Current Message:\n%s", string(jsonBytes))
}
func RunTUIForm() (*tx.TxBody, error) {
m := NewModel()
p := tea.NewProgram(m)
finalModel, err := p.Run()
if err != nil {
return nil, fmt.Errorf("failed to run program: %w", err)
}
finalM, ok := finalModel.(Model)
if !ok || finalM.message == nil {
return nil, fmt.Errorf("form not completed")
}
return finalM.message, nil
}

View File

@ -0,0 +1,165 @@
package dexmodel
import (
"fmt"
"time"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/spf13/cobra"
)
var (
subtle = lipgloss.AdaptiveColor{Light: "#D9DCCF", Dark: "#383838"}
highlight = lipgloss.AdaptiveColor{Light: "#874BFD", Dark: "#7D56F4"}
special = lipgloss.AdaptiveColor{Light: "#43BF6D", Dark: "#73F59F"}
titleStyle = lipgloss.NewStyle().
MarginLeft(1).
MarginRight(5).
Padding(0, 1).
Italic(true).
Foreground(lipgloss.Color("#FFF7DB")).
SetString("Cosmos Block Explorer")
infoStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.NormalBorder()).
BorderTop(true).
BorderForeground(subtle)
)
type model struct {
blocks []string
transactionTable table.Model
stats map[string]string
width int
height int
}
func initialModel() model {
columns := []table.Column{
{Title: "Hash", Width: 10},
{Title: "Type", Width: 15},
{Title: "Height", Width: 10},
{Title: "Time", Width: 20},
}
rows := []table.Row{
{"abc123", "Transfer", "1000", time.Now().Format(time.RFC3339)},
{"def456", "Delegate", "999", time.Now().Add(-1 * time.Minute).Format(time.RFC3339)},
{"ghi789", "Vote", "998", time.Now().Add(-2 * time.Minute).Format(time.RFC3339)},
}
t := table.New(
table.WithColumns(columns),
table.WithRows(rows),
table.WithFocused(true),
table.WithHeight(7),
)
s := table.DefaultStyles()
s.Header = s.Header.
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("240")).
BorderBottom(true).
Bold(false)
s.Selected = s.Selected.
Foreground(lipgloss.Color("229")).
Background(lipgloss.Color("57")).
Bold(false)
t.SetStyles(s)
return model{
blocks: []string{"Block 1", "Block 2", "Block 3"},
transactionTable: t,
stats: map[string]string{
"Latest Block": "1000",
"Validators": "100",
"Bonded Tokens": "1,000,000",
},
}
}
func (m model) Init() tea.Cmd {
return tick
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
case "enter":
return m, tea.Batch(
tea.Printf("Selected transaction: %s", m.transactionTable.SelectedRow()[0]),
)
}
case tea.WindowSizeMsg:
m.height = msg.Height
m.width = msg.Width
case tickMsg:
// Update data here
m.blocks = append([]string{"New Block"}, m.blocks...)
if len(m.blocks) > 5 {
m.blocks = m.blocks[:5]
}
// Add a new transaction to the table
newRow := table.Row{
fmt.Sprintf("tx%d", time.Now().Unix()),
"NewTxType",
fmt.Sprintf("%d", 1000+len(m.transactionTable.Rows())),
time.Now().Format(time.RFC3339),
}
m.transactionTable.SetRows(append([]table.Row{newRow}, m.transactionTable.Rows()...))
if len(m.transactionTable.Rows()) > 10 {
m.transactionTable.SetRows(m.transactionTable.Rows()[:10])
}
return m, tick
}
m.transactionTable, cmd = m.transactionTable.Update(msg)
return m, cmd
}
func (m model) View() string {
s := titleStyle.Render("Cosmos Block Explorer")
s += "\n\n"
// Blocks
s += lipgloss.NewStyle().Bold(true).Render("Recent Blocks") + "\n"
for _, block := range m.blocks {
s += "• " + block + "\n"
}
s += "\n"
// Transactions
s += lipgloss.NewStyle().Bold(true).Render("Recent Transactions") + "\n"
s += m.transactionTable.View() + "\n\n"
// Stats
s += lipgloss.NewStyle().Bold(true).Render("Network Statistics") + "\n"
for key, value := range m.stats {
s += fmt.Sprintf("%s: %s\n", key, value)
}
return s
}
type tickMsg time.Time
func tick() tea.Msg {
time.Sleep(time.Second)
return tickMsg{}
}
func RunExplorerTUI(cmd *cobra.Command, args []string) error {
p := tea.NewProgram(initialModel(), tea.WithAltScreen())
if _, err := p.Run(); err != nil {
return fmt.Errorf("error running explorer: %v", err)
}
return nil
}

49
internal/tui/tui.go Normal file
View File

@ -0,0 +1,49 @@
package tui
import (
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/onsonr/sonr/internal/tui/dexmodel"
"github.com/onsonr/sonr/internal/tui/txmodel"
"github.com/spf13/cobra"
)
func AddTUICmds(rootCmd *cobra.Command) {
rootCmd.AddCommand(newBuildTxnTUICmd())
rootCmd.AddCommand(newExplorerTUICmd())
}
func newBuildTxnTUICmd() *cobra.Command {
return &cobra.Command{
Use: "dash",
Short: "TUI for managing the local Sonr validator node",
RunE: func(cmd *cobra.Command, args []string) error {
txBody, err := txmodel.RunBuildTxnTUI()
if err != nil {
return err
}
interfaceRegistry := codectypes.NewInterfaceRegistry()
marshaler := codec.NewProtoCodec(interfaceRegistry)
jsonBytes, err := marshaler.MarshalJSON(txBody)
if err != nil {
return fmt.Errorf("failed to marshal tx body: %w", err)
}
fmt.Println("Generated Protobuf Message (JSON format):")
fmt.Println(string(jsonBytes))
return nil
},
}
}
func newExplorerTUICmd() *cobra.Command {
return &cobra.Command{
Use: "cosmos-explorer",
Short: "A terminal-based Cosmos blockchain explorer",
RunE: dexmodel.RunExplorerTUI,
}
}

View File

@ -0,0 +1,322 @@
package txmodel
import (
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/huh"
"github.com/charmbracelet/lipgloss"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
const maxWidth = 100
var (
red = lipgloss.AdaptiveColor{Light: "#FE5F86", Dark: "#FE5F86"}
indigo = lipgloss.AdaptiveColor{Light: "#5A56E0", Dark: "#7571F9"}
green = lipgloss.AdaptiveColor{Light: "#02BA84", Dark: "#02BF87"}
)
type Styles struct {
Base,
HeaderText,
Status,
StatusHeader,
Highlight,
ErrorHeaderText,
Help lipgloss.Style
}
func NewStyles(lg *lipgloss.Renderer) *Styles {
s := Styles{}
s.Base = lg.NewStyle().
Padding(1, 2, 0, 1)
s.HeaderText = lg.NewStyle().
Foreground(indigo).
Bold(true).
Padding(0, 1, 0, 1)
s.Status = lg.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(indigo).
PaddingLeft(1).
MarginTop(1)
s.StatusHeader = lg.NewStyle().
Foreground(green).
Bold(true)
s.Highlight = lg.NewStyle().
Foreground(lipgloss.Color("212"))
s.ErrorHeaderText = s.HeaderText.
Foreground(red)
s.Help = lg.NewStyle().
Foreground(lipgloss.Color("240"))
return &s
}
type state int
const (
statusNormal state = iota
stateDone
)
type Model struct {
state state
lg *lipgloss.Renderer
styles *Styles
form *huh.Form
width int
message *tx.TxBody
}
func NewModel() Model {
m := Model{width: maxWidth}
m.lg = lipgloss.DefaultRenderer()
m.styles = NewStyles(m.lg)
m.form = huh.NewForm(
huh.NewGroup(
huh.NewInput().
Key("from").
Title("From Address").
Placeholder("cosmos1...").
Validate(func(s string) error {
if !strings.HasPrefix(s, "cosmos1") {
return fmt.Errorf("invalid address format")
}
return nil
}),
huh.NewInput().
Key("to").
Title("To Address").
Placeholder("cosmos1...").
Validate(func(s string) error {
if !strings.HasPrefix(s, "cosmos1") {
return fmt.Errorf("invalid address format")
}
return nil
}),
huh.NewInput().
Key("amount").
Title("Amount").
Placeholder("100").
Validate(func(s string) error {
if _, err := sdk.ParseCoinNormalized(s + "atom"); err != nil {
return fmt.Errorf("invalid coin amount")
}
return nil
}),
huh.NewSelect[string]().
Key("denom").
Title("Denom").
Options(huh.NewOptions("atom", "osmo", "usnr", "snr")...),
huh.NewInput().
Key("memo").
Title("Memo").
Placeholder("Optional"),
huh.NewConfirm().
Key("done").
Title("Ready to convert?").
Validate(func(v bool) error {
if !v {
return fmt.Errorf("Please confirm when you're ready to convert")
}
return nil
}).
Affirmative("Yes, convert!").
Negative("Not yet"),
),
).
WithWidth(60).
WithShowHelp(false).
WithShowErrors(false)
return m
}
func (m Model) Init() tea.Cmd {
return m.form.Init()
}
func min(x, y int) int {
if x > y {
return y
}
return x
}
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = min(msg.Width, maxWidth) - m.styles.Base.GetHorizontalFrameSize()
case tea.KeyMsg:
switch msg.String() {
case "esc", "ctrl+c", "q":
return m, tea.Quit
}
}
var cmds []tea.Cmd
form, cmd := m.form.Update(msg)
if f, ok := form.(*huh.Form); ok {
m.form = f
cmds = append(cmds, cmd)
}
if m.form.State == huh.StateCompleted {
m.buildMessage()
cmds = append(cmds, tea.Quit)
}
return m, tea.Batch(cmds...)
}
func (m Model) View() string {
s := m.styles
switch m.form.State {
case huh.StateCompleted:
pklCode := m.generatePkl()
messageView := m.getMessageView()
var b strings.Builder
fmt.Fprintf(&b, "Final Tx:\n\n%s\n\n%s", pklCode, messageView)
return s.Status.Margin(0, 1).Padding(1, 2).Width(80).Render(b.String()) + "\n\n"
default:
var schemaType string
if m.form.GetString("schemaType") != "" {
schemaType = "Schema Type: " + m.form.GetString("schemaType")
}
v := strings.TrimSuffix(m.form.View(), "\n\n")
form := m.lg.NewStyle().Margin(1, 0).Render(v)
var status string
{
preview := "(Preview will appear here)"
if m.form.GetString("schema") != "" {
preview = m.generatePkl()
}
const statusWidth = 40
statusMarginLeft := m.width - statusWidth - lipgloss.Width(form) - s.Status.GetMarginRight()
status = s.Status.
Height(lipgloss.Height(form)).
Width(statusWidth).
MarginLeft(statusMarginLeft).
Render(s.StatusHeader.Render("Pkl Preview") + "\n" +
schemaType + "\n\n" +
preview)
}
errors := m.form.Errors()
header := m.appBoundaryView("Sonr TX Builder")
if len(errors) > 0 {
header = m.appErrorBoundaryView(m.errorView())
}
body := lipgloss.JoinHorizontal(lipgloss.Top, form, status)
footer := m.appBoundaryView(m.form.Help().ShortHelpView(m.form.KeyBinds()))
if len(errors) > 0 {
footer = m.appErrorBoundaryView("")
}
return s.Base.Render(header + "\n" + body + "\n\n" + footer)
}
}
func (m Model) errorView() string {
var s string
for _, err := range m.form.Errors() {
s += err.Error()
}
return s
}
func (m Model) appBoundaryView(text string) string {
return lipgloss.PlaceHorizontal(
m.width,
lipgloss.Left,
m.styles.HeaderText.Render(text),
lipgloss.WithWhitespaceChars("="),
lipgloss.WithWhitespaceForeground(indigo),
)
}
func (m Model) appErrorBoundaryView(text string) string {
return lipgloss.PlaceHorizontal(
m.width,
lipgloss.Left,
m.styles.ErrorHeaderText.Render(text),
lipgloss.WithWhitespaceChars("="),
lipgloss.WithWhitespaceForeground(red),
)
}
func (m Model) generatePkl() string {
schemaType := m.form.GetString("schemaType")
schema := m.form.GetString("schema")
// This is a placeholder for the actual conversion logic
// In a real implementation, you would parse the schema and generate Pkl code
return fmt.Sprintf("// Converted from %s\n\nclass ConvertedSchema {\n // TODO: Implement conversion from %s\n // Original schema:\n /*\n%s\n */\n}", schemaType, schemaType, schema)
}
func (m *Model) buildMessage() {
from := m.form.GetString("from")
to := m.form.GetString("to")
amount := m.form.GetString("amount")
denom := m.form.GetString("denom")
memo := m.form.GetString("memo")
coin, _ := sdk.ParseCoinNormalized(fmt.Sprintf("%s%s", amount, denom))
sendMsg := &banktypes.MsgSend{
FromAddress: from,
ToAddress: to,
Amount: sdk.NewCoins(coin),
}
anyMsg, _ := codectypes.NewAnyWithValue(sendMsg)
m.message = &tx.TxBody{
Messages: []*codectypes.Any{anyMsg},
Memo: memo,
}
}
func (m Model) getMessageView() string {
if m.message == nil {
return "Current Message: None"
}
interfaceRegistry := codectypes.NewInterfaceRegistry()
marshaler := codec.NewProtoCodec(interfaceRegistry)
jsonBytes, _ := marshaler.MarshalJSON(m.message)
return fmt.Sprintf("Current Message:\n%s", string(jsonBytes))
}
func RunBuildTxnTUI() (*tx.TxBody, error) {
m := NewModel()
p := tea.NewProgram(m)
finalModel, err := p.Run()
if err != nil {
return nil, fmt.Errorf("failed to run program: %w", err)
}
finalM, ok := finalModel.(Model)
if !ok || finalM.message == nil {
return nil, fmt.Errorf("form not completed")
}
return finalM.message, nil
}

20
internal/vfs/assemble.go Normal file
View File

@ -0,0 +1,20 @@
package vfs
import (
"github.com/ipfs/boxo/files"
)
var (
kServiceWorkerFileName = "server/sw.js"
kVaultFileName = "server/vault.wasm"
kIndexFileName = "index.html"
)
func AssembleDirectory() files.Directory {
fileMap := map[string]files.Node{
kVaultFileName: DWNWasmFile(),
kServiceWorkerFileName: SWJSFile(),
}
return files.NewMapDirectory(fileMap)
}

BIN
internal/vfs/dwn.wasm Executable file

Binary file not shown.

22
internal/vfs/embed.go Normal file
View File

@ -0,0 +1,22 @@
package vfs
import (
_ "embed"
"github.com/ipfs/boxo/files"
)
//go:embed dwn.wasm
var dwnWasmData []byte
//go:embed sw.js
var swJSData []byte
func DWNWasmFile() files.Node {
return files.NewBytesFile(dwnWasmData)
}
// Use ServiceWorkerJS template to generate the service worker file
func SWJSFile() files.Node {
return files.NewBytesFile(swJSData)
}

8
internal/vfs/sw.js Normal file
View File

@ -0,0 +1,8 @@
importScripts(
"https://cdn.jsdelivr.net/gh/golang/go@go1.18.4/misc/wasm/wasm_exec.js",
"https://cdn.jsdelivr.net/gh/nlepage/go-wasm-http-server@v1.1.0/sw.js",
"https://cdn.jsdelivr.net/npm/htmx.org@1.9.12/dist/htmx.min.js",
"https://cdn.jsdelivr.net/npm/alpinejs@3.14.1/dist/cdn.min.js",
);
registerWasmHTTPListener("dwn.wasm");

View File

@ -0,0 +1,37 @@
//go:build js && wasm
package wasm
import (
"bytes"
"net/http"
"net/http/httptest"
"syscall/js"
promise "github.com/nlepage/go-js-promise"
)
// Request builds and returns the equivalent http.Request
func Request(r js.Value) *http.Request {
jsBody := js.Global().Get("Uint8Array").New(promise.Await(r.Call("arrayBuffer")))
body := make([]byte, jsBody.Get("length").Int())
js.CopyBytesToGo(body, jsBody)
req := httptest.NewRequest(
r.Get("method").String(),
r.Get("url").String(),
bytes.NewBuffer(body),
)
headersIt := r.Get("headers").Call("entries")
for {
e := headersIt.Call("next")
if e.Get("done").Bool() {
break
}
v := e.Get("value")
req.Header.Set(v.Index(0).String(), v.Index(1).String())
}
return req
}

View File

@ -0,0 +1,50 @@
//go:build js && wasm
package wasm
import (
"io"
"net/http/httptest"
"syscall/js"
)
// ResponseRecorder uses httptest.ResponseRecorder to build a JS Response
type ResponseRecorder struct {
*httptest.ResponseRecorder
}
// NewResponseRecorder returns a new ResponseRecorder
func NewResponseRecorder() ResponseRecorder {
return ResponseRecorder{httptest.NewRecorder()}
}
// JSResponse builds and returns the equivalent JS Response
func (rr ResponseRecorder) JSResponse() js.Value {
res := rr.Result()
body := js.Undefined()
if res.ContentLength != 0 {
b, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
body = js.Global().Get("Uint8Array").New(len(b))
js.CopyBytesToJS(body, b)
}
init := make(map[string]interface{}, 2)
if res.StatusCode != 0 {
init["status"] = res.StatusCode
}
if len(res.Header) != 0 {
headers := make(map[string]interface{}, len(res.Header))
for k := range res.Header {
headers[k] = res.Header.Get(k)
}
init["headers"] = headers
}
return js.Global().Get("Response").New(body, init)
}

View File

@ -0,0 +1,59 @@
//go:build js && wasm
package wasm
import (
"fmt"
"net/http"
"strings"
"syscall/js"
promise "github.com/nlepage/go-js-promise"
)
// Serve serves HTTP requests using handler or http.DefaultServeMux if handler is nil.
func Serve(handler http.Handler) func() {
h := handler
if h == nil {
h = http.DefaultServeMux
}
prefix := js.Global().Get("wasmhttp").Get("path").String()
for strings.HasSuffix(prefix, "/") {
prefix = strings.TrimSuffix(prefix, "/")
}
if prefix != "" {
mux := http.NewServeMux()
mux.Handle(prefix+"/", http.StripPrefix(prefix, h))
h = mux
}
cb := js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
resPromise, resolve, reject := promise.New()
go func() {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(error); ok {
reject(fmt.Sprintf("wasmhttp: panic: %+v\n", err))
} else {
reject(fmt.Sprintf("wasmhttp: panic: %v\n", r))
}
}
}()
res := NewResponseRecorder()
h.ServeHTTP(res, Request(args[0]))
resolve(res.JSResponse())
}()
return resPromise
})
js.Global().Get("wasmhttp").Call("setHandler", cb)
return cb.Release
}

37
pkl/api.pkl Normal file
View File

@ -0,0 +1,37 @@
@go.Package { name = "github.com/onsonr/sonr/motr/api" }
module api
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.5.0#/go.pkl"
class JsonField extends go.Field {
structTags {
["json"] = "%{name},omitempty"
}
}
abstract class Request {
route: String
method: String
headers: Map<String, String>
origin: String?
userAgent: String?
body: Dynamic
}
abstract class Response {
statusCode: Int
headers: Map<String, String>
body: Dynamic
}
class GetAccountsRequest extends Request {
route = "/accounts"
method = "GET"
headers = {
"Content-Type" = "application/json"
}
origin = null
userAgent = null
body = null
}

30
pkl/bake.pkl Normal file
View File

@ -0,0 +1,30 @@
@go.Package { name = "github.com/onsonr/sonr/motr/api/bake" }
module bake
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.5.0#/go.pkl"
class JsonField extends go.Field {
structTags {
["json"] = "%{name},omitempty"
}
}
abstract class Macroon {
id: String
location: String
}
abstract class FirstPartyCaveats {
scope: String
exp: Int
cnf: String
aud: String
}
abstract class ThirdPartyCaveats {
scope: String
exp: Int
cnf: String
aud: String
}

59
pkl/oidc.pkl Normal file
View File

@ -0,0 +1,59 @@
@go.Package { name = "github.com/onsonr/sonr/x/did/types/oidc" }
module oidc
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.5.0#/go.pkl"
class JsonField extends go.Field {
structTags {
["json"] = "%{name},omitempty"
["param"] = "%{name}"
}
}
class DiscoveryDocument {
@JsonField
issuer: String
@JsonField
authorization_endpoint: String
@JsonField
token_endpoint: String
@JsonField
userinfo_endpoint: String
@JsonField
jwks_uri: String
@JsonField
registration_endpoint: String
@JsonField
scopes_supported: List<String>
@JsonField
response_types_supported: List<String>
@JsonField
response_modes_supported: List<String>
@JsonField
subject_types_supported: List<String>
@JsonField
id_token_signing_alg_values_supported: List<String>
@JsonField
claims_supported: List<String>
@JsonField
grant_types_supported: List<String>
@JsonField
acr_values_supported: List<String>
@JsonField
token_endpoint_auth_methods_supported: List<String>
}

227
pkl/orm.pkl Normal file
View File

@ -0,0 +1,227 @@
@go.Package { name = "github.com/onsonr/sonr/internal/db/orm" }
module orm
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.5.0#/go.pkl"
class PrimaryKey extends go.Field {
structTags {
["gorm"] = "primaryKey,autoIncrement"
["json"] = "%{name},omitempty"
["query"] = "%{name}"
}
}
class Unique extends go.Field {
structTags {
["gorm"] = "unique"
["json"] = "%{name},omitempty"
}
}
class Default extends go.Field {
defaultValue: String
structTags {
["gorm"] = "default:%{defaultValue}"
["json"] = "%{name},omitempty"
}
}
class NotNull extends go.Field {
structTags {
["gorm"] = "not null"
}
}
class ForeignKey extends go.Field {
references: String
structTags {
["gorm"] = "foreignKey:%{references}"
}
}
class JsonField extends go.Field {
structTags {
["json"] = "%{name},omitempty"
["param"] = "%{name}"
}
}
class Account {
@PrimaryKey
id: UInt
@JsonField
name: String
@JsonField
address: String
@JsonField
publicKey: String
@JsonField
createdAt: String?
}
class Asset {
@PrimaryKey
id: UInt
@JsonField
name: String
@JsonField
symbol: String
@JsonField
decimals: Int
@JsonField
chainId: Int?
@JsonField
createdAt: String?
}
class Chain {
@PrimaryKey
id: UInt
@JsonField
name: String
@JsonField
networkId: String
@JsonField
createdAt: String?
}
class Credential {
@PrimaryKey
id: UInt
@JsonField
subject: String
@JsonField
controller: String
@JsonField
attestationType: String
@JsonField
origin: String
@JsonField
credentialId: String
@JsonField
publicKey: String
@JsonField
transport: String
@JsonField
signCount: UInt
@JsonField
userPresent: Boolean
@JsonField
userVerified: Boolean
@JsonField
backupEligible: Boolean
@JsonField
backupState: Boolean
@JsonField
cloneWarning: Boolean
@JsonField
createdAt: String?
@JsonField
updatedAt: String?
}
class Profile {
@PrimaryKey
id: String
@JsonField
subject: String
@JsonField
controller: String
@JsonField
originUri: String?
@JsonField
publicMetadata: String?
@JsonField
privateMetadata: String?
@JsonField
createdAt: String?
@JsonField
updatedAt: String?
}
class Property {
@PrimaryKey
id: UInt
@JsonField
profileId: String
@JsonField
key: String
@JsonField
accumulator: String
@JsonField
propertyKey: String
}
class Keyshare {
@PrimaryKey
id: UInt
@JsonField
data: String
@JsonField
role: Int
@JsonField
createdAt: String?
}
class Permission {
@PrimaryKey
id: UInt
@JsonField
serviceId: String
@JsonField
grants: String
@JsonField
scopes: String
@JsonField
createdAt: String?
@JsonField
updatedAt: String?
}

175
pkl/txns.pkl Normal file
View File

@ -0,0 +1,175 @@
@go.Package { name = "github.com/onsonr/sonr/x/did/types/txns" }
module txns
import "package://pkg.pkl-lang.org/pkl-go/pkl.golang@0.5.0#/go.pkl"
/// Common Cosmos SDK types
typealias Coin = Dynamic
typealias AccAddress = String
typealias ValAddress = String
typealias Timestamp = String
/// Base class for all messages
abstract class Msg {
/// The type URL for the message
typeUrl: String
}
/// Base class for all proposals
class Proposal {
/// The title of the proposal
title: String
/// The description of the proposal
description: String
}
/// Gov module messages
class MsgGovSubmitProposal extends Msg {
typeUrl = "/cosmos.gov.v1beta1.MsgSubmitProposal"
content: Proposal
initialDeposit: List<Coin>
proposer: AccAddress
}
class MsgGovVote extends Msg {
typeUrl = "/cosmos.gov.v1beta1.MsgVote"
proposalId: Int
voter: AccAddress
option: Int
}
class MsgGovDeposit extends Msg {
typeUrl = "/cosmos.gov.v1beta1.MsgDeposit"
proposalId: Int
depositor: AccAddress
amount: List<Coin>
}
/// Group module messages
class MsgGroupCreateGroup extends Msg {
typeUrl = "/cosmos.group.v1.MsgCreateGroup"
admin: AccAddress
members: List<Dynamic>
metadata: String
}
class MsgGroupSubmitProposal extends Msg {
typeUrl = "/cosmos.group.v1.MsgSubmitProposal"
groupPolicyAddress: AccAddress
proposers: List<AccAddress>
metadata: String
messages: List<Dynamic>
exec: Int
}
class MsgGroupVote extends Msg {
typeUrl = "/cosmos.group.v1.MsgVote"
proposalId: Int
voter: AccAddress
option: Int
metadata: String
exec: Int
}
/// Staking module messages
class MsgStakingCreateValidator extends Msg {
typeUrl = "/cosmos.staking.v1beta1.MsgCreateValidator"
description: Dynamic
commission: Dynamic
minSelfDelegation: String
delegatorAddress: AccAddress
validatorAddress: ValAddress
pubkey: Dynamic
value: Coin
}
class MsgStakingDelegate extends Msg {
typeUrl = "/cosmos.staking.v1beta1.MsgDelegate"
delegatorAddress: AccAddress
validatorAddress: ValAddress
amount: Coin
}
class MsgStakingUndelegate extends Msg {
typeUrl = "/cosmos.staking.v1beta1.MsgUndelegate"
delegatorAddress: AccAddress
validatorAddress: ValAddress
amount: Coin
}
class MsgStakingBeginRedelegate extends Msg {
typeUrl = "/cosmos.staking.v1beta1.MsgBeginRedelegate"
delegatorAddress: AccAddress
validatorSrcAddress: ValAddress
validatorDstAddress: ValAddress
amount: Coin
}
class MsgDidUpdateParams extends Msg {
typeUrl = "/sonr.did.v1.MsgUpdateParams"
authority: AccAddress
params: Dynamic
token: Dynamic
}
class MsgDidAllocateVault extends Msg {
typeUrl = "/sonr.did.v1.MsgAllocateVault"
authority: AccAddress
subject: String
token: Dynamic
}
class MsgDidProveWitness extends Msg {
typeUrl = "/sonr.did.v1.MsgProveWitness"
authority: AccAddress
property: String
witness: Listing<Int>
token: Dynamic
}
class MsgDidSyncVault extends Msg {
typeUrl = "/sonr.did.v1.MsgSyncVault"
controller: AccAddress
token: Dynamic
}
class MsgDidRegisterController extends Msg {
typeUrl = "/sonr.did.v1.MsgRegisterController"
authority: AccAddress
cid: String
origin: String
authentication: List<Dynamic>
token: Dynamic
}
class MsgDidAuthorize extends Msg {
typeUrl = "/sonr.did.v1.MsgAuthorize"
authority: AccAddress
controller: AccAddress
address: AccAddress
origin: String
token: Dynamic
}
class MsgDidRegisterService extends Msg {
typeUrl = "/sonr.did.v1.MsgRegisterService"
controller: AccAddress
originUri: String
scopes: Dynamic
description: String
serviceEndpoints: Map<String, String>
metadata: Dynamic
token: Dynamic
}
/// Represents a transaction body
class TxBody {
messages: List<Msg>
memo: String?
timeoutHeight: Int?
extensionOptions: List<Dynamic>?
nonCriticalExtensionOptions: List<Dynamic>?
}

18
process-compose.yaml Normal file
View File

@ -0,0 +1,18 @@
version: "0.6"
processes:
ipfs:
namespace: testnet
command: "ipfs-cluster-service init --consensus crdt && ipfs-cluster-service daemon"
background: true
availability:
restart: on_failure
max_restarts: 3
sonr:
namespace: testnet
command: "make sh-testnet"
restart: on_failure
max_restarts: 3
depends:
- ipfs

View File

@ -10,6 +10,17 @@ option go_package = "github.com/onsonr/sonr/x/did/types";
message GenesisState {
// Params defines all the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];
// GlobalIntegrity defines a zkp integrity proof for the entire DID namespace
GlobalIntegrity global_integrity = 2;
}
// GlobalIntegrity defines a zkp integrity proof for the entire DID namespace
message GlobalIntegrity {
string controller = 1;
string seed = 2;
bytes accumulator = 3;
uint64 count = 4;
}
// Params defines the set of module parameters.

View File

@ -92,7 +92,7 @@ message Controller {
// Verification reprsents a method of verifying membership in a DID
message Verification {
option (cosmos.orm.v1.table) = {
id: 5
id: 4
primary_key: {fields: "id"}
index: {
id: 1

251
x/did/builder/api.go Normal file
View File

@ -0,0 +1,251 @@
package builder
import (
"encoding/base64"
"fmt"
"github.com/go-webauthn/webauthn/protocol"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
didv1 "github.com/onsonr/sonr/api/did/v1"
"github.com/onsonr/sonr/x/did/types"
)
func APIFormatDIDNamespace(namespace types.DIDNamespace) didv1.DIDNamespace {
return didv1.DIDNamespace(namespace)
}
func APIFormatDIDNamespaces(namespaces []types.DIDNamespace) []didv1.DIDNamespace {
var s []didv1.DIDNamespace
for _, namespace := range namespaces {
s = append(s, APIFormatDIDNamespace(namespace))
}
return s
}
func APIFormatKeyRole(role types.KeyRole) didv1.KeyRole {
return didv1.KeyRole(role)
}
func APIFormatKeyAlgorithm(algorithm types.KeyAlgorithm) didv1.KeyAlgorithm {
return didv1.KeyAlgorithm(algorithm)
}
func APIFormatKeyEncoding(encoding types.KeyEncoding) didv1.KeyEncoding {
return didv1.KeyEncoding(encoding)
}
func APIFormatKeyCurve(curve types.KeyCurve) didv1.KeyCurve {
return didv1.KeyCurve(curve)
}
func APIFormatKeyType(keyType types.KeyType) didv1.KeyType {
return didv1.KeyType(keyType)
}
func APIFormatPermissions(permissions *types.Permissions) *didv1.Permissions {
if permissions == nil {
return nil
}
p := didv1.Permissions{
Grants: APIFormatDIDNamespaces(permissions.Grants),
Scopes: APIFormatPermissionScopes(permissions.Scopes),
}
return &p
}
func APIFormatPermissionScope(scope types.PermissionScope) didv1.PermissionScope {
return didv1.PermissionScope(scope)
}
func APIFormatPermissionScopes(scopes []types.PermissionScope) []didv1.PermissionScope {
var s []didv1.PermissionScope
for _, scope := range scopes {
s = append(s, APIFormatPermissionScope(scope))
}
return s
}
func APIFormatServiceRecord(service *types.Service) *didv1.ServiceRecord {
return &didv1.ServiceRecord{
Id: service.Id,
ServiceType: service.ServiceType,
Authority: service.Authority,
Origin: service.Origin,
Description: service.Description,
ServiceEndpoints: service.ServiceEndpoints,
Permissions: APIFormatPermissions(service.Permissions),
}
}
func APIFormatPubKeyJWK(jwk *types.PubKey_JWK) *didv1.PubKey_JWK {
return &didv1.PubKey_JWK{
Kty: jwk.Kty,
Crv: jwk.Crv,
X: jwk.X,
Y: jwk.Y,
N: jwk.N,
E: jwk.E,
}
}
func APIFormatPubKey(key *types.PubKey) *didv1.PubKey {
return &didv1.PubKey{
Role: APIFormatKeyRole(key.GetRole()),
Algorithm: APIFormatKeyAlgorithm(key.GetAlgorithm()),
Encoding: APIFormatKeyEncoding(key.GetEncoding()),
Curve: APIFormatKeyCurve(key.GetCurve()),
KeyType: APIFormatKeyType(key.GetKeyType()),
Raw: key.GetRaw(),
}
}
func FormatEC2PublicKey(key *webauthncose.EC2PublicKeyData) (*types.PubKey_JWK, error) {
curve, err := GetCOSECurveName(key.Curve)
if err != nil {
return nil, err
}
jwkMap := map[string]interface{}{
"kty": "EC",
"crv": curve,
"x": base64.RawURLEncoding.EncodeToString(key.XCoord),
"y": base64.RawURLEncoding.EncodeToString(key.YCoord),
}
return MapToJWK(jwkMap)
}
func FormatRSAPublicKey(key *webauthncose.RSAPublicKeyData) (*types.PubKey_JWK, error) {
jwkMap := map[string]interface{}{
"kty": "RSA",
"n": base64.RawURLEncoding.EncodeToString(key.Modulus),
"e": base64.RawURLEncoding.EncodeToString(key.Exponent),
}
return MapToJWK(jwkMap)
}
func FormatOKPPublicKey(key *webauthncose.OKPPublicKeyData) (*types.PubKey_JWK, error) {
curve, err := GetOKPCurveName(key.Curve)
if err != nil {
return nil, err
}
jwkMap := map[string]interface{}{
"kty": "OKP",
"crv": curve,
"x": base64.RawURLEncoding.EncodeToString(key.XCoord),
}
return MapToJWK(jwkMap)
}
func MapToJWK(m map[string]interface{}) (*types.PubKey_JWK, error) {
jwk := &types.PubKey_JWK{}
for k, v := range m {
switch k {
case "kty":
jwk.Kty = v.(string)
case "crv":
jwk.Crv = v.(string)
case "x":
jwk.X = v.(string)
case "y":
jwk.Y = v.(string)
case "n":
jwk.N = v.(string)
case "e":
jwk.E = v.(string)
}
}
return jwk, nil
}
func GetCOSECurveName(curveID int64) (string, error) {
switch curveID {
case int64(webauthncose.P256):
return "P-256", nil
case int64(webauthncose.P384):
return "P-384", nil
case int64(webauthncose.P521):
return "P-521", nil
default:
return "", fmt.Errorf("unknown curve ID: %d", curveID)
}
}
func GetOKPCurveName(curveID int64) (string, error) {
switch curveID {
case int64(webauthncose.Ed25519):
return "Ed25519", nil
default:
return "", fmt.Errorf("unknown OKP curve ID: %d", curveID)
}
}
// NormalizeTransports returns the transports as strings
func NormalizeTransports(transports []protocol.AuthenticatorTransport) []string {
tss := make([]string, len(transports))
for i, t := range transports {
tss[i] = string(t)
}
return tss
}
// GetTransports returns the protocol.AuthenticatorTransport
func ModuleTransportsToProtocol(transport []string) []protocol.AuthenticatorTransport {
tss := make([]protocol.AuthenticatorTransport, len(transport))
for i, t := range transport {
tss[i] = protocol.AuthenticatorTransport(t)
}
return tss
}
// ModuleFormatAPIServiceRecord formats a service record for the module
func ModuleFormatAPIServiceRecord(service *didv1.ServiceRecord) *types.Service {
return &types.Service{
Id: service.Id,
ServiceType: service.ServiceType,
Authority: service.Authority,
Origin: service.Origin,
Description: service.Description,
ServiceEndpoints: service.ServiceEndpoints,
Permissions: ModuleFormatAPIPermissions(service.Permissions),
}
}
func ModuleFormatAPIPermissions(permissions *didv1.Permissions) *types.Permissions {
if permissions == nil {
return nil
}
p := types.Permissions{
Grants: ModuleFormatAPIDIDNamespaces(permissions.Grants),
Scopes: ModuleFormatAPIPermissionScopes(permissions.Scopes),
}
return &p
}
func ModuleFormatAPIPermissionScope(scope didv1.PermissionScope) types.PermissionScope {
return types.PermissionScope(scope)
}
func ModuleFormatAPIPermissionScopes(scopes []didv1.PermissionScope) []types.PermissionScope {
var s []types.PermissionScope
for _, scope := range scopes {
s = append(s, ModuleFormatAPIPermissionScope(scope))
}
return s
}
func ModuleFormatAPIDIDNamespace(namespace didv1.DIDNamespace) types.DIDNamespace {
return types.DIDNamespace(namespace)
}
func ModuleFormatAPIDIDNamespaces(namespaces []didv1.DIDNamespace) []types.DIDNamespace {
var s []types.DIDNamespace
for _, namespace := range namespaces {
s = append(s, ModuleFormatAPIDIDNamespace(namespace))
}
return s
}

70
x/did/builder/chains.go Normal file
View File

@ -0,0 +1,70 @@
package builder
import (
"crypto/hmac"
"crypto/sha512"
"encoding/binary"
"errors"
"math/big"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/onsonr/sonr/x/did/types"
)
// ComputeAccountPublicKey computes the public key of a child key given the extended public key, chain code, and index.
func computeBip32AccountPublicKey(extPubKey PublicKey, chainCode types.ChainCode, index int) (*types.PubKey, error) {
// Check if the index is a hardened child key
if chainCode&0x80000000 != 0 && index < 0 {
return nil, errors.New("invalid index")
}
// Serialize the public key
pubKey, err := btcec.ParsePubKey(extPubKey.GetRaw())
if err != nil {
return nil, err
}
pubKeyBytes := pubKey.SerializeCompressed()
// Serialize the index
indexBytes := make([]byte, 4)
binary.BigEndian.PutUint32(indexBytes, uint32(index))
// Compute the HMAC-SHA512
mac := hmac.New(sha512.New, []byte{byte(chainCode)})
mac.Write(pubKeyBytes)
mac.Write(indexBytes)
I := mac.Sum(nil)
// Split I into two 32-byte sequences
IL := I[:32]
// Convert IL to a big integer
ilNum := new(big.Int).SetBytes(IL)
// Check if parse256(IL) >= n
curve := btcec.S256()
if ilNum.Cmp(curve.N) >= 0 {
return nil, errors.New("invalid child key")
}
// Compute the child public key
ilx, ily := curve.ScalarBaseMult(IL)
childX, childY := curve.Add(ilx, ily, pubKey.X(), pubKey.Y())
lx := newBigIntFieldVal(childX)
ly := newBigIntFieldVal(childY)
// Create the child public key
childPubKey := btcec.NewPublicKey(lx, ly)
pk, err := types.NewPublicKey(childPubKey.SerializeCompressed(), types.ChainCodeKeyInfos[chainCode])
if err != nil {
return nil, err
}
return pk, nil
}
// newBigIntFieldVal creates a new field value from a big integer.
func newBigIntFieldVal(val *big.Int) *btcec.FieldVal {
lx := new(btcec.FieldVal)
lx.SetByteSlice(val.Bytes())
return lx
}

334
x/did/builder/constants.go Normal file
View File

@ -0,0 +1,334 @@
package builder
import (
"github.com/onsonr/sonr/x/did/types"
)
type (
AuthenticatorAttachment string
AuthenticatorTransport string
)
const (
// Platform represents a platform authenticator is attached using a client device-specific transport, called
// platform attachment, and is usually not removable from the client device. A public key credential bound to a
// platform authenticator is called a platform credential.
Platform AuthenticatorAttachment = "platform"
// CrossPlatform represents a roaming authenticator is attached using cross-platform transports, called
// cross-platform attachment. Authenticators of this class are removable from, and can "roam" among, client devices.
// A public key credential bound to a roaming authenticator is called a roaming credential.
CrossPlatform AuthenticatorAttachment = "cross-platform"
)
func ParseAuthenticatorAttachment(s string) AuthenticatorAttachment {
switch s {
case "platform":
return Platform
default:
return CrossPlatform
}
}
const (
// USB indicates the respective authenticator can be contacted over removable USB.
USB AuthenticatorTransport = "usb"
// NFC indicates the respective authenticator can be contacted over Near Field Communication (NFC).
NFC AuthenticatorTransport = "nfc"
// BLE indicates the respective authenticator can be contacted over Bluetooth Smart (Bluetooth Low Energy / BLE).
BLE AuthenticatorTransport = "ble"
// SmartCard indicates the respective authenticator can be contacted over ISO/IEC 7816 smart card with contacts.
//
// WebAuthn Level 3.
SmartCard AuthenticatorTransport = "smart-card"
// Hybrid indicates the respective authenticator can be contacted using a combination of (often separate)
// data-transport and proximity mechanisms. This supports, for example, authentication on a desktop computer using
// a smartphone.
//
// WebAuthn Level 3.
Hybrid AuthenticatorTransport = "hybrid"
// Internal indicates the respective authenticator is contacted using a client device-specific transport, i.e., it
// is a platform authenticator. These authenticators are not removable from the client device.
Internal AuthenticatorTransport = "internal"
)
func ParseAuthenticatorTransport(s string) AuthenticatorTransport {
switch s {
case "usb":
return USB
case "nfc":
return NFC
case "ble":
return BLE
case "smart-card":
return SmartCard
case "hybrid":
return Hybrid
default:
return Internal
}
}
type AuthenticatorFlags byte
const (
// FlagUserPresent Bit 00000001 in the byte sequence. Tells us if user is present. Also referred to as the UP flag.
FlagUserPresent AuthenticatorFlags = 1 << iota // Referred to as UP
// FlagRFU1 is a reserved for future use flag.
FlagRFU1
// FlagUserVerified Bit 00000100 in the byte sequence. Tells us if user is verified
// by the authenticator using a biometric or PIN. Also referred to as the UV flag.
FlagUserVerified
// FlagBackupEligible Bit 00001000 in the byte sequence. Tells us if a backup is eligible for device. Also referred
// to as the BE flag.
FlagBackupEligible // Referred to as BE
// FlagBackupState Bit 00010000 in the byte sequence. Tells us if a backup state for device. Also referred to as the
// BS flag.
FlagBackupState
// FlagRFU2 is a reserved for future use flag.
FlagRFU2
// FlagAttestedCredentialData Bit 01000000 in the byte sequence. Indicates whether
// the authenticator added attested credential data. Also referred to as the AT flag.
FlagAttestedCredentialData
// FlagHasExtensions Bit 10000000 in the byte sequence. Indicates if the authenticator data has extensions. Also
// referred to as the ED flag.
FlagHasExtensions
)
type AttestationFormat string
const (
// AttestationFormatPacked is the "packed" attestation statement format is a WebAuthn-optimized format for
// attestation. It uses a very compact but still extensible encoding method. This format is implementable by
// authenticators with limited resources (e.g., secure elements).
AttestationFormatPacked AttestationFormat = "packed"
// AttestationFormatTPM is the TPM attestation statement format returns an attestation statement in the same format
// as the packed attestation statement format, although the rawData and signature fields are computed differently.
AttestationFormatTPM AttestationFormat = "tpm"
// AttestationFormatAndroidKey is the attestation statement format for platform authenticators on versions "N", and
// later, which may provide this proprietary "hardware attestation" statement.
AttestationFormatAndroidKey AttestationFormat = "android-key"
// AttestationFormatAndroidSafetyNet is the attestation statement format that Android-based platform authenticators
// MAY produce an attestation statement based on the Android SafetyNet API.
AttestationFormatAndroidSafetyNet AttestationFormat = "android-safetynet"
// AttestationFormatFIDOUniversalSecondFactor is the attestation statement format that is used with FIDO U2F
// authenticators.
AttestationFormatFIDOUniversalSecondFactor AttestationFormat = "fido-u2f"
// AttestationFormatApple is the attestation statement format that is used with Apple devices' platform
// authenticators.
AttestationFormatApple AttestationFormat = "apple"
// AttestationFormatNone is the attestation statement format that is used to replace any authenticator-provided
// attestation statement when a WebAuthn Relying Party indicates it does not wish to receive attestation information.
AttestationFormatNone AttestationFormat = "none"
)
func ExtractAttestationFormats(p *types.Params) []AttestationFormat {
var formats []AttestationFormat
for _, v := range p.AttestationFormats {
formats = append(formats, parseAttestationFormat(v))
}
return formats
}
func parseAttestationFormat(s string) AttestationFormat {
switch s {
case "packed":
return AttestationFormatPacked
case "tpm":
return AttestationFormatTPM
case "android-key":
return AttestationFormatAndroidKey
case "android-safetynet":
return AttestationFormatAndroidSafetyNet
case "fido-u2f":
return AttestationFormatFIDOUniversalSecondFactor
case "apple":
return AttestationFormatApple
case "none":
return AttestationFormatNone
default:
return AttestationFormatPacked
}
}
type CredentialType string
const (
CredentialTypePublicKeyCredential CredentialType = "public-key"
)
type ConveyancePreference string
const (
// PreferNoAttestation is a ConveyancePreference value.
//
// This value indicates that the Relying Party is not interested in authenticator attestation. For example, in order
// to potentially avoid having to obtain user consent to relay identifying information to the Relying Party, or to
// save a round trip to an Attestation CA or Anonymization CA.
//
// This is the default value.
//
// Specification: §5.4.7. Attestation Conveyance Preference Enumeration (https://www.w3.org/TR/webauthn/#dom-attestationconveyancepreference-none)
PreferNoAttestation ConveyancePreference = "none"
// PreferIndirectAttestation is a ConveyancePreference value.
//
// This value indicates that the Relying Party prefers an attestation conveyance yielding verifiable attestation
// statements, but allows the client to decide how to obtain such attestation statements. The client MAY replace the
// authenticator-generated attestation statements with attestation statements generated by an Anonymization CA, in
// order to protect the users privacy, or to assist Relying Parties with attestation verification in a
// heterogeneous ecosystem.
//
// Note: There is no guarantee that the Relying Party will obtain a verifiable attestation statement in this case.
// For example, in the case that the authenticator employs self attestation.
//
// Specification: §5.4.7. Attestation Conveyance Preference Enumeration (https://www.w3.org/TR/webauthn/#dom-attestationconveyancepreference-indirect)
PreferIndirectAttestation ConveyancePreference = "indirect"
// PreferDirectAttestation is a ConveyancePreference value.
//
// This value indicates that the Relying Party wants to receive the attestation statement as generated by the
// authenticator.
//
// Specification: §5.4.7. Attestation Conveyance Preference Enumeration (https://www.w3.org/TR/webauthn/#dom-attestationconveyancepreference-direct)
PreferDirectAttestation ConveyancePreference = "direct"
// PreferEnterpriseAttestation is a ConveyancePreference value.
//
// This value indicates that the Relying Party wants to receive an attestation statement that may include uniquely
// identifying information. This is intended for controlled deployments within an enterprise where the organization
// wishes to tie registrations to specific authenticators. User agents MUST NOT provide such an attestation unless
// the user agent or authenticator configuration permits it for the requested RP ID.
//
// If permitted, the user agent SHOULD signal to the authenticator (at invocation time) that enterprise
// attestation is requested, and convey the resulting AAGUID and attestation statement, unaltered, to the Relying
// Party.
//
// Specification: §5.4.7. Attestation Conveyance Preference Enumeration (https://www.w3.org/TR/webauthn/#dom-attestationconveyancepreference-enterprise)
PreferEnterpriseAttestation ConveyancePreference = "enterprise"
)
func ExtractConveyancePreference(p *types.Params) ConveyancePreference {
switch p.ConveyancePreference {
case "none":
return PreferNoAttestation
case "indirect":
return PreferIndirectAttestation
case "direct":
return PreferDirectAttestation
case "enterprise":
return PreferEnterpriseAttestation
default:
return PreferNoAttestation
}
}
type PublicKeyCredentialHints string
const (
// PublicKeyCredentialHintSecurityKey is a PublicKeyCredentialHint that indicates that the Relying Party believes
// that users will satisfy this request with a physical security key. For example, an enterprise Relying Party may
// set this hint if they have issued security keys to their employees and will only accept those authenticators for
// registration and authentication.
//
// For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the
// authenticatorAttachment SHOULD be set to cross-platform.
PublicKeyCredentialHintSecurityKey PublicKeyCredentialHints = "security-key"
// PublicKeyCredentialHintClientDevice is a PublicKeyCredentialHint that indicates that the Relying Party believes
// that users will satisfy this request with a platform authenticator attached to the client device.
//
// For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the
// authenticatorAttachment SHOULD be set to platform.
PublicKeyCredentialHintClientDevice PublicKeyCredentialHints = "client-device"
// PublicKeyCredentialHintHybrid is a PublicKeyCredentialHint that indicates that the Relying Party believes that
// users will satisfy this request with general-purpose authenticators such as smartphones. For example, a consumer
// Relying Party may believe that only a small fraction of their customers possesses dedicated security keys. This
// option also implies that the local platform authenticator should not be promoted in the UI.
//
// For compatibility with older user agents, when this hint is used in PublicKeyCredentialCreationOptions, the
// authenticatorAttachment SHOULD be set to cross-platform.
PublicKeyCredentialHintHybrid PublicKeyCredentialHints = "hybrid"
)
func ParsePublicKeyCredentialHints(s string) PublicKeyCredentialHints {
switch s {
case "security-key":
return PublicKeyCredentialHintSecurityKey
case "client-device":
return PublicKeyCredentialHintClientDevice
case "hybrid":
return PublicKeyCredentialHintHybrid
default:
return ""
}
}
type AttestedCredentialData struct {
AAGUID []byte `json:"aaguid"`
CredentialID []byte `json:"credential_id"`
// The raw credential public key bytes received from the attestation data.
CredentialPublicKey []byte `json:"public_key"`
}
type ResidentKeyRequirement string
const (
// ResidentKeyRequirementDiscouraged indicates the Relying Party prefers creating a server-side credential, but will
// accept a client-side discoverable credential. This is the default.
ResidentKeyRequirementDiscouraged ResidentKeyRequirement = "discouraged"
// ResidentKeyRequirementPreferred indicates to the client we would prefer a discoverable credential.
ResidentKeyRequirementPreferred ResidentKeyRequirement = "preferred"
// ResidentKeyRequirementRequired indicates the Relying Party requires a client-side discoverable credential, and is
// prepared to receive an error if a client-side discoverable credential cannot be created.
ResidentKeyRequirementRequired ResidentKeyRequirement = "required"
)
func ParseResidentKeyRequirement(s string) ResidentKeyRequirement {
switch s {
case "discouraged":
return ResidentKeyRequirementDiscouraged
case "preferred":
return ResidentKeyRequirementPreferred
default:
return ResidentKeyRequirementRequired
}
}
type (
AuthenticationExtensions map[string]any
UserVerificationRequirement string
)
const (
// VerificationRequired User verification is required to create/release a credential
VerificationRequired UserVerificationRequirement = "required"
// VerificationPreferred User verification is preferred to create/release a credential
VerificationPreferred UserVerificationRequirement = "preferred" // This is the default
// VerificationDiscouraged The authenticator should not verify the user for the credential
VerificationDiscouraged UserVerificationRequirement = "discouraged"
)

48
x/did/builder/macroon.go Normal file
View File

@ -0,0 +1,48 @@
package builder
import (
"net/http"
"github.com/labstack/echo/v4"
"gopkg.in/macaroon.v2"
"gopkg.in/macaroon-bakery.v2/bakery/checkers"
)
var PermissionNamespace *checkers.Namespace
func ValidateMacaroonMiddleware(secretKey []byte, location string) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Extract the macaroon from the Authorization header
auth := c.Request().Header.Get("Authorization")
if auth == "" {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Missing Authorization header"})
}
// Decode the macaroon
mac, err := macaroon.Base64Decode([]byte(auth))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid macaroon encoding"})
}
token, err := macaroon.New(secretKey, mac, location, macaroon.LatestVersion)
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid macaroon"})
}
// Verify the macaroon
err = token.Verify(secretKey, func(caveat string) error {
// Implement your caveat verification logic here
// For example, you might check if the caveat is still valid (e.g., not expired)
return nil // Return nil if the caveat is valid
}, nil)
if err != nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Invalid macaroon"})
}
// Macaroon is valid, proceed to the next handler
return next(c)
}
}
}

27
x/did/builder/openid.go Normal file
View File

@ -0,0 +1,27 @@
package builder
import (
"fmt"
"github.com/onsonr/sonr/x/did/types/oidc"
)
func GetDiscovery(origin string) *oidc.DiscoveryDocument {
baseURL := "https://" + origin // Ensure this is the correct base URL for your service
discoveryDoc := &oidc.DiscoveryDocument{
Issuer: baseURL,
AuthorizationEndpoint: fmt.Sprintf("%s/auth", baseURL),
TokenEndpoint: fmt.Sprintf("%s/token", baseURL),
UserinfoEndpoint: fmt.Sprintf("%s/userinfo", baseURL),
JwksUri: fmt.Sprintf("%s/jwks", baseURL),
RegistrationEndpoint: fmt.Sprintf("%s/register", baseURL),
ScopesSupported: []string{"openid", "profile", "email", "web3", "sonr"},
ResponseTypesSupported: []string{"code"},
ResponseModesSupported: []string{"query", "form_post"},
GrantTypesSupported: []string{"authorization_code", "refresh_token"},
AcrValuesSupported: []string{"passkey"},
SubjectTypesSupported: []string{"public"},
ClaimsSupported: []string{"sub", "iss", "name", "email"},
}
return discoveryDoc
}

82
x/did/builder/options.go Normal file
View File

@ -0,0 +1,82 @@
package builder
import (
"encoding/json"
"github.com/onsonr/sonr/x/did/types"
)
type AuthenticatorResponse struct {
// From the spec https://www.w3.org/TR/webauthn/#dom-authenticatorresponse-clientdatajson
// This attribute contains a JSON serialization of the client data passed to the authenticator
// by the client in its call to either create() or get().
ClientDataJSON URLEncodedBase64 `json:"clientDataJSON"`
}
type AuthenticatorAttestationResponse struct {
// The byte slice of clientDataJSON, which becomes CollectedClientData
AuthenticatorResponse
Transports []string `json:"transports,omitempty"`
AuthenticatorData URLEncodedBase64 `json:"authenticatorData"`
PublicKey URLEncodedBase64 `json:"publicKey"`
PublicKeyAlgorithm int64 `json:"publicKeyAlgorithm"`
// AttestationObject is the byte slice version of attestationObject.
// This attribute contains an attestation object, which is opaque to, and
// cryptographically protected against tampering by, the client. The
// attestation object contains both authenticator data and an attestation
// statement. The former contains the AAGUID, a unique credential ID, and
// the credential public key. The contents of the attestation statement are
// determined by the attestation statement format used by the authenticator.
// It also contains any additional information that the Relying Party's server
// requires to validate the attestation statement, as well as to decode and
// validate the authenticator data along with the JSON-serialized client data.
AttestationObject URLEncodedBase64 `json:"attestationObject"`
}
type PublicKeyCredentialCreationOptions struct {
RelyingParty RelyingPartyEntity `json:"rp"`
User UserEntity `json:"user"`
Challenge URLEncodedBase64 `json:"challenge"`
Parameters []CredentialParameter `json:"pubKeyCredParams,omitempty"`
Timeout int `json:"timeout,omitempty"`
CredentialExcludeList []CredentialDescriptor `json:"excludeCredentials,omitempty"`
AuthenticatorSelection AuthenticatorSelection `json:"authenticatorSelection,omitempty"`
Hints []PublicKeyCredentialHints `json:"hints,omitempty"`
Attestation ConveyancePreference `json:"attestation,omitempty"`
AttestationFormats []AttestationFormat `json:"attestationFormats,omitempty"`
Extensions AuthenticationExtensions `json:"extensions,omitempty"`
}
func GetPublicKeyCredentialCreationOptions(origin string, subject string, vaultCID string, params *types.Params) (*PublicKeyCredentialCreationOptions, error) {
chal, err := CreateChallenge()
if err != nil {
return nil, err
}
return &PublicKeyCredentialCreationOptions{
RelyingParty: NewRelayingParty(origin, subject),
User: NewUserEntity(subject, subject, vaultCID),
Parameters: ExtractCredentialParameters(params),
Timeout: 20,
CredentialExcludeList: nil,
Challenge: chal,
AuthenticatorSelection: AuthenticatorSelection{},
Hints: nil,
Attestation: ExtractConveyancePreference(params),
AttestationFormats: ExtractAttestationFormats(params),
Extensions: nil,
}, nil
}
func UnmarshalAuthenticatorResponse(data []byte) (*AuthenticatorResponse, error) {
var ar AuthenticatorResponse
err := json.Unmarshal(data, &ar)
if err != nil {
return nil, err
}
return &ar, nil
}

81
x/did/builder/pubkey.go Normal file
View File

@ -0,0 +1,81 @@
package builder
import (
"fmt"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
didv1 "github.com/onsonr/sonr/api/did/v1"
"github.com/onsonr/sonr/x/did/types"
"github.com/go-webauthn/webauthn/protocol/webauthncose"
)
// PublicKey is an interface for a public key
type PublicKey interface {
cryptotypes.PubKey
Clone() cryptotypes.PubKey
GetRaw() []byte
GetRole() types.KeyRole
GetAlgorithm() types.KeyAlgorithm
GetEncoding() types.KeyEncoding
GetCurve() types.KeyCurve
GetKeyType() types.KeyType
}
// CreateAuthnVerification creates a new verification method for an authn method
func CreateAuthnVerification(namespace types.DIDNamespace, issuer string, controller string, pubkey *types.PubKey, identifier string) *types.VerificationMethod {
return &types.VerificationMethod{
Method: namespace,
Controller: controller,
PublicKey: pubkey,
Id: identifier,
Issuer: issuer,
}
}
// CreateWalletVerification creates a new verification method for a wallet
func CreateWalletVerification(namespace types.DIDNamespace, controller string, pubkey *types.PubKey, identifier string) *didv1.VerificationMethod {
return &didv1.VerificationMethod{
Method: APIFormatDIDNamespace(namespace),
Controller: controller,
PublicKey: APIFormatPubKey(pubkey),
Id: identifier,
}
}
// ExtractWebAuthnPublicKey parses the raw public key bytes and returns a JWK representation
func ExtractWebAuthnPublicKey(keyBytes []byte) (*types.PubKey_JWK, error) {
key, err := webauthncose.ParsePublicKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("failed to parse public key: %w", err)
}
switch k := key.(type) {
case *webauthncose.EC2PublicKeyData:
return FormatEC2PublicKey(k)
case *webauthncose.RSAPublicKeyData:
return FormatRSAPublicKey(k)
case *webauthncose.OKPPublicKeyData:
return FormatOKPPublicKey(k)
default:
return nil, fmt.Errorf("unsupported key type")
}
}
// NewInitialWalletAccounts creates a new set of verification methods for a wallet
func NewInitialWalletAccounts(controller string, pubkey *types.PubKey) ([]*didv1.VerificationMethod, error) {
var verificationMethods []*didv1.VerificationMethod
for method, chain := range types.InitialChainCodes {
nk, err := computeBip32AccountPublicKey(pubkey, chain, 0)
if err != nil {
return nil, err
}
addr, err := chain.FormatAddress(nk)
if err != nil {
return nil, nil
}
verificationMethods = append(verificationMethods, CreateWalletVerification(method, controller, nk, method.FormatDID(addr)))
}
return verificationMethods, nil
}

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