this repo has no description

Compare changes

Choose any two refs to compare.

Changed files
+529 -869
api
appview
issues
knots
ogcard
pages
templates
brand
fragments
layouts
repo
fragments
issues
pulls
fragments
settings
fragments
user
settings
fragments
pulls
repo
settings
spindles
state
cmd
cborgen
dolly
docs
ico
lexicons
comment
nix
-416
api/tangled/cbor_gen.go
··· 561 562 return nil 563 } 564 - func (t *Comment) MarshalCBOR(w io.Writer) error { 565 - if t == nil { 566 - _, err := w.Write(cbg.CborNull) 567 - return err 568 - } 569 - 570 - cw := cbg.NewCborWriter(w) 571 - fieldCount := 7 572 - 573 - if t.Mentions == nil { 574 - fieldCount-- 575 - } 576 - 577 - if t.References == nil { 578 - fieldCount-- 579 - } 580 - 581 - if t.ReplyTo == nil { 582 - fieldCount-- 583 - } 584 - 585 - if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { 586 - return err 587 - } 588 - 589 - // t.Body (string) (string) 590 - if len("body") > 1000000 { 591 - return xerrors.Errorf("Value in field \"body\" was too long") 592 - } 593 - 594 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("body"))); err != nil { 595 - return err 596 - } 597 - if _, err := cw.WriteString(string("body")); err != nil { 598 - return err 599 - } 600 - 601 - if len(t.Body) > 1000000 { 602 - return xerrors.Errorf("Value in field t.Body was too long") 603 - } 604 - 605 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Body))); err != nil { 606 - return err 607 - } 608 - if _, err := cw.WriteString(string(t.Body)); err != nil { 609 - return err 610 - } 611 - 612 - // t.LexiconTypeID (string) (string) 613 - if len("$type") > 1000000 { 614 - return xerrors.Errorf("Value in field \"$type\" was too long") 615 - } 616 - 617 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 618 - return err 619 - } 620 - if _, err := cw.WriteString(string("$type")); err != nil { 621 - return err 622 - } 623 - 624 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("sh.tangled.comment"))); err != nil { 625 - return err 626 - } 627 - if _, err := cw.WriteString(string("sh.tangled.comment")); err != nil { 628 - return err 629 - } 630 - 631 - // t.ReplyTo (string) (string) 632 - if t.ReplyTo != nil { 633 - 634 - if len("replyTo") > 1000000 { 635 - return xerrors.Errorf("Value in field \"replyTo\" was too long") 636 - } 637 - 638 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("replyTo"))); err != nil { 639 - return err 640 - } 641 - if _, err := cw.WriteString(string("replyTo")); err != nil { 642 - return err 643 - } 644 - 645 - if t.ReplyTo == nil { 646 - if _, err := cw.Write(cbg.CborNull); err != nil { 647 - return err 648 - } 649 - } else { 650 - if len(*t.ReplyTo) > 1000000 { 651 - return xerrors.Errorf("Value in field t.ReplyTo was too long") 652 - } 653 - 654 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.ReplyTo))); err != nil { 655 - return err 656 - } 657 - if _, err := cw.WriteString(string(*t.ReplyTo)); err != nil { 658 - return err 659 - } 660 - } 661 - } 662 - 663 - // t.Subject (string) (string) 664 - if len("subject") > 1000000 { 665 - return xerrors.Errorf("Value in field \"subject\" was too long") 666 - } 667 - 668 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("subject"))); err != nil { 669 - return err 670 - } 671 - if _, err := cw.WriteString(string("subject")); err != nil { 672 - return err 673 - } 674 - 675 - if len(t.Subject) > 1000000 { 676 - return xerrors.Errorf("Value in field t.Subject was too long") 677 - } 678 - 679 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Subject))); err != nil { 680 - return err 681 - } 682 - if _, err := cw.WriteString(string(t.Subject)); err != nil { 683 - return err 684 - } 685 - 686 - // t.Mentions ([]string) (slice) 687 - if t.Mentions != nil { 688 - 689 - if len("mentions") > 1000000 { 690 - return xerrors.Errorf("Value in field \"mentions\" was too long") 691 - } 692 - 693 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("mentions"))); err != nil { 694 - return err 695 - } 696 - if _, err := cw.WriteString(string("mentions")); err != nil { 697 - return err 698 - } 699 - 700 - if len(t.Mentions) > 8192 { 701 - return xerrors.Errorf("Slice value in field t.Mentions was too long") 702 - } 703 - 704 - if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Mentions))); err != nil { 705 - return err 706 - } 707 - for _, v := range t.Mentions { 708 - if len(v) > 1000000 { 709 - return xerrors.Errorf("Value in field v was too long") 710 - } 711 - 712 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { 713 - return err 714 - } 715 - if _, err := cw.WriteString(string(v)); err != nil { 716 - return err 717 - } 718 - 719 - } 720 - } 721 - 722 - // t.CreatedAt (string) (string) 723 - if len("createdAt") > 1000000 { 724 - return xerrors.Errorf("Value in field \"createdAt\" was too long") 725 - } 726 - 727 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("createdAt"))); err != nil { 728 - return err 729 - } 730 - if _, err := cw.WriteString(string("createdAt")); err != nil { 731 - return err 732 - } 733 - 734 - if len(t.CreatedAt) > 1000000 { 735 - return xerrors.Errorf("Value in field t.CreatedAt was too long") 736 - } 737 - 738 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.CreatedAt))); err != nil { 739 - return err 740 - } 741 - if _, err := cw.WriteString(string(t.CreatedAt)); err != nil { 742 - return err 743 - } 744 - 745 - // t.References ([]string) (slice) 746 - if t.References != nil { 747 - 748 - if len("references") > 1000000 { 749 - return xerrors.Errorf("Value in field \"references\" was too long") 750 - } 751 - 752 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("references"))); err != nil { 753 - return err 754 - } 755 - if _, err := cw.WriteString(string("references")); err != nil { 756 - return err 757 - } 758 - 759 - if len(t.References) > 8192 { 760 - return xerrors.Errorf("Slice value in field t.References was too long") 761 - } 762 - 763 - if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.References))); err != nil { 764 - return err 765 - } 766 - for _, v := range t.References { 767 - if len(v) > 1000000 { 768 - return xerrors.Errorf("Value in field v was too long") 769 - } 770 - 771 - if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { 772 - return err 773 - } 774 - if _, err := cw.WriteString(string(v)); err != nil { 775 - return err 776 - } 777 - 778 - } 779 - } 780 - return nil 781 - } 782 - 783 - func (t *Comment) UnmarshalCBOR(r io.Reader) (err error) { 784 - *t = Comment{} 785 - 786 - cr := cbg.NewCborReader(r) 787 - 788 - maj, extra, err := cr.ReadHeader() 789 - if err != nil { 790 - return err 791 - } 792 - defer func() { 793 - if err == io.EOF { 794 - err = io.ErrUnexpectedEOF 795 - } 796 - }() 797 - 798 - if maj != cbg.MajMap { 799 - return fmt.Errorf("cbor input should be of type map") 800 - } 801 - 802 - if extra > cbg.MaxLength { 803 - return fmt.Errorf("Comment: map struct too large (%d)", extra) 804 - } 805 - 806 - n := extra 807 - 808 - nameBuf := make([]byte, 10) 809 - for i := uint64(0); i < n; i++ { 810 - nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000) 811 - if err != nil { 812 - return err 813 - } 814 - 815 - if !ok { 816 - // Field doesn't exist on this type, so ignore it 817 - if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 818 - return err 819 - } 820 - continue 821 - } 822 - 823 - switch string(nameBuf[:nameLen]) { 824 - // t.Body (string) (string) 825 - case "body": 826 - 827 - { 828 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 829 - if err != nil { 830 - return err 831 - } 832 - 833 - t.Body = string(sval) 834 - } 835 - // t.LexiconTypeID (string) (string) 836 - case "$type": 837 - 838 - { 839 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 840 - if err != nil { 841 - return err 842 - } 843 - 844 - t.LexiconTypeID = string(sval) 845 - } 846 - // t.ReplyTo (string) (string) 847 - case "replyTo": 848 - 849 - { 850 - b, err := cr.ReadByte() 851 - if err != nil { 852 - return err 853 - } 854 - if b != cbg.CborNull[0] { 855 - if err := cr.UnreadByte(); err != nil { 856 - return err 857 - } 858 - 859 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 860 - if err != nil { 861 - return err 862 - } 863 - 864 - t.ReplyTo = (*string)(&sval) 865 - } 866 - } 867 - // t.Subject (string) (string) 868 - case "subject": 869 - 870 - { 871 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 872 - if err != nil { 873 - return err 874 - } 875 - 876 - t.Subject = string(sval) 877 - } 878 - // t.Mentions ([]string) (slice) 879 - case "mentions": 880 - 881 - maj, extra, err = cr.ReadHeader() 882 - if err != nil { 883 - return err 884 - } 885 - 886 - if extra > 8192 { 887 - return fmt.Errorf("t.Mentions: array too large (%d)", extra) 888 - } 889 - 890 - if maj != cbg.MajArray { 891 - return fmt.Errorf("expected cbor array") 892 - } 893 - 894 - if extra > 0 { 895 - t.Mentions = make([]string, extra) 896 - } 897 - 898 - for i := 0; i < int(extra); i++ { 899 - { 900 - var maj byte 901 - var extra uint64 902 - var err error 903 - _ = maj 904 - _ = extra 905 - _ = err 906 - 907 - { 908 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 909 - if err != nil { 910 - return err 911 - } 912 - 913 - t.Mentions[i] = string(sval) 914 - } 915 - 916 - } 917 - } 918 - // t.CreatedAt (string) (string) 919 - case "createdAt": 920 - 921 - { 922 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 923 - if err != nil { 924 - return err 925 - } 926 - 927 - t.CreatedAt = string(sval) 928 - } 929 - // t.References ([]string) (slice) 930 - case "references": 931 - 932 - maj, extra, err = cr.ReadHeader() 933 - if err != nil { 934 - return err 935 - } 936 - 937 - if extra > 8192 { 938 - return fmt.Errorf("t.References: array too large (%d)", extra) 939 - } 940 - 941 - if maj != cbg.MajArray { 942 - return fmt.Errorf("expected cbor array") 943 - } 944 - 945 - if extra > 0 { 946 - t.References = make([]string, extra) 947 - } 948 - 949 - for i := 0; i < int(extra); i++ { 950 - { 951 - var maj byte 952 - var extra uint64 953 - var err error 954 - _ = maj 955 - _ = extra 956 - _ = err 957 - 958 - { 959 - sval, err := cbg.ReadStringWithMax(cr, 1000000) 960 - if err != nil { 961 - return err 962 - } 963 - 964 - t.References[i] = string(sval) 965 - } 966 - 967 - } 968 - } 969 - 970 - default: 971 - // Field doesn't exist on this type, so ignore it 972 - if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 973 - return err 974 - } 975 - } 976 - } 977 - 978 - return nil 979 - } 980 func (t *FeedReaction) MarshalCBOR(w io.Writer) error { 981 if t == nil { 982 _, err := w.Write(cbg.CborNull)
··· 561 562 return nil 563 } 564 func (t *FeedReaction) MarshalCBOR(w io.Writer) error { 565 if t == nil { 566 _, err := w.Write(cbg.CborNull)
-27
api/tangled/tangledcomment.go
··· 1 - // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 - 3 - package tangled 4 - 5 - // schema: sh.tangled.comment 6 - 7 - import ( 8 - "github.com/bluesky-social/indigo/lex/util" 9 - ) 10 - 11 - const ( 12 - CommentNSID = "sh.tangled.comment" 13 - ) 14 - 15 - func init() { 16 - util.RegisterType("sh.tangled.comment", &Comment{}) 17 - } // 18 - // RECORDTYPE: Comment 19 - type Comment struct { 20 - LexiconTypeID string `json:"$type,const=sh.tangled.comment" cborgen:"$type,const=sh.tangled.comment"` 21 - Body string `json:"body" cborgen:"body"` 22 - CreatedAt string `json:"createdAt" cborgen:"createdAt"` 23 - Mentions []string `json:"mentions,omitempty" cborgen:"mentions,omitempty"` 24 - References []string `json:"references,omitempty" cborgen:"references,omitempty"` 25 - ReplyTo *string `json:"replyTo,omitempty" cborgen:"replyTo,omitempty"` 26 - Subject string `json:"subject" cborgen:"subject"` 27 - }
···
+8 -9
appview/issues/issues.go
··· 129 } 130 131 rp.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{ 132 - LoggedInUser: user, 133 - RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 134 - Issue: issue, 135 - CommentList: issue.CommentList(), 136 - Backlinks: backlinks, 137 - OrderedReactionKinds: models.OrderedReactionKinds, 138 - Reactions: reactionMap, 139 - UserReacted: userReactions, 140 - LabelDefs: defs, 141 }) 142 } 143
··· 129 } 130 131 rp.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{ 132 + LoggedInUser: user, 133 + RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 134 + Issue: issue, 135 + CommentList: issue.CommentList(), 136 + Backlinks: backlinks, 137 + Reactions: reactionMap, 138 + UserReacted: userReactions, 139 + LabelDefs: defs, 140 }) 141 } 142
+2 -2
appview/issues/opengraph.go
··· 193 dollyX := dollyBounds.Min.X + (dollyBounds.Dx() / 2) - (dollySize / 2) 194 dollyY := statsY + iconBaselineOffset - dollySize/2 + 25 195 dollyColor := color.RGBA{180, 180, 180, 255} // light gray 196 - err = dollyArea.DrawDollySilhouette(dollyX, dollyY, dollySize, dollyColor) 197 if err != nil { 198 - log.Printf("dolly silhouette not available (this is ok): %v", err) 199 } 200 201 // Draw "opened by @author" and date at the bottom with more spacing
··· 193 dollyX := dollyBounds.Min.X + (dollyBounds.Dx() / 2) - (dollySize / 2) 194 dollyY := statsY + iconBaselineOffset - dollySize/2 + 25 195 dollyColor := color.RGBA{180, 180, 180, 255} // light gray 196 + err = dollyArea.DrawDolly(dollyX, dollyY, dollySize, dollyColor) 197 if err != nil { 198 + log.Printf("dolly not available (this is ok): %v", err) 199 } 200 201 // Draw "opened by @author" and date at the bottom with more spacing
-15
appview/knots/knots.go
··· 40 Knotstream *eventconsumer.Consumer 41 } 42 43 - type tab = map[string]any 44 - 45 - var ( 46 - knotsTabs []tab = []tab{ 47 - {"Name": "profile", "Icon": "user"}, 48 - {"Name": "keys", "Icon": "key"}, 49 - {"Name": "emails", "Icon": "mail"}, 50 - {"Name": "notifications", "Icon": "bell"}, 51 - {"Name": "knots", "Icon": "volleyball"}, 52 - {"Name": "spindles", "Icon": "spool"}, 53 - } 54 - ) 55 - 56 func (k *Knots) Router() http.Handler { 57 r := chi.NewRouter() 58 ··· 84 k.Pages.Knots(w, pages.KnotsParams{ 85 LoggedInUser: user, 86 Registrations: registrations, 87 - Tabs: knotsTabs, 88 Tab: "knots", 89 }) 90 } ··· 148 Members: members, 149 Repos: repoMap, 150 IsOwner: true, 151 - Tabs: knotsTabs, 152 Tab: "knots", 153 }) 154 }
··· 40 Knotstream *eventconsumer.Consumer 41 } 42 43 func (k *Knots) Router() http.Handler { 44 r := chi.NewRouter() 45 ··· 71 k.Pages.Knots(w, pages.KnotsParams{ 72 LoggedInUser: user, 73 Registrations: registrations, 74 Tab: "knots", 75 }) 76 } ··· 134 Members: members, 135 Repos: repoMap, 136 IsOwner: true, 137 Tab: "knots", 138 }) 139 }
+9 -9
appview/ogcard/card.go
··· 334 return nil 335 } 336 337 - func (c *Card) DrawDollySilhouette(x, y, size int, iconColor color.Color) error { 338 tpl, err := template.New("dolly"). 339 - ParseFS(pages.Files, "templates/fragments/dolly/silhouette.html") 340 if err != nil { 341 - return fmt.Errorf("failed to read dolly silhouette template: %w", err) 342 } 343 344 var svgData bytes.Buffer 345 - if err = tpl.ExecuteTemplate(&svgData, "fragments/dolly/silhouette", nil); err != nil { 346 - return fmt.Errorf("failed to execute dolly silhouette template: %w", err) 347 } 348 349 icon, err := BuildSVGIconFromData(svgData.Bytes(), iconColor) ··· 453 454 // Handle SVG separately 455 if contentType == "image/svg+xml" || strings.HasSuffix(url, ".svg") { 456 - return c.convertSVGToPNG(bodyBytes) 457 } 458 459 // Support content types are in-sync with the allowed custom avatar file types ··· 493 } 494 495 // convertSVGToPNG converts SVG data to a PNG image 496 - func (c *Card) convertSVGToPNG(svgData []byte) (image.Image, bool) { 497 // Parse the SVG 498 icon, err := oksvg.ReadIconStream(bytes.NewReader(svgData)) 499 if err != nil { ··· 547 draw.CatmullRom.Scale(scaledImg, scaledImg.Bounds(), img, srcBounds, draw.Src, nil) 548 549 // Draw the image with circular clipping 550 - for cy := 0; cy < size; cy++ { 551 - for cx := 0; cx < size; cx++ { 552 // Calculate distance from center 553 dx := float64(cx - center) 554 dy := float64(cy - center)
··· 334 return nil 335 } 336 337 + func (c *Card) DrawDolly(x, y, size int, iconColor color.Color) error { 338 tpl, err := template.New("dolly"). 339 + ParseFS(pages.Files, "templates/fragments/dolly/logo.html") 340 if err != nil { 341 + return fmt.Errorf("failed to read dolly template: %w", err) 342 } 343 344 var svgData bytes.Buffer 345 + if err = tpl.ExecuteTemplate(&svgData, "fragments/dolly/logo", nil); err != nil { 346 + return fmt.Errorf("failed to execute dolly template: %w", err) 347 } 348 349 icon, err := BuildSVGIconFromData(svgData.Bytes(), iconColor) ··· 453 454 // Handle SVG separately 455 if contentType == "image/svg+xml" || strings.HasSuffix(url, ".svg") { 456 + return convertSVGToPNG(bodyBytes) 457 } 458 459 // Support content types are in-sync with the allowed custom avatar file types ··· 493 } 494 495 // convertSVGToPNG converts SVG data to a PNG image 496 + func convertSVGToPNG(svgData []byte) (image.Image, bool) { 497 // Parse the SVG 498 icon, err := oksvg.ReadIconStream(bytes.NewReader(svgData)) 499 if err != nil { ··· 547 draw.CatmullRom.Scale(scaledImg, scaledImg.Bounds(), img, srcBounds, draw.Src, nil) 548 549 // Draw the image with circular clipping 550 + for cy := range size { 551 + for cx := range size { 552 // Calculate distance from center 553 dx := float64(cx - center) 554 dy := float64(cy - center)
+22
appview/pages/funcmap.go
··· 32 "tangled.org/core/crypto" 33 ) 34 35 func (p *Pages) funcMap() template.FuncMap { 36 return template.FuncMap{ 37 "split": func(s string) []string { ··· 384 return "error" 385 } 386 return fp 387 }, 388 } 389 }
··· 32 "tangled.org/core/crypto" 33 ) 34 35 + type tab map[string]string 36 + 37 func (p *Pages) funcMap() template.FuncMap { 38 return template.FuncMap{ 39 "split": func(s string) []string { ··· 386 return "error" 387 } 388 return fp 389 + }, 390 + // constant values used to define a template 391 + "const": func() map[string]any { 392 + return map[string]any{ 393 + "OrderedReactionKinds": models.OrderedReactionKinds, 394 + // would be great to have ordered maps right about now 395 + "UserSettingsTabs": []tab{ 396 + {"Name": "profile", "Icon": "user"}, 397 + {"Name": "keys", "Icon": "key"}, 398 + {"Name": "emails", "Icon": "mail"}, 399 + {"Name": "notifications", "Icon": "bell"}, 400 + {"Name": "knots", "Icon": "volleyball"}, 401 + {"Name": "spindles", "Icon": "spool"}, 402 + }, 403 + "RepoSettingsTabs": []tab{ 404 + {"Name": "general", "Icon": "sliders-horizontal"}, 405 + {"Name": "access", "Icon": "users"}, 406 + {"Name": "pipelines", "Icon": "layers-2"}, 407 + }, 408 + } 409 }, 410 } 411 }
+30 -35
appview/pages/pages.go
··· 210 return tpl.ExecuteTemplate(w, "layouts/base", params) 211 } 212 213 func (p *Pages) Favicon(w io.Writer) error { 214 - return p.executePlain("fragments/dolly/silhouette", w, nil) 215 } 216 217 type LoginParams struct { ··· 325 326 type UserProfileSettingsParams struct { 327 LoggedInUser *oauth.User 328 - Tabs []map[string]any 329 Tab string 330 } 331 ··· 364 type UserKeysSettingsParams struct { 365 LoggedInUser *oauth.User 366 PubKeys []models.PublicKey 367 - Tabs []map[string]any 368 Tab string 369 } 370 ··· 375 type UserEmailsSettingsParams struct { 376 LoggedInUser *oauth.User 377 Emails []models.Email 378 - Tabs []map[string]any 379 Tab string 380 } 381 ··· 386 type UserNotificationSettingsParams struct { 387 LoggedInUser *oauth.User 388 Preferences *models.NotificationPreferences 389 - Tabs []map[string]any 390 Tab string 391 } 392 ··· 406 type KnotsParams struct { 407 LoggedInUser *oauth.User 408 Registrations []models.Registration 409 - Tabs []map[string]any 410 Tab string 411 } 412 ··· 420 Members []string 421 Repos map[string][]models.Repo 422 IsOwner bool 423 - Tabs []map[string]any 424 Tab string 425 } 426 ··· 439 type SpindlesParams struct { 440 LoggedInUser *oauth.User 441 Spindles []models.Spindle 442 - Tabs []map[string]any 443 Tab string 444 } 445 ··· 449 450 type SpindleListingParams struct { 451 models.Spindle 452 - Tabs []map[string]any 453 Tab string 454 } 455 ··· 462 Spindle models.Spindle 463 Members []string 464 Repos map[string][]models.Repo 465 - Tabs []map[string]any 466 Tab string 467 } 468 ··· 870 SubscribedLabels map[string]struct{} 871 ShouldSubscribeAll bool 872 Active string 873 - Tabs []map[string]any 874 Tab string 875 Branches []types.Branch 876 } ··· 884 LoggedInUser *oauth.User 885 RepoInfo repoinfo.RepoInfo 886 Active string 887 - Tabs []map[string]any 888 Tab string 889 Collaborators []Collaborator 890 } ··· 898 LoggedInUser *oauth.User 899 RepoInfo repoinfo.RepoInfo 900 Active string 901 - Tabs []map[string]any 902 Tab string 903 Spindles []string 904 CurrentSpindle string ··· 936 Backlinks []models.RichReferenceLink 937 LabelDefs map[string]*models.LabelDefinition 938 939 - OrderedReactionKinds []models.ReactionKind 940 - Reactions map[models.ReactionKind]models.ReactionDisplayData 941 - UserReacted map[models.ReactionKind]bool 942 } 943 944 func (p *Pages) RepoSingleIssue(w io.Writer, params RepoSingleIssueParams) error { ··· 1093 ResubmitCheck ResubmitResult 1094 Pipelines map[string]models.Pipeline 1095 1096 - OrderedReactionKinds []models.ReactionKind 1097 - Reactions map[models.ReactionKind]models.ReactionDisplayData 1098 - UserReacted map[models.ReactionKind]bool 1099 1100 LabelDefs map[string]*models.LabelDefinition 1101 } ··· 1106 } 1107 1108 type RepoPullPatchParams struct { 1109 - LoggedInUser *oauth.User 1110 - RepoInfo repoinfo.RepoInfo 1111 - Pull *models.Pull 1112 - Stack models.Stack 1113 - Diff *types.NiceDiff 1114 - Round int 1115 - Submission *models.PullSubmission 1116 - OrderedReactionKinds []models.ReactionKind 1117 - DiffOpts types.DiffOpts 1118 } 1119 1120 // this name is a mouthful ··· 1123 } 1124 1125 type RepoPullInterdiffParams struct { 1126 - LoggedInUser *oauth.User 1127 - RepoInfo repoinfo.RepoInfo 1128 - Pull *models.Pull 1129 - Round int 1130 - Interdiff *patchutil.InterdiffResult 1131 - OrderedReactionKinds []models.ReactionKind 1132 - DiffOpts types.DiffOpts 1133 } 1134 1135 // this name is a mouthful
··· 210 return tpl.ExecuteTemplate(w, "layouts/base", params) 211 } 212 213 + type DollyParams struct { 214 + Classes string 215 + FillColor string 216 + } 217 + 218 + func (p *Pages) Dolly(w io.Writer, params DollyParams) error { 219 + return p.executePlain("fragments/dolly/logo", w, params) 220 + } 221 + 222 func (p *Pages) Favicon(w io.Writer) error { 223 + return p.Dolly(w, DollyParams{ 224 + Classes: "text-black dark:text-white", 225 + }) 226 } 227 228 type LoginParams struct { ··· 336 337 type UserProfileSettingsParams struct { 338 LoggedInUser *oauth.User 339 Tab string 340 } 341 ··· 374 type UserKeysSettingsParams struct { 375 LoggedInUser *oauth.User 376 PubKeys []models.PublicKey 377 Tab string 378 } 379 ··· 384 type UserEmailsSettingsParams struct { 385 LoggedInUser *oauth.User 386 Emails []models.Email 387 Tab string 388 } 389 ··· 394 type UserNotificationSettingsParams struct { 395 LoggedInUser *oauth.User 396 Preferences *models.NotificationPreferences 397 Tab string 398 } 399 ··· 413 type KnotsParams struct { 414 LoggedInUser *oauth.User 415 Registrations []models.Registration 416 Tab string 417 } 418 ··· 426 Members []string 427 Repos map[string][]models.Repo 428 IsOwner bool 429 Tab string 430 } 431 ··· 444 type SpindlesParams struct { 445 LoggedInUser *oauth.User 446 Spindles []models.Spindle 447 Tab string 448 } 449 ··· 453 454 type SpindleListingParams struct { 455 models.Spindle 456 Tab string 457 } 458 ··· 465 Spindle models.Spindle 466 Members []string 467 Repos map[string][]models.Repo 468 Tab string 469 } 470 ··· 872 SubscribedLabels map[string]struct{} 873 ShouldSubscribeAll bool 874 Active string 875 Tab string 876 Branches []types.Branch 877 } ··· 885 LoggedInUser *oauth.User 886 RepoInfo repoinfo.RepoInfo 887 Active string 888 Tab string 889 Collaborators []Collaborator 890 } ··· 898 LoggedInUser *oauth.User 899 RepoInfo repoinfo.RepoInfo 900 Active string 901 Tab string 902 Spindles []string 903 CurrentSpindle string ··· 935 Backlinks []models.RichReferenceLink 936 LabelDefs map[string]*models.LabelDefinition 937 938 + Reactions map[models.ReactionKind]models.ReactionDisplayData 939 + UserReacted map[models.ReactionKind]bool 940 } 941 942 func (p *Pages) RepoSingleIssue(w io.Writer, params RepoSingleIssueParams) error { ··· 1091 ResubmitCheck ResubmitResult 1092 Pipelines map[string]models.Pipeline 1093 1094 + Reactions map[models.ReactionKind]models.ReactionDisplayData 1095 + UserReacted map[models.ReactionKind]bool 1096 1097 LabelDefs map[string]*models.LabelDefinition 1098 } ··· 1103 } 1104 1105 type RepoPullPatchParams struct { 1106 + LoggedInUser *oauth.User 1107 + RepoInfo repoinfo.RepoInfo 1108 + Pull *models.Pull 1109 + Stack models.Stack 1110 + Diff *types.NiceDiff 1111 + Round int 1112 + Submission *models.PullSubmission 1113 + DiffOpts types.DiffOpts 1114 } 1115 1116 // this name is a mouthful ··· 1119 } 1120 1121 type RepoPullInterdiffParams struct { 1122 + LoggedInUser *oauth.User 1123 + RepoInfo repoinfo.RepoInfo 1124 + Pull *models.Pull 1125 + Round int 1126 + Interdiff *patchutil.InterdiffResult 1127 + DiffOpts types.DiffOpts 1128 } 1129 1130 // this name is a mouthful
+9 -29
appview/pages/templates/brand/brand.html
··· 4 <div class="grid grid-cols-10"> 5 <header class="col-span-full md:col-span-10 px-6 py-2 mb-4"> 6 <h1 class="text-2xl font-bold dark:text-white mb-1">Brand</h1> 7 - <p class="text-gray-600 dark:text-gray-400 mb-1"> 8 Assets and guidelines for using Tangled's logo and brand elements. 9 </p> 10 </header> ··· 14 15 <!-- Introduction Section --> 16 <section> 17 - <p class="text-gray-600 dark:text-gray-400 mb-2"> 18 Tangled's logo and mascot is <strong>Dolly</strong>, the first ever <em>cloned</em> mammal. Please 19 follow the below guidelines when using Dolly and the logotype. 20 </p> 21 - <p class="text-gray-600 dark:text-gray-400 mb-2"> 22 All assets are served as SVGs, and can be downloaded by right-clicking and clicking "Save image as". 23 </p> 24 </section> ··· 34 </div> 35 <div class="order-1 lg:order-2"> 36 <h2 class="text-xl font-semibold dark:text-white mb-3">Black logotype</h2> 37 - <p class="text-gray-600 dark:text-gray-400 mb-4">For use on light-colored backgrounds.</p> 38 <p class="text-gray-700 dark:text-gray-300"> 39 This is the preferred version of the logotype, featuring dark text and elements, ideal for light 40 backgrounds and designs. ··· 53 </div> 54 <div class="order-1 lg:order-2"> 55 <h2 class="text-xl font-semibold dark:text-white mb-3">White logotype</h2> 56 - <p class="text-gray-600 dark:text-gray-400 mb-4">For use on dark-colored backgrounds.</p> 57 <p class="text-gray-700 dark:text-gray-300"> 58 This version features white text and elements, ideal for dark backgrounds 59 and inverted designs. ··· 81 </div> 82 <div class="order-1 lg:order-2"> 83 <h2 class="text-xl font-semibold dark:text-white mb-3">Mark only</h2> 84 - <p class="text-gray-600 dark:text-gray-400 mb-4"> 85 When a smaller 1:1 logo or icon is needed, Dolly's face may be used on its own. 86 </p> 87 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 123 </div> 124 <div class="order-1 lg:order-2"> 125 <h2 class="text-xl font-semibold dark:text-white mb-3">Colored backgrounds</h2> 126 - <p class="text-gray-600 dark:text-gray-400 mb-4"> 127 White logo mark on colored backgrounds. 128 </p> 129 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 165 </div> 166 <div class="order-1 lg:order-2"> 167 <h2 class="text-xl font-semibold dark:text-white mb-3">Lighter backgrounds</h2> 168 - <p class="text-gray-600 dark:text-gray-400 mb-4"> 169 Dark logo mark on lighter, pastel backgrounds. 170 </p> 171 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 186 </div> 187 <div class="order-1 lg:order-2"> 188 <h2 class="text-xl font-semibold dark:text-white mb-3">Recoloring</h2> 189 - <p class="text-gray-600 dark:text-gray-400 mb-4"> 190 Custom coloring of the logotype is permitted. 191 </p> 192 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 194 </p> 195 <p class="text-gray-700 dark:text-gray-300 text-sm"> 196 <strong>Example:</strong> Gray/sand colored logotype on a light yellow/tan background. 197 - </p> 198 - </div> 199 - </section> 200 - 201 - <!-- Silhouette Section --> 202 - <section class="grid grid-cols-1 lg:grid-cols-2 gap-8 items-center"> 203 - <div class="order-2 lg:order-1"> 204 - <div class="border border-gray-200 dark:border-gray-700 p-8 sm:p-16 bg-gray-50 dark:bg-gray-100 rounded"> 205 - <img src="https://assets.tangled.network/tangled_dolly_silhouette.svg" 206 - alt="Dolly silhouette" 207 - class="w-full max-w-32 mx-auto" /> 208 - </div> 209 - </div> 210 - <div class="order-1 lg:order-2"> 211 - <h2 class="text-xl font-semibold dark:text-white mb-3">Dolly silhouette</h2> 212 - <p class="text-gray-600 dark:text-gray-400 mb-4">A minimalist version of Dolly.</p> 213 - <p class="text-gray-700 dark:text-gray-300"> 214 - The silhouette can be used where a subtle brand presence is needed, 215 - or as a background element. Works on any background color with proper contrast. 216 - For example, we use this as the site's favicon. 217 </p> 218 </div> 219 </section>
··· 4 <div class="grid grid-cols-10"> 5 <header class="col-span-full md:col-span-10 px-6 py-2 mb-4"> 6 <h1 class="text-2xl font-bold dark:text-white mb-1">Brand</h1> 7 + <p class="text-gray-500 dark:text-gray-300 mb-1"> 8 Assets and guidelines for using Tangled's logo and brand elements. 9 </p> 10 </header> ··· 14 15 <!-- Introduction Section --> 16 <section> 17 + <p class="text-gray-500 dark:text-gray-300 mb-2"> 18 Tangled's logo and mascot is <strong>Dolly</strong>, the first ever <em>cloned</em> mammal. Please 19 follow the below guidelines when using Dolly and the logotype. 20 </p> 21 + <p class="text-gray-500 dark:text-gray-300 mb-2"> 22 All assets are served as SVGs, and can be downloaded by right-clicking and clicking "Save image as". 23 </p> 24 </section> ··· 34 </div> 35 <div class="order-1 lg:order-2"> 36 <h2 class="text-xl font-semibold dark:text-white mb-3">Black logotype</h2> 37 + <p class="text-gray-500 dark:text-gray-300 mb-4">For use on light-colored backgrounds.</p> 38 <p class="text-gray-700 dark:text-gray-300"> 39 This is the preferred version of the logotype, featuring dark text and elements, ideal for light 40 backgrounds and designs. ··· 53 </div> 54 <div class="order-1 lg:order-2"> 55 <h2 class="text-xl font-semibold dark:text-white mb-3">White logotype</h2> 56 + <p class="text-gray-500 dark:text-gray-300 mb-4">For use on dark-colored backgrounds.</p> 57 <p class="text-gray-700 dark:text-gray-300"> 58 This version features white text and elements, ideal for dark backgrounds 59 and inverted designs. ··· 81 </div> 82 <div class="order-1 lg:order-2"> 83 <h2 class="text-xl font-semibold dark:text-white mb-3">Mark only</h2> 84 + <p class="text-gray-500 dark:text-gray-300 mb-4"> 85 When a smaller 1:1 logo or icon is needed, Dolly's face may be used on its own. 86 </p> 87 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 123 </div> 124 <div class="order-1 lg:order-2"> 125 <h2 class="text-xl font-semibold dark:text-white mb-3">Colored backgrounds</h2> 126 + <p class="text-gray-500 dark:text-gray-300 mb-4"> 127 White logo mark on colored backgrounds. 128 </p> 129 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 165 </div> 166 <div class="order-1 lg:order-2"> 167 <h2 class="text-xl font-semibold dark:text-white mb-3">Lighter backgrounds</h2> 168 + <p class="text-gray-500 dark:text-gray-300 mb-4"> 169 Dark logo mark on lighter, pastel backgrounds. 170 </p> 171 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 186 </div> 187 <div class="order-1 lg:order-2"> 188 <h2 class="text-xl font-semibold dark:text-white mb-3">Recoloring</h2> 189 + <p class="text-gray-500 dark:text-gray-300 mb-4"> 190 Custom coloring of the logotype is permitted. 191 </p> 192 <p class="text-gray-700 dark:text-gray-300 mb-4"> ··· 194 </p> 195 <p class="text-gray-700 dark:text-gray-300 text-sm"> 196 <strong>Example:</strong> Gray/sand colored logotype on a light yellow/tan background. 197 </p> 198 </div> 199 </section>
+14 -2
appview/pages/templates/fragments/dolly/logo.html
··· 2 <svg 3 version="1.1" 4 id="svg1" 5 - class="{{ . }}" 6 width="25" 7 height="25" 8 viewBox="0 0 25 25" ··· 17 xmlns:svg="http://www.w3.org/2000/svg" 18 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 19 xmlns:cc="http://creativecommons.org/ns#"> 20 <sodipodi:namedview 21 id="namedview1" 22 pagecolor="#ffffff" ··· 51 id="g1" 52 transform="translate(-0.42924038,-0.87777209)"> 53 <path 54 - fill="currentColor" 55 style="stroke-width:0.111183;" 56 d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z m 0.686342,-3.497495 c -0.643126,-0.394168 -0.33365,-1.249599 -0.359402,-1.870938 0.064,-0.749774 0.115321,-1.538054 0.452402,-2.221125 0.356724,-0.487008 1.226721,-0.299139 1.265134,0.325689 -0.02558,0.628509 -0.314101,1.25416 -0.279646,1.9057 -0.07482,0.544043 0.05418,1.155133 -0.186476,1.652391 -0.197455,0.275121 -0.599638,0.355105 -0.892012,0.208283 z m -2.808766,-0.358124 c -0.605767,-0.328664 -0.4133176,-1.155655 -0.5083256,-1.73063 0.078762,-0.66567 0.013203,-1.510085 0.5705316,-1.976886 0.545037,-0.380109 1.286917,0.270803 1.029164,0.868384 -0.274913,0.755214 -0.09475,1.580345 -0.08893,2.34609 -0.104009,0.451702 -0.587146,0.691508 -1.002445,0.493042 z" 57 id="path4"
··· 2 <svg 3 version="1.1" 4 id="svg1" 5 + class="{{ .Classes }}" 6 width="25" 7 height="25" 8 viewBox="0 0 25 25" ··· 17 xmlns:svg="http://www.w3.org/2000/svg" 18 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 19 xmlns:cc="http://creativecommons.org/ns#"> 20 + <style> 21 + .dolly { 22 + color: #000000; 23 + } 24 + 25 + @media (prefers-color-scheme: dark) { 26 + .dolly { 27 + color: #ffffff; 28 + } 29 + } 30 + </style> 31 <sodipodi:namedview 32 id="namedview1" 33 pagecolor="#ffffff" ··· 62 id="g1" 63 transform="translate(-0.42924038,-0.87777209)"> 64 <path 65 + class="dolly" 66 + fill="{{ or .FillColor "currentColor" }}" 67 style="stroke-width:0.111183;" 68 d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z m 0.686342,-3.497495 c -0.643126,-0.394168 -0.33365,-1.249599 -0.359402,-1.870938 0.064,-0.749774 0.115321,-1.538054 0.452402,-2.221125 0.356724,-0.487008 1.226721,-0.299139 1.265134,0.325689 -0.02558,0.628509 -0.314101,1.25416 -0.279646,1.9057 -0.07482,0.544043 0.05418,1.155133 -0.186476,1.652391 -0.197455,0.275121 -0.599638,0.355105 -0.892012,0.208283 z m -2.808766,-0.358124 c -0.605767,-0.328664 -0.4133176,-1.155655 -0.5083256,-1.73063 0.078762,-0.66567 0.013203,-1.510085 0.5705316,-1.976886 0.545037,-0.380109 1.286917,0.270803 1.029164,0.868384 -0.274913,0.755214 -0.09475,1.580345 -0.08893,2.34609 -0.104009,0.451702 -0.587146,0.691508 -1.002445,0.493042 z" 69 id="path4"
-95
appview/pages/templates/fragments/dolly/silhouette.html
··· 1 - {{ define "fragments/dolly/silhouette" }} 2 - <svg 3 - version="1.1" 4 - id="svg1" 5 - width="25" 6 - height="25" 7 - viewBox="0 0 25 25" 8 - sodipodi:docname="tangled_dolly_face_only_black_on_trans.svg" 9 - inkscape:export-filename="tangled_dolly_silhouette_black_on_trans.svg" 10 - inkscape:export-xdpi="96" 11 - inkscape:export-ydpi="96" 12 - inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 13 - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 14 - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 15 - xmlns="http://www.w3.org/2000/svg" 16 - xmlns:svg="http://www.w3.org/2000/svg" 17 - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 18 - xmlns:cc="http://creativecommons.org/ns#"> 19 - <style> 20 - .dolly { 21 - color: #000000; 22 - } 23 - 24 - @media (prefers-color-scheme: dark) { 25 - .dolly { 26 - color: #ffffff; 27 - } 28 - } 29 - </style> 30 - <sodipodi:namedview 31 - id="namedview1" 32 - pagecolor="#ffffff" 33 - bordercolor="#000000" 34 - borderopacity="0.25" 35 - inkscape:showpageshadow="2" 36 - inkscape:pageopacity="0.0" 37 - inkscape:pagecheckerboard="true" 38 - inkscape:deskcolor="#d5d5d5" 39 - inkscape:zoom="64" 40 - inkscape:cx="4.96875" 41 - inkscape:cy="13.429688" 42 - inkscape:window-width="3840" 43 - inkscape:window-height="2160" 44 - inkscape:window-x="0" 45 - inkscape:window-y="0" 46 - inkscape:window-maximized="0" 47 - inkscape:current-layer="g1" 48 - borderlayer="true"> 49 - <inkscape:page 50 - x="0" 51 - y="0" 52 - width="25" 53 - height="25" 54 - id="page2" 55 - margin="0" 56 - bleed="0" /> 57 - </sodipodi:namedview> 58 - <g 59 - inkscape:groupmode="layer" 60 - inkscape:label="Image" 61 - id="g1" 62 - transform="translate(-0.42924038,-0.87777209)"> 63 - <path 64 - class="dolly" 65 - fill="currentColor" 66 - style="stroke-width:0.111183" 67 - d="m 16.775491,24.987061 c -0.78517,-0.0064 -1.384202,-0.234614 -2.033994,-0.631295 -0.931792,-0.490188 -1.643475,-1.31368 -2.152014,-2.221647 C 11.781409,23.136647 10.701392,23.744942 9.4922931,24.0886 8.9774725,24.238111 8.0757679,24.389777 6.5811304,23.84827 4.4270703,23.124679 2.8580086,20.883331 3.0363279,18.599583 3.0037061,17.652919 3.3488675,16.723769 3.8381157,15.925061 2.5329485,15.224503 1.4686756,14.048584 1.0611184,12.606459 0.81344502,11.816973 0.82385989,10.966486 0.91519098,10.154906 1.2422711,8.2387903 2.6795811,6.5725716 4.5299585,5.9732484 5.2685364,4.290122 6.8802592,3.0349975 8.706276,2.7794663 c 1.2124148,-0.1688264 2.46744,0.084987 3.52811,0.7011837 1.545426,-1.7139736 4.237779,-2.2205077 6.293579,-1.1676231 1.568222,0.7488935 2.689625,2.3113526 2.961888,4.0151464 1.492195,0.5977882 2.749007,1.8168898 3.242225,3.3644951 0.329805,0.9581836 0.340709,2.0135956 0.127128,2.9974286 -0.381606,1.535184 -1.465322,2.842146 -2.868035,3.556463 0.0034,0.273204 0.901506,2.243045 0.751284,3.729647 -0.03281,1.858525 -1.211631,3.619894 -2.846433,4.475452 -0.953967,0.556812 -2.084452,0.546309 -3.120531,0.535398 z m -4.470079,-5.349839 c 1.322246,-0.147248 2.189053,-1.300106 2.862307,-2.338363 0.318287,-0.472954 0.561404,-1.002348 0.803,-1.505815 0.313265,0.287151 0.578698,0.828085 1.074141,0.956909 0.521892,0.162542 1.133743,0.03052 1.45325,-0.443554 0.611414,-1.140449 0.31004,-2.516537 -0.04602,-3.698347 C 18.232844,11.92927 17.945151,11.232927 17.397785,10.751793 17.514522,9.9283111 17.026575,9.0919791 16.332883,8.6609491 15.741721,9.1323278 14.842258,9.1294949 14.271975,8.6252369 13.178927,9.7400102 12.177239,9.7029996 11.209704,8.8195135 10.992255,8.6209543 10.577326,10.031484 9.1211947,9.2324497 8.2846288,9.9333947 7.6359672,10.607693 7.0611981,11.578553 6.5026891,12.62523 5.9177873,13.554793 5.867393,14.69141 c -0.024234,0.66432 0.4948601,1.360337 1.1982269,1.306329 0.702996,0.06277 1.1815208,-0.629091 1.7138087,-0.916491 0.079382,0.927141 0.1688108,1.923227 0.4821259,2.828358 0.3596254,1.171275 1.6262605,1.915695 2.8251855,1.745211 0.08481,-0.0066 0.218672,-0.01769 0.218672,-0.0176 z" 68 - id="path7" 69 - sodipodi:nodetypes="sccccccccccccccccccsscccccccccscccccccsc" /> 70 - </g> 71 - <metadata 72 - id="metadata1"> 73 - <rdf:RDF> 74 - <cc:Work 75 - rdf:about=""> 76 - <cc:license 77 - rdf:resource="http://creativecommons.org/licenses/by/4.0/" /> 78 - </cc:Work> 79 - <cc:License 80 - rdf:about="http://creativecommons.org/licenses/by/4.0/"> 81 - <cc:permits 82 - rdf:resource="http://creativecommons.org/ns#Reproduction" /> 83 - <cc:permits 84 - rdf:resource="http://creativecommons.org/ns#Distribution" /> 85 - <cc:requires 86 - rdf:resource="http://creativecommons.org/ns#Notice" /> 87 - <cc:requires 88 - rdf:resource="http://creativecommons.org/ns#Attribution" /> 89 - <cc:permits 90 - rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> 91 - </cc:License> 92 - </rdf:RDF> 93 - </metadata> 94 - </svg> 95 - {{ end }}
···
+1 -1
appview/pages/templates/fragments/logotype.html
··· 1 {{ define "fragments/logotype" }} 2 <span class="flex items-center gap-2"> 3 - {{ template "fragments/dolly/logo" "size-16 text-black dark:text-white" }} 4 <span class="font-bold text-4xl not-italic">tangled</span> 5 <span class="font-normal not-italic text-xs rounded bg-gray-100 dark:bg-gray-700 px-1"> 6 alpha
··· 1 {{ define "fragments/logotype" }} 2 <span class="flex items-center gap-2"> 3 + {{ template "fragments/dolly/logo" (dict "Classes" "size-16 text-black dark:text-white") }} 4 <span class="font-bold text-4xl not-italic">tangled</span> 5 <span class="font-normal not-italic text-xs rounded bg-gray-100 dark:bg-gray-700 px-1"> 6 alpha
+1 -1
appview/pages/templates/fragments/logotypeSmall.html
··· 1 {{ define "fragments/logotypeSmall" }} 2 <span class="flex items-center gap-2"> 3 - {{ template "fragments/dolly/logo" "size-8 text-black dark:text-white" }} 4 <span class="font-bold text-xl not-italic">tangled</span> 5 <span class="font-normal not-italic text-xs rounded bg-gray-100 dark:bg-gray-700 px-1"> 6 alpha
··· 1 {{ define "fragments/logotypeSmall" }} 2 <span class="flex items-center gap-2"> 3 + {{ template "fragments/dolly/logo" (dict "Classes" "size-8 text-black dark:text-white")}} 4 <span class="font-bold text-xl not-italic">tangled</span> 5 <span class="font-normal not-italic text-xs rounded bg-gray-100 dark:bg-gray-700 px-1"> 6 alpha
+4
appview/pages/templates/layouts/base.html
··· 11 <script defer src="/static/htmx-ext-ws.min.js"></script> 12 <script defer src="/static/actor-typeahead.js" type="module"></script> 13 14 <!-- preconnect to image cdn --> 15 <link rel="preconnect" href="https://avatar.tangled.sh" /> 16 <link rel="preconnect" href="https://camo.tangled.sh" />
··· 11 <script defer src="/static/htmx-ext-ws.min.js"></script> 12 <script defer src="/static/actor-typeahead.js" type="module"></script> 13 14 + <link rel="icon" href="/static/logos/dolly.ico" sizes="48x48"/> 15 + <link rel="icon" href="/static/logos/dolly.svg" sizes="any" type="image/svg+xml"/> 16 + <link rel="apple-touch-icon" href="/static/logos/dolly.png"/> 17 + 18 <!-- preconnect to image cdn --> 19 <link rel="preconnect" href="https://avatar.tangled.sh" /> 20 <link rel="preconnect" href="https://camo.tangled.sh" />
+1 -5
appview/pages/templates/layouts/fragments/topbar.html
··· 3 <div class="flex justify-between p-0 items-center"> 4 <div id="left-items"> 5 <a href="/" hx-boost="true" class="text-2xl no-underline hover:no-underline flex items-center gap-2"> 6 - {{ template "fragments/dolly/logo" "size-8 text-black dark:text-white" }} 7 - <span class="font-bold text-xl not-italic hidden md:inline">tangled</span> 8 - <span class="font-normal not-italic text-xs rounded bg-gray-100 dark:bg-gray-700 px-1 hidden md:inline"> 9 - alpha 10 - </span> 11 </a> 12 </div> 13
··· 3 <div class="flex justify-between p-0 items-center"> 4 <div id="left-items"> 5 <a href="/" hx-boost="true" class="text-2xl no-underline hover:no-underline flex items-center gap-2"> 6 + {{ template "fragments/logotypeSmall" }} 7 </a> 8 </div> 9
+50
appview/pages/templates/repo/fragments/reactions.html
···
··· 1 + {{ define "repo/fragments/reactions" }} 2 + <div class="flex flex-wrap items-center gap-2"> 3 + {{- $reactions := .Reactions -}} 4 + {{- $userReacted := .UserReacted -}} 5 + {{- $threadAt := .ThreadAt -}} 6 + 7 + {{ template "reactionsPopup" }} 8 + {{ range $kind := const.OrderedReactionKinds }} 9 + {{ $reactionData := index $reactions $kind }} 10 + {{ template "repo/fragments/reaction" 11 + (dict 12 + "Kind" $kind 13 + "Count" $reactionData.Count 14 + "IsReacted" (index $userReacted $kind) 15 + "ThreadAt" $threadAt 16 + "Users" $reactionData.Users) }} 17 + {{ end }} 18 + </div> 19 + {{ end }} 20 + 21 + {{ define "reactionsPopup" }} 22 + <details 23 + id="reactionsPopUp" 24 + class="relative inline-block" 25 + > 26 + <summary 27 + class="flex justify-center items-center min-w-8 min-h-8 rounded border border-gray-200 dark:border-gray-700 28 + hover:bg-gray-50 29 + hover:border-gray-300 30 + dark:hover:bg-gray-700 31 + dark:hover:border-gray-600 32 + cursor-pointer list-none" 33 + > 34 + {{ i "smile" "size-4" }} 35 + </summary> 36 + <div 37 + class="absolute flex left-0 z-10 mt-4 rounded bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700 shadow-lg" 38 + > 39 + {{ range $kind := const.OrderedReactionKinds }} 40 + <button 41 + id="reactBtn-{{ $kind }}" 42 + class="size-12 hover:bg-gray-100 dark:hover:bg-gray-700" 43 + hx-on:click="this.parentElement.parentElement.removeAttribute('open')" 44 + > 45 + {{ $kind }} 46 + </button> 47 + {{ end }} 48 + </div> 49 + </details> 50 + {{ end }}
-30
appview/pages/templates/repo/fragments/reactionsPopUp.html
··· 1 - {{ define "repo/fragments/reactionsPopUp" }} 2 - <details 3 - id="reactionsPopUp" 4 - class="relative inline-block" 5 - > 6 - <summary 7 - class="flex justify-center items-center min-w-8 min-h-8 rounded border border-gray-200 dark:border-gray-700 8 - hover:bg-gray-50 9 - hover:border-gray-300 10 - dark:hover:bg-gray-700 11 - dark:hover:border-gray-600 12 - cursor-pointer list-none" 13 - > 14 - {{ i "smile" "size-4" }} 15 - </summary> 16 - <div 17 - class="absolute flex left-0 z-10 mt-4 rounded bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700 shadow-lg" 18 - > 19 - {{ range $kind := . }} 20 - <button 21 - id="reactBtn-{{ $kind }}" 22 - class="size-12 hover:bg-gray-100 dark:hover:bg-gray-700" 23 - hx-on:click="this.parentElement.parentElement.removeAttribute('open')" 24 - > 25 - {{ $kind }} 26 - </button> 27 - {{ end }} 28 - </div> 29 - </details> 30 - {{ end }}
···
+5 -21
appview/pages/templates/repo/issues/issue.html
··· 35 {{ if .Issue.Body }} 36 <article id="body" class="mt-4 prose dark:prose-invert">{{ .Issue.Body | markdown }}</article> 37 {{ end }} 38 - <div class="flex flex-wrap gap-2 items-stretch mt-4"> 39 - {{ template "issueReactions" . }} 40 </div> 41 </section> 42 {{ end }} ··· 106 {{ i "loader-circle" "size-3 animate-spin hidden group-[.htmx-request]:inline" }} 107 </a> 108 {{ end }} 109 - 110 - {{ define "issueReactions" }} 111 - <div class="flex items-center gap-2"> 112 - {{ template "repo/fragments/reactionsPopUp" .OrderedReactionKinds }} 113 - {{ range $kind := .OrderedReactionKinds }} 114 - {{ $reactionData := index $.Reactions $kind }} 115 - {{ 116 - template "repo/fragments/reaction" 117 - (dict 118 - "Kind" $kind 119 - "Count" $reactionData.Count 120 - "IsReacted" (index $.UserReacted $kind) 121 - "ThreadAt" $.Issue.AtUri 122 - "Users" $reactionData.Users) 123 - }} 124 - {{ end }} 125 - </div> 126 - {{ end }} 127 - 128 129 {{ define "repoAfter" }} 130 <div class="flex flex-col gap-4 mt-4">
··· 35 {{ if .Issue.Body }} 36 <article id="body" class="mt-4 prose dark:prose-invert">{{ .Issue.Body | markdown }}</article> 37 {{ end }} 38 + <div class="mt-4"> 39 + {{ template "repo/fragments/reactions" 40 + (dict "Reactions" .Reactions 41 + "UserReacted" .UserReacted 42 + "ThreadAt" .Issue.AtUri) }} 43 </div> 44 </section> 45 {{ end }} ··· 109 {{ i "loader-circle" "size-3 animate-spin hidden group-[.htmx-request]:inline" }} 110 </a> 111 {{ end }} 112 113 {{ define "repoAfter" }} 114 <div class="flex flex-col gap-4 mt-4">
+5 -16
appview/pages/templates/repo/pulls/fragments/pullHeader.html
··· 64 </article> 65 {{ end }} 66 67 - {{ with .OrderedReactionKinds }} 68 - <div class="flex items-center gap-2 mt-2"> 69 - {{ template "repo/fragments/reactionsPopUp" . }} 70 - {{ range $kind := . }} 71 - {{ $reactionData := index $.Reactions $kind }} 72 - {{ 73 - template "repo/fragments/reaction" 74 - (dict 75 - "Kind" $kind 76 - "Count" $reactionData.Count 77 - "IsReacted" (index $.UserReacted $kind) 78 - "ThreadAt" $.Pull.AtUri 79 - "Users" $reactionData.Users) 80 - }} 81 - {{ end }} 82 </div> 83 - {{ end }} 84 </section> 85 86
··· 64 </article> 65 {{ end }} 66 67 + <div class="mt-2"> 68 + {{ template "repo/fragments/reactions" 69 + (dict "Reactions" .Reactions 70 + "UserReacted" .UserReacted 71 + "ThreadAt" .Pull.AtUri) }} 72 </div> 73 </section> 74 75
+1 -2
appview/pages/templates/repo/settings/fragments/sidebar.html
··· 1 {{ define "repo/settings/fragments/sidebar" }} 2 {{ $active := .Tab }} 3 - {{ $tabs := .Tabs }} 4 <div class="sticky top-2 grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700 shadow-inner"> 5 {{ $activeTab := "bg-white dark:bg-gray-700 drop-shadow-sm" }} 6 {{ $inactiveTab := "bg-gray-100 dark:bg-gray-800" }} 7 - {{ range $tabs }} 8 <a href="/{{ $.RepoInfo.FullName }}/settings?tab={{.Name}}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25"> 9 <div class="flex gap-3 items-center p-2 {{ if eq .Name $active }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}"> 10 {{ i .Icon "size-4" }}
··· 1 {{ define "repo/settings/fragments/sidebar" }} 2 {{ $active := .Tab }} 3 <div class="sticky top-2 grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700 shadow-inner"> 4 {{ $activeTab := "bg-white dark:bg-gray-700 drop-shadow-sm" }} 5 {{ $inactiveTab := "bg-gray-100 dark:bg-gray-800" }} 6 + {{ range const.RepoSettingsTabs }} 7 <a href="/{{ $.RepoInfo.FullName }}/settings?tab={{.Name}}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25"> 8 <div class="flex gap-3 items-center p-2 {{ if eq .Name $active }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}"> 9 {{ i .Icon "size-4" }}
+2 -3
appview/pages/templates/user/settings/fragments/sidebar.html
··· 1 {{ define "user/settings/fragments/sidebar" }} 2 {{ $active := .Tab }} 3 - {{ $tabs := .Tabs }} 4 <div class="sticky top-2 grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700 shadow-inner"> 5 {{ $activeTab := "bg-white dark:bg-gray-700 drop-shadow-sm" }} 6 {{ $inactiveTab := "bg-gray-100 dark:bg-gray-800" }} 7 - {{ range $tabs }} 8 <a href="/settings/{{.Name}}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25"> 9 <div class="flex gap-3 items-center p-2 {{ if eq .Name $active }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}"> 10 {{ i .Icon "size-4" }} ··· 13 </a> 14 {{ end }} 15 </div> 16 - {{ end }}
··· 1 {{ define "user/settings/fragments/sidebar" }} 2 {{ $active := .Tab }} 3 <div class="sticky top-2 grid grid-cols-1 rounded border border-gray-200 dark:border-gray-700 divide-y divide-gray-200 dark:divide-gray-700 shadow-inner"> 4 {{ $activeTab := "bg-white dark:bg-gray-700 drop-shadow-sm" }} 5 {{ $inactiveTab := "bg-gray-100 dark:bg-gray-800" }} 6 + {{ range const.UserSettingsTabs }} 7 <a href="/settings/{{.Name}}" class="no-underline hover:no-underline hover:bg-gray-100/25 hover:dark:bg-gray-700/25"> 8 <div class="flex gap-3 items-center p-2 {{ if eq .Name $active }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}"> 9 {{ i .Icon "size-4" }} ··· 12 </a> 13 {{ end }} 14 </div> 15 + {{ end }}
+1 -1
appview/pulls/opengraph.go
··· 242 dollyX := dollyBounds.Min.X + (dollyBounds.Dx() / 2) - (dollySize / 2) 243 dollyY := statsY + iconBaselineOffset - dollySize/2 + 25 244 dollyColor := color.RGBA{180, 180, 180, 255} // light gray 245 - err = dollyArea.DrawDollySilhouette(dollyX, dollyY, dollySize, dollyColor) 246 if err != nil { 247 log.Printf("dolly silhouette not available (this is ok): %v", err) 248 }
··· 242 dollyX := dollyBounds.Min.X + (dollyBounds.Dx() / 2) - (dollySize / 2) 243 dollyY := statsY + iconBaselineOffset - dollySize/2 + 25 244 dollyColor := color.RGBA{180, 180, 180, 255} // light gray 245 + err = dollyArea.DrawDolly(dollyX, dollyY, dollySize, dollyColor) 246 if err != nil { 247 log.Printf("dolly silhouette not available (this is ok): %v", err) 248 }
+2 -3
appview/pulls/pulls.go
··· 244 ResubmitCheck: resubmitResult, 245 Pipelines: m, 246 247 - OrderedReactionKinds: models.OrderedReactionKinds, 248 - Reactions: reactionMap, 249 - UserReacted: userReactions, 250 251 LabelDefs: defs, 252 })
··· 244 ResubmitCheck: resubmitResult, 245 Pipelines: m, 246 247 + Reactions: reactionMap, 248 + UserReacted: userReactions, 249 250 LabelDefs: defs, 251 })
+1 -1
appview/repo/opengraph.go
··· 237 dollyX := dollyBounds.Min.X + (dollyBounds.Dx() / 2) - (dollySize / 2) 238 dollyY := statsY + iconBaselineOffset - dollySize/2 + 25 239 dollyColor := color.RGBA{180, 180, 180, 255} // light gray 240 - err = dollyArea.DrawDollySilhouette(dollyX, dollyY, dollySize, dollyColor) 241 if err != nil { 242 log.Printf("dolly silhouette not available (this is ok): %v", err) 243 }
··· 237 dollyX := dollyBounds.Min.X + (dollyBounds.Dx() / 2) - (dollySize / 2) 238 dollyY := statsY + iconBaselineOffset - dollySize/2 + 25 239 dollyColor := color.RGBA{180, 180, 180, 255} // light gray 240 + err = dollyArea.DrawDolly(dollyX, dollyY, dollySize, dollyColor) 241 if err != nil { 242 log.Printf("dolly silhouette not available (this is ok): %v", err) 243 }
-14
appview/repo/settings.go
··· 22 indigoxrpc "github.com/bluesky-social/indigo/xrpc" 23 ) 24 25 - type tab = map[string]any 26 - 27 - var ( 28 - // would be great to have ordered maps right about now 29 - settingsTabs []tab = []tab{ 30 - {"Name": "general", "Icon": "sliders-horizontal"}, 31 - {"Name": "access", "Icon": "users"}, 32 - {"Name": "pipelines", "Icon": "layers-2"}, 33 - } 34 - ) 35 - 36 func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) { 37 l := rp.logger.With("handler", "SetDefaultBranch") 38 ··· 262 DefaultLabels: defaultLabels, 263 SubscribedLabels: subscribedLabels, 264 ShouldSubscribeAll: shouldSubscribeAll, 265 - Tabs: settingsTabs, 266 Tab: "general", 267 }) 268 } ··· 308 rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{ 309 LoggedInUser: user, 310 RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 311 - Tabs: settingsTabs, 312 Tab: "access", 313 Collaborators: collaborators, 314 }) ··· 369 rp.pages.RepoPipelineSettings(w, pages.RepoPipelineSettingsParams{ 370 LoggedInUser: user, 371 RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 372 - Tabs: settingsTabs, 373 Tab: "pipelines", 374 Spindles: spindles, 375 CurrentSpindle: f.Spindle,
··· 22 indigoxrpc "github.com/bluesky-social/indigo/xrpc" 23 ) 24 25 func (rp *Repo) SetDefaultBranch(w http.ResponseWriter, r *http.Request) { 26 l := rp.logger.With("handler", "SetDefaultBranch") 27 ··· 251 DefaultLabels: defaultLabels, 252 SubscribedLabels: subscribedLabels, 253 ShouldSubscribeAll: shouldSubscribeAll, 254 Tab: "general", 255 }) 256 } ··· 296 rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{ 297 LoggedInUser: user, 298 RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 299 Tab: "access", 300 Collaborators: collaborators, 301 }) ··· 356 rp.pages.RepoPipelineSettings(w, pages.RepoPipelineSettingsParams{ 357 LoggedInUser: user, 358 RepoInfo: rp.repoResolver.GetRepoInfo(r, user), 359 Tab: "pipelines", 360 Spindles: spindles, 361 CurrentSpindle: f.Spindle,
-17
appview/settings/settings.go
··· 35 Config *config.Config 36 } 37 38 - type tab = map[string]any 39 - 40 - var ( 41 - settingsTabs []tab = []tab{ 42 - {"Name": "profile", "Icon": "user"}, 43 - {"Name": "keys", "Icon": "key"}, 44 - {"Name": "emails", "Icon": "mail"}, 45 - {"Name": "notifications", "Icon": "bell"}, 46 - {"Name": "knots", "Icon": "volleyball"}, 47 - {"Name": "spindles", "Icon": "spool"}, 48 - } 49 - ) 50 - 51 func (s *Settings) Router() http.Handler { 52 r := chi.NewRouter() 53 ··· 85 86 s.Pages.UserProfileSettings(w, pages.UserProfileSettingsParams{ 87 LoggedInUser: user, 88 - Tabs: settingsTabs, 89 Tab: "profile", 90 }) 91 } ··· 104 s.Pages.UserNotificationSettings(w, pages.UserNotificationSettingsParams{ 105 LoggedInUser: user, 106 Preferences: prefs, 107 - Tabs: settingsTabs, 108 Tab: "notifications", 109 }) 110 } ··· 146 s.Pages.UserKeysSettings(w, pages.UserKeysSettingsParams{ 147 LoggedInUser: user, 148 PubKeys: pubKeys, 149 - Tabs: settingsTabs, 150 Tab: "keys", 151 }) 152 } ··· 161 s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{ 162 LoggedInUser: user, 163 Emails: emails, 164 - Tabs: settingsTabs, 165 Tab: "emails", 166 }) 167 }
··· 35 Config *config.Config 36 } 37 38 func (s *Settings) Router() http.Handler { 39 r := chi.NewRouter() 40 ··· 72 73 s.Pages.UserProfileSettings(w, pages.UserProfileSettingsParams{ 74 LoggedInUser: user, 75 Tab: "profile", 76 }) 77 } ··· 90 s.Pages.UserNotificationSettings(w, pages.UserNotificationSettingsParams{ 91 LoggedInUser: user, 92 Preferences: prefs, 93 Tab: "notifications", 94 }) 95 } ··· 131 s.Pages.UserKeysSettings(w, pages.UserKeysSettingsParams{ 132 LoggedInUser: user, 133 PubKeys: pubKeys, 134 Tab: "keys", 135 }) 136 } ··· 145 s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{ 146 LoggedInUser: user, 147 Emails: emails, 148 Tab: "emails", 149 }) 150 }
-15
appview/spindles/spindles.go
··· 39 Logger *slog.Logger 40 } 41 42 - type tab = map[string]any 43 - 44 - var ( 45 - spindlesTabs []tab = []tab{ 46 - {"Name": "profile", "Icon": "user"}, 47 - {"Name": "keys", "Icon": "key"}, 48 - {"Name": "emails", "Icon": "mail"}, 49 - {"Name": "notifications", "Icon": "bell"}, 50 - {"Name": "knots", "Icon": "volleyball"}, 51 - {"Name": "spindles", "Icon": "spool"}, 52 - } 53 - ) 54 - 55 func (s *Spindles) Router() http.Handler { 56 r := chi.NewRouter() 57 ··· 83 s.Pages.Spindles(w, pages.SpindlesParams{ 84 LoggedInUser: user, 85 Spindles: all, 86 - Tabs: spindlesTabs, 87 Tab: "spindles", 88 }) 89 } ··· 143 Spindle: spindle, 144 Members: members, 145 Repos: repoMap, 146 - Tabs: spindlesTabs, 147 Tab: "spindles", 148 }) 149 }
··· 39 Logger *slog.Logger 40 } 41 42 func (s *Spindles) Router() http.Handler { 43 r := chi.NewRouter() 44 ··· 70 s.Pages.Spindles(w, pages.SpindlesParams{ 71 LoggedInUser: user, 72 Spindles: all, 73 Tab: "spindles", 74 }) 75 } ··· 129 Spindle: spindle, 130 Members: members, 131 Repos: repoMap, 132 Tab: "spindles", 133 }) 134 }
+29
appview/state/manifest.go
···
··· 1 + package state 2 + 3 + import ( 4 + "encoding/json" 5 + "net/http" 6 + ) 7 + 8 + // https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest 9 + // https://www.w3.org/TR/appmanifest/ 10 + var manifestData = map[string]any{ 11 + "name": "tangled", 12 + "description": "tightly-knit social coding.", 13 + "icons": []map[string]string{ 14 + { 15 + "src": "/static/logos/dolly.svg", 16 + "sizes": "144x144", 17 + }, 18 + }, 19 + "start_url": "/", 20 + "id": "https://tangled.org", 21 + "display": "standalone", 22 + "background_color": "#111827", 23 + "theme_color": "#111827", 24 + } 25 + 26 + func (p *State) WebAppManifest(w http.ResponseWriter, r *http.Request) { 27 + w.Header().Set("Content-Type", "application/manifest+json") 28 + json.NewEncoder(w).Encode(manifestData) 29 + }
+1 -3
appview/state/router.go
··· 32 s.pages, 33 ) 34 35 - router.Get("/favicon.svg", s.Favicon) 36 - router.Get("/favicon.ico", s.Favicon) 37 - router.Get("/pwa-manifest.json", s.PWAManifest) 38 router.Get("/robots.txt", s.RobotsTxt) 39 40 userRouter := s.UserRouter(&middleware)
··· 32 s.pages, 33 ) 34 35 + router.Get("/pwa-manifest.json", s.WebAppManifest) 36 router.Get("/robots.txt", s.RobotsTxt) 37 38 userRouter := s.UserRouter(&middleware)
-36
appview/state/state.go
··· 202 return s.db.Close() 203 } 204 205 - func (s *State) Favicon(w http.ResponseWriter, r *http.Request) { 206 - w.Header().Set("Content-Type", "image/svg+xml") 207 - w.Header().Set("Cache-Control", "public, max-age=31536000") // one year 208 - w.Header().Set("ETag", `"favicon-svg-v1"`) 209 - 210 - if match := r.Header.Get("If-None-Match"); match == `"favicon-svg-v1"` { 211 - w.WriteHeader(http.StatusNotModified) 212 - return 213 - } 214 - 215 - s.pages.Favicon(w) 216 - } 217 - 218 func (s *State) RobotsTxt(w http.ResponseWriter, r *http.Request) { 219 w.Header().Set("Content-Type", "text/plain") 220 w.Header().Set("Cache-Control", "public, max-age=86400") // one day ··· 223 Allow: / 224 ` 225 w.Write([]byte(robotsTxt)) 226 - } 227 - 228 - // https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Manifest 229 - const manifestJson = `{ 230 - "name": "tangled", 231 - "description": "tightly-knit social coding.", 232 - "icons": [ 233 - { 234 - "src": "/favicon.svg", 235 - "sizes": "144x144" 236 - } 237 - ], 238 - "start_url": "/", 239 - "id": "org.tangled", 240 - 241 - "display": "standalone", 242 - "background_color": "#111827", 243 - "theme_color": "#111827" 244 - }` 245 - 246 - func (p *State) PWAManifest(w http.ResponseWriter, r *http.Request) { 247 - w.Header().Set("Content-Type", "application/json") 248 - w.Write([]byte(manifestJson)) 249 } 250 251 func (s *State) TermsOfService(w http.ResponseWriter, r *http.Request) {
··· 202 return s.db.Close() 203 } 204 205 func (s *State) RobotsTxt(w http.ResponseWriter, r *http.Request) { 206 w.Header().Set("Content-Type", "text/plain") 207 w.Header().Set("Cache-Control", "public, max-age=86400") // one day ··· 210 Allow: / 211 ` 212 w.Write([]byte(robotsTxt)) 213 } 214 215 func (s *State) TermsOfService(w http.ResponseWriter, r *http.Request) {
-1
cmd/cborgen/cborgen.go
··· 15 "api/tangled/cbor_gen.go", 16 "tangled", 17 tangled.ActorProfile{}, 18 - tangled.Comment{}, 19 tangled.FeedReaction{}, 20 tangled.FeedStar{}, 21 tangled.GitRefUpdate{},
··· 15 "api/tangled/cbor_gen.go", 16 "tangled", 17 tangled.ActorProfile{}, 18 tangled.FeedReaction{}, 19 tangled.FeedStar{}, 20 tangled.GitRefUpdate{},
+182
cmd/dolly/main.go
···
··· 1 + package main 2 + 3 + import ( 4 + "bytes" 5 + "flag" 6 + "fmt" 7 + "image" 8 + "image/color" 9 + "image/png" 10 + "os" 11 + "path/filepath" 12 + "strconv" 13 + "strings" 14 + "text/template" 15 + 16 + "github.com/srwiley/oksvg" 17 + "github.com/srwiley/rasterx" 18 + "golang.org/x/image/draw" 19 + "tangled.org/core/appview/pages" 20 + "tangled.org/core/ico" 21 + ) 22 + 23 + func main() { 24 + var ( 25 + size string 26 + fillColor string 27 + output string 28 + ) 29 + 30 + flag.StringVar(&size, "size", "512x512", "Output size in format WIDTHxHEIGHT (e.g., 512x512)") 31 + flag.StringVar(&fillColor, "color", "#000000", "Fill color in hex format (e.g., #FF5733)") 32 + flag.StringVar(&output, "output", "dolly.svg", "Output file path (format detected from extension: .svg, .png, or .ico)") 33 + flag.Parse() 34 + 35 + width, height, err := parseSize(size) 36 + if err != nil { 37 + fmt.Fprintf(os.Stderr, "Error parsing size: %v\n", err) 38 + os.Exit(1) 39 + } 40 + 41 + // Detect format from file extension 42 + ext := strings.ToLower(filepath.Ext(output)) 43 + format := strings.TrimPrefix(ext, ".") 44 + 45 + if format != "svg" && format != "png" && format != "ico" { 46 + fmt.Fprintf(os.Stderr, "Invalid file extension: %s. Must be .svg, .png, or .ico\n", ext) 47 + os.Exit(1) 48 + } 49 + 50 + if fillColor != "currentColor" && !isValidHexColor(fillColor) { 51 + fmt.Fprintf(os.Stderr, "Invalid color format: %s. Use hex format like #FF5733\n", fillColor) 52 + os.Exit(1) 53 + } 54 + 55 + svgData, err := dolly(fillColor) 56 + if err != nil { 57 + fmt.Fprintf(os.Stderr, "Error generating SVG: %v\n", err) 58 + os.Exit(1) 59 + } 60 + 61 + // Create output directory if it doesn't exist 62 + dir := filepath.Dir(output) 63 + if dir != "" && dir != "." { 64 + if err := os.MkdirAll(dir, 0755); err != nil { 65 + fmt.Fprintf(os.Stderr, "Error creating output directory: %v\n", err) 66 + os.Exit(1) 67 + } 68 + } 69 + 70 + switch format { 71 + case "svg": 72 + err = saveSVG(svgData, output, width, height) 73 + case "png": 74 + err = savePNG(svgData, output, width, height) 75 + case "ico": 76 + err = saveICO(svgData, output, width, height) 77 + } 78 + 79 + if err != nil { 80 + fmt.Fprintf(os.Stderr, "Error saving file: %v\n", err) 81 + os.Exit(1) 82 + } 83 + 84 + fmt.Printf("Successfully generated %s (%dx%d)\n", output, width, height) 85 + } 86 + 87 + func dolly(hexColor string) ([]byte, error) { 88 + tpl, err := template.New("dolly"). 89 + ParseFS(pages.Files, "templates/fragments/dolly/logo.html") 90 + if err != nil { 91 + return nil, err 92 + } 93 + 94 + var svgData bytes.Buffer 95 + if err := tpl.ExecuteTemplate(&svgData, "fragments/dolly/logo", pages.DollyParams{ 96 + FillColor: hexColor, 97 + }); err != nil { 98 + return nil, err 99 + } 100 + 101 + return svgData.Bytes(), nil 102 + } 103 + 104 + func svgToImage(svgData []byte, w, h int) (image.Image, error) { 105 + icon, err := oksvg.ReadIconStream(bytes.NewReader(svgData)) 106 + if err != nil { 107 + return nil, fmt.Errorf("error parsing SVG: %v", err) 108 + } 109 + 110 + icon.SetTarget(0, 0, float64(w), float64(h)) 111 + rgba := image.NewRGBA(image.Rect(0, 0, w, h)) 112 + draw.Draw(rgba, rgba.Bounds(), &image.Uniform{color.Transparent}, image.Point{}, draw.Src) 113 + scanner := rasterx.NewScannerGV(w, h, rgba, rgba.Bounds()) 114 + raster := rasterx.NewDasher(w, h, scanner) 115 + icon.Draw(raster, 1.0) 116 + 117 + return rgba, nil 118 + } 119 + 120 + func parseSize(size string) (int, int, error) { 121 + parts := strings.Split(size, "x") 122 + if len(parts) != 2 { 123 + return 0, 0, fmt.Errorf("invalid size format, use WIDTHxHEIGHT") 124 + } 125 + 126 + width, err := strconv.Atoi(parts[0]) 127 + if err != nil { 128 + return 0, 0, fmt.Errorf("invalid width: %v", err) 129 + } 130 + 131 + height, err := strconv.Atoi(parts[1]) 132 + if err != nil { 133 + return 0, 0, fmt.Errorf("invalid height: %v", err) 134 + } 135 + 136 + if width <= 0 || height <= 0 { 137 + return 0, 0, fmt.Errorf("width and height must be positive") 138 + } 139 + 140 + return width, height, nil 141 + } 142 + 143 + func isValidHexColor(hex string) bool { 144 + if len(hex) != 7 || hex[0] != '#' { 145 + return false 146 + } 147 + _, err := strconv.ParseUint(hex[1:], 16, 32) 148 + return err == nil 149 + } 150 + 151 + func saveSVG(svgData []byte, filepath string, _, _ int) error { 152 + return os.WriteFile(filepath, svgData, 0644) 153 + } 154 + 155 + func savePNG(svgData []byte, filepath string, width, height int) error { 156 + img, err := svgToImage(svgData, width, height) 157 + if err != nil { 158 + return err 159 + } 160 + 161 + f, err := os.Create(filepath) 162 + if err != nil { 163 + return err 164 + } 165 + defer f.Close() 166 + 167 + return png.Encode(f, img) 168 + } 169 + 170 + func saveICO(svgData []byte, filepath string, width, height int) error { 171 + img, err := svgToImage(svgData, width, height) 172 + if err != nil { 173 + return err 174 + } 175 + 176 + icoData, err := ico.ImageToIco(img) 177 + if err != nil { 178 + return err 179 + } 180 + 181 + return os.WriteFile(filepath, icoData, 0644) 182 + }
+6
docs/logo.html
···
··· 1 + <div class="flex items-center gap-2 w-fit mx-auto"> 2 + <span class="w-16 h-16 [&>svg]:w-full [&>svg]:h-full text-black dark:text-white"> 3 + ${ dolly.svg() } 4 + </span> 5 + <span class="font-bold text-4xl not-italic text-black dark:text-white">tangled</span> 6 + </div>
+7 -6
docs/template.html
··· 74 ${ x.svg() } 75 $if(toc-title)$$toc-title$$else$Table of Contents$endif$ 76 </button> 77 ${ search.html() } 78 ${ table-of-contents:toc.html() } 79 </div> ··· 88 class="hidden md:flex md:flex-col gap-4 fixed left-0 top-0 w-80 h-screen 89 bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 90 p-4 z-50 overflow-y-auto"> 91 ${ search.html() } 92 <div class="flex-1"> 93 $if(toc-title)$ ··· 118 $endif$ 119 $endif$ 120 </header> 121 - $endif$ 122 - 123 - $if(abstract)$ 124 - <article class="prose dark:prose-invert max-w-none"> 125 - $abstract$ 126 - </article> 127 $endif$ 128 129 <article class="prose dark:prose-invert max-w-none">
··· 74 ${ x.svg() } 75 $if(toc-title)$$toc-title$$else$Table of Contents$endif$ 76 </button> 77 + ${ logo.html() } 78 ${ search.html() } 79 ${ table-of-contents:toc.html() } 80 </div> ··· 89 class="hidden md:flex md:flex-col gap-4 fixed left-0 top-0 w-80 h-screen 90 bg-gray-50 dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 91 p-4 z-50 overflow-y-auto"> 92 + ${ logo.html() } 93 ${ search.html() } 94 <div class="flex-1"> 95 $if(toc-title)$ ··· 120 $endif$ 121 $endif$ 122 </header> 123 + $if(abstract)$ 124 + <article class="prose dark:prose-invert max-w-none"> 125 + $abstract$ 126 + </article> 127 + $endif$ 128 $endif$ 129 130 <article class="prose dark:prose-invert max-w-none">
+17 -2
flake.nix
··· 94 spindle = self.callPackage ./nix/pkgs/spindle.nix {}; 95 knot-unwrapped = self.callPackage ./nix/pkgs/knot-unwrapped.nix {}; 96 knot = self.callPackage ./nix/pkgs/knot.nix {}; 97 }); 98 in { 99 overlays.default = final: prev: { 100 - inherit (mkPackageSet final) lexgen goat sqlite-lib spindle knot-unwrapped knot appview docs; 101 }; 102 103 packages = forAllSystems (system: let ··· 106 staticPackages = mkPackageSet pkgs.pkgsStatic; 107 crossPackages = mkPackageSet pkgs.pkgsCross.gnu64.pkgsStatic; 108 in { 109 - inherit (packages) appview appview-static-files lexgen goat spindle knot knot-unwrapped sqlite-lib docs; 110 111 pkgsStatic-appview = staticPackages.appview; 112 pkgsStatic-knot = staticPackages.knot; 113 pkgsStatic-knot-unwrapped = staticPackages.knot-unwrapped; 114 pkgsStatic-spindle = staticPackages.spindle; 115 pkgsStatic-sqlite-lib = staticPackages.sqlite-lib; 116 117 pkgsCross-gnu64-pkgsStatic-appview = crossPackages.appview; 118 pkgsCross-gnu64-pkgsStatic-knot = crossPackages.knot; 119 pkgsCross-gnu64-pkgsStatic-knot-unwrapped = crossPackages.knot-unwrapped; 120 pkgsCross-gnu64-pkgsStatic-spindle = crossPackages.spindle; 121 122 treefmt-wrapper = pkgs.treefmt.withConfig { 123 settings.formatter = {
··· 94 spindle = self.callPackage ./nix/pkgs/spindle.nix {}; 95 knot-unwrapped = self.callPackage ./nix/pkgs/knot-unwrapped.nix {}; 96 knot = self.callPackage ./nix/pkgs/knot.nix {}; 97 + dolly = self.callPackage ./nix/pkgs/dolly.nix {}; 98 }); 99 in { 100 overlays.default = final: prev: { 101 + inherit (mkPackageSet final) lexgen goat sqlite-lib spindle knot-unwrapped knot appview docs dolly; 102 }; 103 104 packages = forAllSystems (system: let ··· 107 staticPackages = mkPackageSet pkgs.pkgsStatic; 108 crossPackages = mkPackageSet pkgs.pkgsCross.gnu64.pkgsStatic; 109 in { 110 + inherit 111 + (packages) 112 + appview 113 + appview-static-files 114 + lexgen 115 + goat 116 + spindle 117 + knot 118 + knot-unwrapped 119 + sqlite-lib 120 + docs 121 + dolly 122 + ; 123 124 pkgsStatic-appview = staticPackages.appview; 125 pkgsStatic-knot = staticPackages.knot; 126 pkgsStatic-knot-unwrapped = staticPackages.knot-unwrapped; 127 pkgsStatic-spindle = staticPackages.spindle; 128 pkgsStatic-sqlite-lib = staticPackages.sqlite-lib; 129 + pkgsStatic-dolly = staticPackages.dolly; 130 131 pkgsCross-gnu64-pkgsStatic-appview = crossPackages.appview; 132 pkgsCross-gnu64-pkgsStatic-knot = crossPackages.knot; 133 pkgsCross-gnu64-pkgsStatic-knot-unwrapped = crossPackages.knot-unwrapped; 134 pkgsCross-gnu64-pkgsStatic-spindle = crossPackages.spindle; 135 + pkgsCross-gnu64-pkgsStatic-dolly = crossPackages.dolly; 136 137 treefmt-wrapper = pkgs.treefmt.withConfig { 138 settings.formatter = {
+88
ico/ico.go
···
··· 1 + package ico 2 + 3 + import ( 4 + "bytes" 5 + "encoding/binary" 6 + "fmt" 7 + "image" 8 + "image/png" 9 + ) 10 + 11 + type IconDir struct { 12 + Reserved uint16 // must be 0 13 + Type uint16 // 1 for ICO, 2 for CUR 14 + Count uint16 // number of images 15 + } 16 + 17 + type IconDirEntry struct { 18 + Width uint8 // 0 means 256 19 + Height uint8 // 0 means 256 20 + ColorCount uint8 21 + Reserved uint8 // must be 0 22 + ColorPlanes uint16 // 0 or 1 23 + BitsPerPixel uint16 24 + SizeInBytes uint32 25 + Offset uint32 26 + } 27 + 28 + func ImageToIco(img image.Image) ([]byte, error) { 29 + // encode image as png 30 + var pngBuf bytes.Buffer 31 + if err := png.Encode(&pngBuf, img); err != nil { 32 + return nil, fmt.Errorf("failed to encode PNG: %w", err) 33 + } 34 + pngData := pngBuf.Bytes() 35 + 36 + // get image dimensions 37 + bounds := img.Bounds() 38 + width := bounds.Dx() 39 + height := bounds.Dy() 40 + 41 + // prepare output buffer 42 + var icoBuf bytes.Buffer 43 + 44 + iconDir := IconDir{ 45 + Reserved: 0, 46 + Type: 1, // ICO format 47 + Count: 1, // One image 48 + } 49 + 50 + w := uint8(width) 51 + h := uint8(height) 52 + 53 + // width/height of 256 should be stored as 0 54 + if width == 256 { 55 + w = 0 56 + } 57 + if height == 256 { 58 + h = 0 59 + } 60 + 61 + iconDirEntry := IconDirEntry{ 62 + Width: w, 63 + Height: h, 64 + ColorCount: 0, // 0 for PNG (32-bit) 65 + Reserved: 0, 66 + ColorPlanes: 1, 67 + BitsPerPixel: 32, // PNG with alpha 68 + SizeInBytes: uint32(len(pngData)), 69 + Offset: 6 + 16, // Size of ICONDIR + ICONDIRENTRY 70 + } 71 + 72 + // write IconDir 73 + if err := binary.Write(&icoBuf, binary.LittleEndian, iconDir); err != nil { 74 + return nil, fmt.Errorf("failed to write ICONDIR: %w", err) 75 + } 76 + 77 + // write IconDirEntry 78 + if err := binary.Write(&icoBuf, binary.LittleEndian, iconDirEntry); err != nil { 79 + return nil, fmt.Errorf("failed to write ICONDIRENTRY: %w", err) 80 + } 81 + 82 + // write PNG data directly 83 + if _, err := icoBuf.Write(pngData); err != nil { 84 + return nil, fmt.Errorf("failed to write PNG data: %w", err) 85 + } 86 + 87 + return icoBuf.Bytes(), nil 88 + }
-51
lexicons/comment/comment.json
··· 1 - { 2 - "lexicon": 1, 3 - "id": "sh.tangled.comment", 4 - "needsCbor": true, 5 - "needsType": true, 6 - "defs": { 7 - "main": { 8 - "type": "record", 9 - "key": "tid", 10 - "record": { 11 - "type": "object", 12 - "required": [ 13 - "subject", 14 - "body", 15 - "createdAt" 16 - ], 17 - "properties": { 18 - "subject": { 19 - "type": "string", 20 - "format": "at-uri" 21 - }, 22 - "body": { 23 - "type": "string" 24 - }, 25 - "createdAt": { 26 - "type": "string", 27 - "format": "datetime" 28 - }, 29 - "replyTo": { 30 - "type": "string", 31 - "format": "at-uri" 32 - }, 33 - "mentions": { 34 - "type": "array", 35 - "items": { 36 - "type": "string", 37 - "format": "did" 38 - } 39 - }, 40 - "references": { 41 - "type": "array", 42 - "items": { 43 - "type": "string", 44 - "format": "at-uri" 45 - } 46 - } 47 - } 48 - } 49 - } 50 - } 51 - }
···
+6 -1
nix/pkgs/appview-static-files.nix
··· 8 actor-typeahead-src, 9 sqlite-lib, 10 tailwindcss, 11 src, 12 }: 13 runCommandLocal "appview-static-files" { ··· 17 (allow file-read* (subpath "/System/Library/OpenSSL")) 18 ''; 19 } '' 20 - mkdir -p $out/{fonts,icons} && cd $out 21 cp -f ${htmx-src} htmx.min.js 22 cp -f ${htmx-ws-src} htmx-ext-ws.min.js 23 cp -rf ${lucide-src}/*.svg icons/ ··· 26 cp -f ${inter-fonts-src}/InterVariable*.ttf fonts/ 27 cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono*.woff2 fonts/ 28 cp -f ${actor-typeahead-src}/actor-typeahead.js . 29 # tailwindcss -c $src/tailwind.config.js -i $src/input.css -o tw.css won't work 30 # for whatever reason (produces broken css), so we are doing this instead 31 cd ${src} && ${tailwindcss}/bin/tailwindcss -i input.css -o $out/tw.css
··· 8 actor-typeahead-src, 9 sqlite-lib, 10 tailwindcss, 11 + dolly, 12 src, 13 }: 14 runCommandLocal "appview-static-files" { ··· 18 (allow file-read* (subpath "/System/Library/OpenSSL")) 19 ''; 20 } '' 21 + mkdir -p $out/{fonts,icons,logos} && cd $out 22 cp -f ${htmx-src} htmx.min.js 23 cp -f ${htmx-ws-src} htmx-ext-ws.min.js 24 cp -rf ${lucide-src}/*.svg icons/ ··· 27 cp -f ${inter-fonts-src}/InterVariable*.ttf fonts/ 28 cp -f ${ibm-plex-mono-src}/fonts/complete/woff2/IBMPlexMono*.woff2 fonts/ 29 cp -f ${actor-typeahead-src}/actor-typeahead.js . 30 + 31 + ${dolly}/bin/dolly -output logos/dolly.png -size 180x180 32 + ${dolly}/bin/dolly -output logos/dolly.ico -size 48x48 33 + ${dolly}/bin/dolly -output logos/dolly.svg -color currentColor 34 # tailwindcss -c $src/tailwind.config.js -i $src/input.css -o tw.css won't work 35 # for whatever reason (produces broken css), so we are doing this instead 36 cd ${src} && ${tailwindcss}/bin/tailwindcss -i input.css -o $out/tw.css
+4
nix/pkgs/docs.nix
··· 5 inter-fonts-src, 6 ibm-plex-mono-src, 7 lucide-src, 8 src, 9 }: 10 runCommandLocal "docs" {} '' ··· 17 18 # icons 19 cp -rf ${lucide-src}/*.svg working/ 20 21 # content - chunked 22 ${pandoc}/bin/pandoc ${src}/docs/DOCS.md \
··· 5 inter-fonts-src, 6 ibm-plex-mono-src, 7 lucide-src, 8 + dolly, 9 src, 10 }: 11 runCommandLocal "docs" {} '' ··· 18 19 # icons 20 cp -rf ${lucide-src}/*.svg working/ 21 + 22 + # logo 23 + ${dolly}/bin/dolly -output working/dolly.svg -color currentColor 24 25 # content - chunked 26 ${pandoc}/bin/pandoc ${src}/docs/DOCS.md \
+21
nix/pkgs/dolly.nix
···
··· 1 + { 2 + buildGoApplication, 3 + modules, 4 + src, 5 + }: 6 + buildGoApplication { 7 + pname = "dolly"; 8 + version = "0.1.0"; 9 + inherit src modules; 10 + 11 + # patch the static dir 12 + postUnpack = '' 13 + pushd source 14 + mkdir -p appview/pages/static 15 + touch appview/pages/static/x 16 + popd 17 + ''; 18 + 19 + doCheck = false; 20 + subPackages = ["cmd/dolly"]; 21 + }