mirror of
https://github.com/thomiceli/opengist.git
synced 2024-12-23 04:52:40 +00:00
Add avatars to HTML
This commit is contained in:
parent
7b27db8849
commit
f49f4ca10d
11 changed files with 73 additions and 52 deletions
|
@ -1,6 +1,7 @@
|
||||||
package git
|
package git
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"opengist/internal/config"
|
"opengist/internal/config"
|
||||||
"os"
|
"os"
|
||||||
|
@ -114,7 +115,7 @@ func GetLog(user string, gist string, skip string) ([]*Commit, error) {
|
||||||
"-p",
|
"-p",
|
||||||
"--skip",
|
"--skip",
|
||||||
skip,
|
skip,
|
||||||
"--format=format:c %H%na %aN%nt %at",
|
"--format=format:c %H%na %aN%nm %ae%nt %at",
|
||||||
"--shortstat",
|
"--shortstat",
|
||||||
"HEAD",
|
"HEAD",
|
||||||
)
|
)
|
||||||
|
@ -146,12 +147,6 @@ func CloneTmp(user string, gist string, gistTmpId string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = exec.Command("git", "config", "user.name", user)
|
|
||||||
cmd.Dir = tmpRepositoryPath
|
|
||||||
if err = cmd.Run(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove every file (and not the .git directory!)
|
// remove every file (and not the .git directory!)
|
||||||
cmd = exec.Command("find", ".", "-maxdepth", "1", "-type", "f", "-delete")
|
cmd = exec.Command("find", ".", "-maxdepth", "1", "-type", "f", "-delete")
|
||||||
cmd.Dir = tmpRepositoryPath
|
cmd.Dir = tmpRepositoryPath
|
||||||
|
@ -167,13 +162,6 @@ func ForkClone(userSrc string, gistSrc string, userDst string, gistDst string) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = exec.Command("git", "config", "user.name", userDst)
|
|
||||||
cmd.Dir = repositoryPathDst
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return copyFiles(repositoryPathDst)
|
return copyFiles(repositoryPathDst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,8 +188,15 @@ func AddAll(gistTmpId string) error {
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func CommitRepository(gistTmpId string) error {
|
func CommitRepository(gistTmpId string, authorName string, authorEmail string) error {
|
||||||
cmd := exec.Command("git", "commit", "--allow-empty", "-m", `"Opengist commit"`)
|
cmd := exec.Command("git",
|
||||||
|
"commit",
|
||||||
|
"--allow-empty",
|
||||||
|
"-m",
|
||||||
|
"Opengist commit",
|
||||||
|
"--author",
|
||||||
|
fmt.Sprintf("%s <%s>", authorName, authorEmail),
|
||||||
|
)
|
||||||
tmpPath := TmpRepositoryPath(gistTmpId)
|
tmpPath := TmpRepositoryPath(gistTmpId)
|
||||||
cmd.Dir = tmpPath
|
cmd.Dir = tmpPath
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ type CsvFile struct {
|
||||||
|
|
||||||
type Commit struct {
|
type Commit struct {
|
||||||
Hash string
|
Hash string
|
||||||
Author string
|
AuthorName string
|
||||||
|
AuthorEmail string
|
||||||
Timestamp string
|
Timestamp string
|
||||||
Changed string
|
Changed string
|
||||||
Files []File
|
Files []File
|
||||||
|
@ -75,7 +76,10 @@ func parseLog(out io.Reader) []*Commit {
|
||||||
currentCommit = &Commit{Hash: string(scanner.Bytes()[2:]), Files: []File{}}
|
currentCommit = &Commit{Hash: string(scanner.Bytes()[2:]), Files: []File{}}
|
||||||
|
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
currentCommit.Author = string(scanner.Bytes()[2:])
|
currentCommit.AuthorName = string(scanner.Bytes()[2:])
|
||||||
|
|
||||||
|
scanner.Scan()
|
||||||
|
currentCommit.AuthorEmail = string(scanner.Bytes()[2:])
|
||||||
|
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
currentCommit.Timestamp = string(scanner.Bytes()[2:])
|
currentCommit.Timestamp = string(scanner.Bytes()[2:])
|
||||||
|
|
|
@ -251,7 +251,7 @@ func (gist *Gist) AddAndCommitFiles(files *[]FileDTO) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := git.CommitRepository(gist.Uuid); err != nil {
|
if err := git.CommitRepository(gist.Uuid, gist.User.Username, gist.User.Email); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,6 @@ func emailProcess(ctx echo.Context) error {
|
||||||
email := ctx.FormValue("email")
|
email := ctx.FormValue("email")
|
||||||
var hash string
|
var hash string
|
||||||
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
if email == "" {
|
if email == "" {
|
||||||
// generate random md5 string
|
// generate random md5 string
|
||||||
hash = fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String())))
|
hash = fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String())))
|
||||||
|
|
|
@ -71,7 +71,8 @@ func gistInit(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
|
|
||||||
func allGists(ctx echo.Context) error {
|
func allGists(ctx echo.Context) error {
|
||||||
var err error
|
var err error
|
||||||
fromUser := ctx.Param("user")
|
fromUserStr := ctx.Param("user")
|
||||||
|
|
||||||
userLogged := getUserLogged(ctx)
|
userLogged := getUserLogged(ctx)
|
||||||
|
|
||||||
pageInt := getPage(ctx)
|
pageInt := getPage(ctx)
|
||||||
|
@ -99,30 +100,30 @@ func allGists(ctx echo.Context) error {
|
||||||
} else {
|
} else {
|
||||||
currentUserId = 0
|
currentUserId = 0
|
||||||
}
|
}
|
||||||
if fromUser == "" {
|
if fromUserStr == "" {
|
||||||
setData(ctx, "htmlTitle", "All gists")
|
setData(ctx, "htmlTitle", "All gists")
|
||||||
fromUser = "all"
|
fromUserStr = "all"
|
||||||
gists, err = models.GetAllGistsForCurrentUser(currentUserId, pageInt-1, sort, order)
|
gists, err = models.GetAllGistsForCurrentUser(currentUserId, pageInt-1, sort, order)
|
||||||
} else {
|
} else {
|
||||||
setData(ctx, "htmlTitle", "All gists from "+fromUser)
|
setData(ctx, "htmlTitle", "All gists from "+fromUserStr)
|
||||||
setData(ctx, "fromUser", fromUser)
|
|
||||||
|
|
||||||
var exists bool
|
fromUser, err := models.GetUserByUsername(fromUserStr)
|
||||||
if exists, err = models.UserExists(fromUser); err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Error fetching user", err)
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return notFound("User not found")
|
return notFound("User not found")
|
||||||
}
|
}
|
||||||
|
return errorRes(500, "Error fetching user", err)
|
||||||
gists, err = models.GetAllGistsFromUser(fromUser, currentUserId, pageInt-1, sort, order)
|
|
||||||
}
|
}
|
||||||
|
setData(ctx, "fromUser", fromUser)
|
||||||
|
|
||||||
|
gists, err = models.GetAllGistsFromUser(fromUserStr, currentUserId, pageInt-1, sort, order)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errorRes(500, "Error fetching gists", err)
|
return errorRes(500, "Error fetching gists", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = paginate(ctx, gists, pageInt, 10, "gists", fromUser, 2, "&sort="+sort+"&order="+order); err != nil {
|
if err = paginate(ctx, gists, pageInt, 10, "gists", fromUserStr, 2, "&sort="+sort+"&order="+order); err != nil {
|
||||||
return errorRes(404, "Page not found", nil)
|
return errorRes(404, "Page not found", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
@ -100,8 +101,11 @@ func Start() {
|
||||||
"slug": func(s string) string {
|
"slug": func(s string) string {
|
||||||
return strings.Trim(re.ReplaceAllString(strings.ToLower(s), "-"), "-")
|
return strings.Trim(re.ReplaceAllString(strings.ToLower(s), "-"), "-")
|
||||||
},
|
},
|
||||||
"avatarUrl": func(user *models.User) string {
|
"avatarUrl": func(userHash string) string {
|
||||||
return "https://www.gravatar.com/avatar/" + user.MD5Hash + "?d=identicon&s=200"
|
return "https://www.gravatar.com/avatar/" + userHash + "?d=identicon&s=200"
|
||||||
|
},
|
||||||
|
"emailToMD5": func(email string) string {
|
||||||
|
return fmt.Sprintf("%x", md5.Sum([]byte(strings.ToLower(strings.TrimSpace(email)))))
|
||||||
},
|
},
|
||||||
}).ParseGlob("templates/*/*.html")),
|
}).ParseGlob("templates/*/*.html")),
|
||||||
}
|
}
|
||||||
|
|
4
templates/base/base_header.html
vendored
4
templates/base/base_header.html
vendored
|
@ -58,7 +58,7 @@
|
||||||
{{ if .userLogged.IsAdmin }}
|
{{ if .userLogged.IsAdmin }}
|
||||||
<a href="/admin" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Admin</a>
|
<a href="/admin" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Admin</a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<a href="/settings" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Config</a>
|
<a href="/settings" class="hidden sm:block text-slate-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Settings</a>
|
||||||
|
|
||||||
<a href="/logout" id="logged-button" class="inline-flex text-slate-300 hover:bg-rose-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">
|
<a href="/logout" id="logged-button" class="inline-flex text-slate-300 hover:bg-rose-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">
|
||||||
<p class="text-slate-300 mr-1 username">{{ .userLogged.Username }}</p>
|
<p class="text-slate-300 mr-1 username">{{ .userLogged.Username }}</p>
|
||||||
|
@ -90,7 +90,7 @@
|
||||||
<a href="/all" class="bg-gray-900 text-white block px-3 py-2 rounded-md text-base font-medium" aria-current="page">All</a>
|
<a href="/all" class="bg-gray-900 text-white block px-3 py-2 rounded-md text-base font-medium" aria-current="page">All</a>
|
||||||
{{ if .userLogged }}
|
{{ if .userLogged }}
|
||||||
<a href="/{{ .userLogged.Username }}" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">My gists</a>
|
<a href="/{{ .userLogged.Username }}" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">My gists</a>
|
||||||
<a href="/settings" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Config</a>
|
<a href="/settings" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Settings</a>
|
||||||
|
|
||||||
{{ if .userLogged.IsAdmin }}
|
{{ if .userLogged.IsAdmin }}
|
||||||
<a href="/admin" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Admin</a>
|
<a href="/admin" class="text-slate-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Admin</a>
|
||||||
|
|
22
templates/pages/all.html
vendored
22
templates/pages/all.html
vendored
|
@ -2,7 +2,19 @@
|
||||||
<div class="py-10">
|
<div class="py-10">
|
||||||
<header class="pb-4 flex ">
|
<header class="pb-4 flex ">
|
||||||
<div class="flex-auto">
|
<div class="flex-auto">
|
||||||
<h1 class="text-2xl font-bold leading-tight">All gists {{if .fromUser}} from {{.fromUser}} {{end}}</h1>
|
{{if .fromUser}}
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="flex-shrink-0">
|
||||||
|
<img class="h-12 w-12 rounded-md mr-2 border border-gray-700" src="{{ avatarUrl .fromUser.MD5Hash }}" alt="">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-2xl font-bold leading-tight">{{.fromUser.Username}}</h1>
|
||||||
|
<p class="text-sm text-slate-500">Joined <span class="moment-timestamp">{{.fromUser.CreatedAt}}</span></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ else }}
|
||||||
|
<h1 class="text-2xl font-bold leading-tight">All gists</h1>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
<div class="relative inline-block text-left">
|
<div class="relative inline-block text-left">
|
||||||
|
@ -16,21 +28,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="sort-gists-dropdown" class="hidden absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-700 rounded-md rounded border border-gray-600 bg-gray-800 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
<div id="sort-gists-dropdown" class="hidden absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-700 rounded-md rounded border border-gray-600 bg-gray-800 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="menu-button" tabindex="-1">
|
||||||
<div class="" role="none">
|
<div class="" role="none">
|
||||||
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=created&order=desc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500 hover:rounded-t-md" role="menuitem">
|
<a href="/{{if .fromUser}}{{.fromUser.Username}}{{else}}all{{end}}?sort=created&order=desc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500 hover:rounded-t-md" role="menuitem">
|
||||||
Recently created
|
Recently created
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="" role="none">
|
<div class="" role="none">
|
||||||
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=created&order=asc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500" role="menuitem">
|
<a href="/{{if .fromUser}}{{.fromUser.Username}}{{else}}all{{end}}?sort=created&order=asc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500" role="menuitem">
|
||||||
Least recently created
|
Least recently created
|
||||||
</a>
|
</a>
|
||||||
</div><div class="" role="none">
|
</div><div class="" role="none">
|
||||||
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=updated&order=desc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500" role="menuitem">
|
<a href="/{{if .fromUser}}{{.fromUser.Username}}{{else}}all{{end}}?sort=updated&order=desc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500" role="menuitem">
|
||||||
Recently updated
|
Recently updated
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="" role="none">
|
<div class="" role="none">
|
||||||
<a href="/{{if .fromUser}}{{.fromUser}}{{else}}all{{end}}?sort=updated&order=asc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500 hover:rounded-b-md" role="menuitem">
|
<a href="/{{if .fromUser}}{{.fromUser.Username}}{{else}}all{{end}}?sort=updated&order=asc" class="text-slate-300 group flex items-center px-3 py-2 text-xs hover:bg-gray-700 hover:text-white hover:bg-primary-500 hover:rounded-b-md" role="menuitem">
|
||||||
Least recently updated
|
Least recently updated
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
3
templates/pages/forks.html
vendored
3
templates/pages/forks.html
vendored
|
@ -7,6 +7,9 @@
|
||||||
<ul role="list" class="divide-y divide-gray-700">
|
<ul role="list" class="divide-y divide-gray-700">
|
||||||
{{ range $gist := .forks }}
|
{{ range $gist := .forks }}
|
||||||
<li class="flex py-4">
|
<li class="flex py-4">
|
||||||
|
<a href="/{{ $gist.User.Username }}">
|
||||||
|
<img class="h-12 w-12 rounded-md mr-2 border border-gray-700" src="{{ avatarUrl $gist.User.MD5Hash }}" alt="">
|
||||||
|
</a>
|
||||||
<div>
|
<div>
|
||||||
<a href="/{{ $gist.User.Username }}" class="text-sm font-medium text-slate-300">{{ $gist.User.Username }}</a>
|
<a href="/{{ $gist.User.Username }}" class="text-sm font-medium text-slate-300">{{ $gist.User.Username }}</a>
|
||||||
<p class="text-sm text-slate-500">Forked <span class="moment-timestamp">{{ $gist.CreatedAt }}</span></p>
|
<p class="text-sm text-slate-500">Forked <span class="moment-timestamp">{{ $gist.CreatedAt }}</span></p>
|
||||||
|
|
5
templates/pages/likes.html
vendored
5
templates/pages/likes.html
vendored
|
@ -5,10 +5,11 @@
|
||||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-5">
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-5">
|
||||||
{{ range $user := .likers }}
|
{{ range $user := .likers }}
|
||||||
<div class="relative flex items-center space-x-3 rounded-lg border border-gray-600 bg-gray-800 px-6 py-5 shadow-sm focus-within:ring-1 focus-within:border-primary-500 focus-within:ring-primary-500 hover:border-gray-400">
|
<div class="relative flex items-center space-x-3 rounded-lg border border-gray-600 bg-gray-800 px-6 py-5 shadow-sm focus-within:ring-1 focus-within:border-primary-500 focus-within:ring-primary-500 hover:border-gray-400">
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex">
|
||||||
|
<img class="h-12 w-12 rounded-md mr-2 border border-gray-700" src="{{ avatarUrl $user.MD5Hash }}" alt="">
|
||||||
<a href="/{{ $user.Username }}" class="focus:outline-none">
|
<a href="/{{ $user.Username }}" class="focus:outline-none">
|
||||||
<span class="absolute inset-0" aria-hidden="true"></span>
|
<span class="absolute inset-0" aria-hidden="true"></span>
|
||||||
<p class="text-sm font-medium text-slate-300">{{ $user.Username }}</p>
|
<p class="text-sm font-medium text-slate-300 align-middle">{{ $user.Username }}</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
7
templates/pages/revisions.html
vendored
7
templates/pages/revisions.html
vendored
|
@ -6,9 +6,12 @@
|
||||||
{{ range $commit := .commits }}
|
{{ range $commit := .commits }}
|
||||||
<div class="pb-8">
|
<div class="pb-8">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<h3 class="text-sm py-2 flex-auto"><svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 mr-1 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
<h3 class="text-sm py-2 flex-auto">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 mr-1 inline" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
|
<path stroke-linecap="round" stroke-linejoin="round" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
|
||||||
</svg><span class="font-bold">{{ $commit.Author }}</span> revised this gist <span class="moment-timestamp font-bold">{{ $commit.Timestamp }}</span>. <a href="/{{ $.gist.User.Username }}/{{ $.gist.Uuid }}/rev/{{ $commit.Hash }}">Go to revision</a></h3>
|
</svg>
|
||||||
|
<img class="h-5 w-5 rounded-full inline" src="{{ avatarUrl (emailToMD5 $commit.AuthorEmail) }}" alt="" />
|
||||||
|
<span class="font-bold">{{ $commit.AuthorName }}</span> revised this gist <span class="moment-timestamp font-bold">{{ $commit.Timestamp }}</span>. <a href="/{{ $.gist.User.Username }}/{{ $.gist.Uuid }}/rev/{{ $commit.Hash }}">Go to revision</a></h3>
|
||||||
{{ if ne $commit.Changed "" }}
|
{{ if ne $commit.Changed "" }}
|
||||||
<p class="text-sm float-right py-2">
|
<p class="text-sm float-right py-2">
|
||||||
<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 inline-flex">
|
<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 inline-flex">
|
||||||
|
|
Loading…
Reference in a new issue