Group up existing components into elements
This commit is contained in:
15
elements/AMV/AMV.pixy
Normal file
15
elements/AMV/AMV.pixy
Normal file
@ -0,0 +1,15 @@
|
||||
component AMV(amv *arn.AMV, user *arn.User)
|
||||
.amv.mountable
|
||||
AMVVideo(amv)
|
||||
AMVFooter(amv, user)
|
||||
|
||||
component AMVFooter(amv *arn.AMV, user *arn.User)
|
||||
footer.amv-footer
|
||||
if amv.Title.ByUser(user) == ""
|
||||
a(href=amv.Link() + "/edit") untitled
|
||||
else
|
||||
a(href=amv.Link())= amv.Title.ByUser(user)
|
||||
span posted
|
||||
span.utc-date.no-tip(data-date=amv.Created)
|
||||
span by
|
||||
a(href=amv.Creator().Link())= amv.Creator().Nick + " "
|
11
elements/AMV/AMVMini.pixy
Normal file
11
elements/AMV/AMVMini.pixy
Normal file
@ -0,0 +1,11 @@
|
||||
component AMVMini(amv *arn.AMV, user *arn.User)
|
||||
.amv.mountable
|
||||
AMVVideo(amv)
|
||||
AMVMiniFooter(amv, user)
|
||||
|
||||
component AMVMiniFooter(amv *arn.AMV, user *arn.User)
|
||||
footer.amv-footer
|
||||
if amv.Title.ByUser(user) == ""
|
||||
a(href=amv.Link() + "/edit") untitled
|
||||
else
|
||||
a(href=amv.Link())= amv.Title.ByUser(user)
|
9
elements/AMV/AMVVideo.pixy
Normal file
9
elements/AMV/AMVVideo.pixy
Normal file
@ -0,0 +1,9 @@
|
||||
component AMVVideo(amv *arn.AMV)
|
||||
.video-container(id=amv.ID, data-api="/api/amv/" + amv.ID)
|
||||
video.video.lazy.action(data-action="toggleFullscreen", data-trigger="dblclick", data-id=amv.ID)
|
||||
source(data-src=amv.VideoLink(), data-type="video/webm")
|
||||
|
||||
//- button.media-play-button
|
||||
//- RawIcon("play")
|
||||
|
||||
VideoControls(amv.ID, amv.Info.Duration)
|
7
elements/AnimeCard/AnimeCard.pixy
Normal file
7
elements/AnimeCard/AnimeCard.pixy
Normal file
@ -0,0 +1,7 @@
|
||||
component AnimeCard(anime *arn.Anime, note string, user *arn.User)
|
||||
a.anime-card.mountable(href=anime.Link())
|
||||
.anime-card-image-container
|
||||
img.anime-card-image.lazy(data-src=anime.ImageLink("small"), data-webp="true", data-color=anime.AverageColor(), alt=anime.Title.ByUser(user))
|
||||
.anime-card-info
|
||||
.anime-card-info-main= anime.Title.ByUser(user)
|
||||
.anime-card-info-details= note
|
32
elements/AnimeCard/AnimeCard.scarlet
Normal file
32
elements/AnimeCard/AnimeCard.scarlet
Normal file
@ -0,0 +1,32 @@
|
||||
.anime-cards
|
||||
horizontal-wrap
|
||||
|
||||
.anime-card
|
||||
card
|
||||
|
||||
> 600px
|
||||
.anime-card
|
||||
max-width 300px
|
||||
|
||||
.anime-card-image-container
|
||||
width anime-image-small-width
|
||||
height anime-image-small-width
|
||||
|
||||
img
|
||||
width anime-image-small-width
|
||||
height anime-image-small-width
|
||||
border-radius ui-element-border-radius
|
||||
object-fit cover
|
||||
|
||||
.anime-card-info
|
||||
vertical
|
||||
margin-left card-padding
|
||||
font-size 0.95em
|
||||
|
||||
.anime-card-info-main
|
||||
flex 1
|
||||
line-height 1.3em
|
||||
|
||||
.anime-card-info-details
|
||||
color text-color
|
||||
opacity 0.5
|
34
elements/AnimeGrid/AnimeGrid.pixy
Normal file
34
elements/AnimeGrid/AnimeGrid.pixy
Normal file
@ -0,0 +1,34 @@
|
||||
component AnimeGrid(animes []*arn.Anime, user *arn.User)
|
||||
#load-more-target.anime-grid
|
||||
AnimeGridScrollable(animes, user)
|
||||
|
||||
component AnimeGridWithRelation(entries []*utils.AnimeWithRelatedAnime, user *arn.User)
|
||||
#load-more-target.anime-grid
|
||||
AnimeGridWithRelationScrollable(entries, user)
|
||||
|
||||
component AnimeGridScrollable(animes []*arn.Anime, user *arn.User)
|
||||
each anime in animes
|
||||
.anime-grid-cell(data-added=(user != nil && user.AnimeList().Contains(anime.ID)))
|
||||
AnimeImageLink(anime, "medium", user)
|
||||
AnimeGridButton(anime, user)
|
||||
|
||||
component AnimeImageLink(anime *arn.Anime, size string, user *arn.User)
|
||||
a(href="/anime/" + anime.ID)
|
||||
img.anime-grid-image.lazy(data-src=anime.ImageLink(size), data-webp="true", data-color=anime.AverageColor(), alt=anime.Title.Romaji)
|
||||
.image-title
|
||||
.image-title-text= anime.Title.ByUser(user)
|
||||
|
||||
component AnimeGridWithRelationScrollable(entries []*utils.AnimeWithRelatedAnime, user *arn.User)
|
||||
each entry in entries
|
||||
.anime-grid-cell(data-added=(user != nil && user.AnimeList().Contains(entry.Anime.ID)))
|
||||
a(href="/anime/" + entry.Anime.ID)
|
||||
img.anime-grid-image.lazy(data-src=entry.Anime.ImageLink("medium"), data-webp="true", data-color=entry.Anime.AverageColor(), alt=entry.Anime.Title.Romaji)
|
||||
.image-title
|
||||
.image-title-text= entry.Anime.Title.ByUser(user)
|
||||
|
||||
AnimeGridButton(entry.Anime, user)
|
||||
|
||||
component AnimeGridButton(anime *arn.Anime, user *arn.User)
|
||||
if user != nil && !user.AnimeList().Contains(anime.ID)
|
||||
button.anime-grid-add-button.action(data-action="addAnimeToCollection", data-trigger="click", data-api="/api/animelist/" + user.ID, data-anime-id=anime.ID, aria-label="Add anime to my list")
|
||||
RawIcon("plus")
|
34
elements/AnimeGrid/AnimeGrid.scarlet
Normal file
34
elements/AnimeGrid/AnimeGrid.scarlet
Normal file
@ -0,0 +1,34 @@
|
||||
.anime-grid
|
||||
grid
|
||||
|
||||
.anime-grid-cell
|
||||
grid-cell
|
||||
saturate-up
|
||||
shadow-up
|
||||
default-transition
|
||||
|
||||
:hover
|
||||
.image-title,
|
||||
.anime-grid-add-button
|
||||
opacity 1
|
||||
|
||||
< 450px
|
||||
.anime-grid-cell
|
||||
width 71px
|
||||
height 100px
|
||||
margin 0.3rem
|
||||
|
||||
.anime-grid-cell-hide
|
||||
opacity 0.05
|
||||
pointer-events none
|
||||
|
||||
.anime-grid-image
|
||||
grid-image
|
||||
|
||||
.anime-grid-add-button
|
||||
opacity 0
|
||||
position absolute
|
||||
top 5px
|
||||
right 5px
|
||||
padding 0.25rem
|
||||
height auto
|
7
elements/AnimeList/AnimeList.pixy
Normal file
7
elements/AnimeList/AnimeList.pixy
Normal file
@ -0,0 +1,7 @@
|
||||
component AnimeList(animeListItems []*arn.AnimeListItem, nextIndex int, viewUser *arn.User, user *arn.User)
|
||||
#load-more-target.anime-list
|
||||
AnimeListScrollable(animeListItems, viewUser, user)
|
||||
|
||||
if nextIndex != -1
|
||||
.buttons
|
||||
LoadMore(nextIndex)
|
36
elements/AnimeList/AnimeListScrollable.pixy
Normal file
36
elements/AnimeList/AnimeListScrollable.pixy
Normal file
@ -0,0 +1,36 @@
|
||||
component AnimeListScrollable(animeListItems []*arn.AnimeListItem, viewUser *arn.User, user *arn.User)
|
||||
each item in animeListItems
|
||||
.anime-list-item.mountable(title=item.Notes, data-api="/api/animelist/" + viewUser.ID + "/field/Items[AnimeID=\"" + item.AnimeID + "\"]")
|
||||
.anime-list-item-image-container(draggable="true")
|
||||
a.anime-list-item-image-link(href=item.Anime().Link())
|
||||
img.anime-list-item-image.lazy(data-src=item.Anime().ImageLink("small"), data-webp="true", data-color=item.Anime().AverageColor(), alt=item.Anime().Title.ByUser(user))
|
||||
|
||||
.anime-list-item-name(draggable="true")
|
||||
a(href=item.Link(viewUser.Nick))= item.Anime().Title.ByUser(user)
|
||||
|
||||
//- .anime-list-item-actions
|
||||
//- if user != nil && item.Status != arn.AnimeListStatusCompleted
|
||||
//- if item.Anime().EpisodeByNumber(item.Episodes + 1) != nil
|
||||
//- for _, link := range item.Anime().EpisodeByNumber(item.Episodes + 1).Links
|
||||
//- a.tip(href=link, aria-label="Watch episode " + fmt.Sprint(item.Episodes + 1), target="_blank", rel="noopener")
|
||||
//- RawIcon("eye")
|
||||
|
||||
.anime-list-item-airing-date
|
||||
if item.Status != arn.AnimeListStatusCompleted && item.Anime().UpcomingEpisode() != nil
|
||||
span.utc-airing-date(data-start-date=item.Anime().UpcomingEpisode().Episode.AiringDate.Start, data-end-date=item.Anime().UpcomingEpisode().Episode.AiringDate.End, data-episode-number=item.Anime().UpcomingEpisode().Episode.Number)
|
||||
|
||||
if item.Status != arn.AnimeListStatusCompleted
|
||||
.anime-list-item-episodes
|
||||
.anime-list-item-episodes-watched
|
||||
.action(contenteditable=arn.SameUser(user, viewUser), data-field="Episodes", data-type="number", data-trigger="focusout", data-action="save")= item.Episodes
|
||||
|
||||
if item.Status == arn.AnimeListStatusWatching && user != nil && user.ID == viewUser.ID
|
||||
.plus-episode.action(data-action="increaseEpisode", data-trigger="click") +
|
||||
else
|
||||
.plus-episode-dummy +
|
||||
|
||||
.anime-list-item-episodes-separator /
|
||||
.anime-list-item-episodes-max= item.Anime().EpisodeCountString()
|
||||
|
||||
.anime-list-item-rating-container
|
||||
.anime-list-item-rating.action.tip(contenteditable=arn.SameUser(user, viewUser), data-field="Rating.Overall", data-type="number", data-trigger="focusout", data-action="save", aria-label="O: " + utils.FormatRating(item.Rating.Overall) + " | S: " + utils.FormatRating(item.Rating.Story) + " | V: " + utils.FormatRating(item.Rating.Visuals) + " | M: " + utils.FormatRating(item.Rating.Soundtrack))= utils.FormatRating(item.Rating.Overall)
|
9
elements/AnimeListItems.pixy
Normal file
9
elements/AnimeListItems.pixy
Normal file
@ -0,0 +1,9 @@
|
||||
component AnimeListItems(animeListItems []*arn.AnimeListItem, nextIndex int, viewUser *arn.User, user *arn.User)
|
||||
if len(animeListItems) == 0
|
||||
if user != nil && user.ID == viewUser.ID
|
||||
p.no-data.mountable= "You haven't added any anime to this list yet."
|
||||
else
|
||||
p.no-data.mountable= viewUser.Nick + " hasn't added any anime to this list yet."
|
||||
else
|
||||
.anime-list-container
|
||||
AnimeList(animeListItems, nextIndex, viewUser, user)
|
2
elements/Avatar/Avatar.pixy
Normal file
2
elements/Avatar/Avatar.pixy
Normal file
@ -0,0 +1,2 @@
|
||||
component Avatar(user *arn.User)
|
||||
CustomAvatar(user, user.Link(), user.Nick)
|
5
elements/Avatar/AvatarNoLink.pixy
Normal file
5
elements/Avatar/AvatarNoLink.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component AvatarNoLink(user *arn.User)
|
||||
if user.HasAvatar()
|
||||
img.user-image.lazy(data-src=user.AvatarLink("small"), data-webp="true", alt=user.Nick)
|
||||
else
|
||||
SVGAvatar(user)
|
3
elements/Avatar/AvatarNoTip.pixy
Normal file
3
elements/Avatar/AvatarNoTip.pixy
Normal file
@ -0,0 +1,3 @@
|
||||
component AvatarNoTip(user *arn.User)
|
||||
a.user(href=user.Link(), title=user.Nick)
|
||||
AvatarNoLink(user)
|
7
elements/Avatar/CustomAvatar.pixy
Normal file
7
elements/Avatar/CustomAvatar.pixy
Normal file
@ -0,0 +1,7 @@
|
||||
component CustomAvatar(user *arn.User, link string, title string)
|
||||
a.user.tip(href=link, aria-label=title)
|
||||
AvatarNoLink(user)
|
||||
|
||||
if user.IsPro()
|
||||
.user-pro-icon
|
||||
RawIcon("star")
|
5
elements/Avatar/ProfileImage.pixy
Normal file
5
elements/Avatar/ProfileImage.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component ProfileImage(user *arn.User)
|
||||
if user.HasAvatar()
|
||||
img.profile-image.lazy(data-src=user.AvatarLink("large"), data-webp="true", alt="Profile image", importance="high")
|
||||
else
|
||||
SVGProfileImage(user)
|
9
elements/Avatar/SVGAvatar.pixy
Normal file
9
elements/Avatar/SVGAvatar.pixy
Normal file
@ -0,0 +1,9 @@
|
||||
component SVGAvatar(user *arn.User)
|
||||
svg.user-image(viewBox="0 0 50 50")
|
||||
circle.head(cx="25", cy="19", r="10")
|
||||
circle.body(cx="25", cy="50", r="20")
|
||||
|
||||
if len(user.Nick) <= 6
|
||||
text.svg-nick(x="25", y="44", text-anchor="middle")= user.Nick
|
||||
else
|
||||
text.svg-nick(x="25", y="44", text-anchor="middle")= user.Nick[:6]
|
4
elements/Avatar/SVGProfileImage.pixy
Normal file
4
elements/Avatar/SVGProfileImage.pixy
Normal file
@ -0,0 +1,4 @@
|
||||
component SVGProfileImage(user *arn.User)
|
||||
svg.profile-image(viewBox="0 0 50 50", alt="Profile image")
|
||||
circle.head(cx="25", cy="19", r="10")
|
||||
circle.body(cx="25", cy="50", r="20")
|
14
elements/Comments/Comments.pixy
Normal file
14
elements/Comments/Comments.pixy
Normal file
@ -0,0 +1,14 @@
|
||||
component Comments(parent arn.PostParent, user *arn.User)
|
||||
.posts
|
||||
if user != nil
|
||||
if arn.IsLocked(parent)
|
||||
footer.footer.mountable
|
||||
p.text-center= "This " + strings.ToLower(reflect.TypeOf(parent).Elem().Name()) + " is locked."
|
||||
else if parent.TypeName() != "Group" || parent.(*arn.Group).FindMember(user.ID) != nil
|
||||
NewPostArea(parent, user, "Comment")
|
||||
|
||||
//- if parent.CountPosts() == 0
|
||||
//- p.no-data.mountable No comments have been written yet.
|
||||
//- else
|
||||
each post in parent.PostsRelevantFirst(5)
|
||||
Postable(post, user, true, false, "")
|
3
elements/EditForm.pixy
Normal file
3
elements/EditForm.pixy
Normal file
@ -0,0 +1,3 @@
|
||||
component EditFormImagePreview(link string, imageURL string, webp bool, title string)
|
||||
a.tip(href=link, target="_blank", aria-label=title)
|
||||
img.lazy(data-src=imageURL, alt="Preview", data-webp=webp)
|
10
elements/Email.pixy
Normal file
10
elements/Email.pixy
Normal file
@ -0,0 +1,10 @@
|
||||
component NotificationEmail(notification *arn.Notification)
|
||||
h2= notification.Message
|
||||
|
||||
p
|
||||
img(src=notification.Icon, alt="Icon", style="width:125px; height:125px; object-fit: cover;")
|
||||
|
||||
p= notification.Message
|
||||
|
||||
if notification.Link != ""
|
||||
a(href=notification.Link, target="_blank") View it on Anime Notifier
|
2
elements/ExternalMedia.pixy
Normal file
2
elements/ExternalMedia.pixy
Normal file
@ -0,0 +1,2 @@
|
||||
component ExternalMedia(media *arn.ExternalMedia)
|
||||
iframe.lazy(data-src=media.EmbedLink(), title=media.Service + " media", allowfullscreen)
|
2
elements/Icon/Icon.pixy
Normal file
2
elements/Icon/Icon.pixy
Normal file
@ -0,0 +1,2 @@
|
||||
component Icon(name string)
|
||||
svg-icon.padded-icon(name=name, class="icon-" + name)
|
10
elements/Icon/Icon.scarlet
Normal file
10
elements/Icon/Icon.scarlet
Normal file
@ -0,0 +1,10 @@
|
||||
svg-icon
|
||||
display inline-block
|
||||
width 1em
|
||||
height 1em
|
||||
|
||||
svg
|
||||
display inherit
|
||||
width 1em
|
||||
height 1em
|
||||
fill currentColor
|
2
elements/Icon/RawIcon.pixy
Normal file
2
elements/Icon/RawIcon.pixy
Normal file
@ -0,0 +1,2 @@
|
||||
component RawIcon(name string)
|
||||
svg-icon(name=name, class="icon-" + name)
|
5
elements/ImportButton.pixy
Normal file
5
elements/ImportButton.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component ImportButton(url string)
|
||||
.buttons.import-buttons
|
||||
a.button.mountable(href=url)
|
||||
Icon("check")
|
||||
span Import
|
11
elements/Input/InputBool.pixy
Normal file
11
elements/Input/InputBool.pixy
Normal file
@ -0,0 +1,11 @@
|
||||
component InputBool(id string, value bool, label string, title string)
|
||||
.widget-section
|
||||
label= label + ":"
|
||||
if value
|
||||
button.action(id=id, data-action="disable", data-trigger="click", data-field=id, title=title)
|
||||
Icon("toggle-on")
|
||||
span ON
|
||||
else
|
||||
button.action(id=id, data-action="enable", data-trigger="click", data-field=id, title=title)
|
||||
Icon("toggle-off")
|
||||
span OFF
|
9
elements/Input/InputColor.pixy
Normal file
9
elements/Input/InputColor.pixy
Normal file
@ -0,0 +1,9 @@
|
||||
component InputColor(id string, variable string, label string)
|
||||
.widget-section
|
||||
label(for=id)= label
|
||||
|
||||
.color-picker-container
|
||||
.widget-ui-element.color-picker.color-box.action(data-color="var(--" + variable + ")", data-variable=variable, data-action="pickColor", data-trigger="click")
|
||||
|
||||
button.tip(aria-label="Reset", disabled)
|
||||
RawIcon("power-off")
|
6
elements/Input/InputFileUpload.pixy
Normal file
6
elements/Input/InputFileUpload.pixy
Normal file
@ -0,0 +1,6 @@
|
||||
component InputFileUpload(id string, label string, uploadType string, endpoint string)
|
||||
.widget-section
|
||||
label= label + ":"
|
||||
button.action(id=id, data-action="selectFile", data-trigger="click", data-endpoint=endpoint, data-type=uploadType)
|
||||
Icon("upload")
|
||||
span Select file
|
14
elements/Input/InputNumber.pixy
Normal file
14
elements/Input/InputNumber.pixy
Normal file
@ -0,0 +1,14 @@
|
||||
component InputNumber(id string, value float64, label string, placeholder string, min string, max string, step string)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
input.widget-ui-element.action(id=id, data-field=id, type="number", value=value, min=min, max=max, step=step, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")
|
||||
|
||||
component InputNumberWithButtons(id string, value float64, label string, placeholder string, min string, max string, step string)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
.number-input-container
|
||||
input.widget-ui-element.action(id=id, data-field=id, type="number", value=value, min=min, max=max, step=step, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")
|
||||
button.action.tip(data-action="addNumber", data-trigger="click", data-id=id, data-add="1", aria-label="Increase by 1")
|
||||
RawIcon("plus")
|
||||
button.action.tip(data-action="addNumber", data-trigger="click", data-id=id, data-add="-1", aria-label="Decrease by 1")
|
||||
RawIcon("minus")
|
6
elements/Input/InputSelection.pixy
Normal file
6
elements/Input/InputSelection.pixy
Normal file
@ -0,0 +1,6 @@
|
||||
component InputSelection(id string, value string, label string, placeholder string, options []*arn.Option)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
select.widget-ui-element.action(id=id, data-field=id, value=value, title=placeholder, data-action="save", data-trigger="change")
|
||||
each option in options
|
||||
option(value=option.Value)= option.Label
|
13
elements/Input/InputTags.pixy
Normal file
13
elements/Input/InputTags.pixy
Normal file
@ -0,0 +1,13 @@
|
||||
component InputTags(id string, value []string, label string, tooltip string)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
.tags(id=id)
|
||||
for index, tag := range value
|
||||
.tag.tag-edit.action(contenteditable="true", data-action="save", data-trigger="focusout", data-field=id + "[" + strconv.Itoa(index) + "]")= tag
|
||||
button.tag-remove.action(data-action="arrayRemove", data-trigger="click", data-field=id, data-index=index)
|
||||
RawIcon("trash")
|
||||
|
||||
button.tag-add.action(data-action="arrayAppend", data-trigger="click", data-field=id, title="Add more")
|
||||
RawIcon("plus")
|
||||
|
||||
p!= tooltip
|
4
elements/Input/InputText.pixy
Normal file
4
elements/Input/InputText.pixy
Normal file
@ -0,0 +1,4 @@
|
||||
component InputText(id string, value string, label string, placeholder string, maxLength int)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
input.widget-ui-element.action(id=id, data-field=id, type="text", value=value, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change", maxlength=maxLength)
|
4
elements/Input/InputTextArea.pixy
Normal file
4
elements/Input/InputTextArea.pixy
Normal file
@ -0,0 +1,4 @@
|
||||
component InputTextArea(id string, value string, label string, placeholder string, maxLength int)
|
||||
.widget-section
|
||||
label(for=id)= label + ":"
|
||||
textarea.widget-ui-element.action(id=id, data-field=id, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change", maxlength=maxLength)= value
|
87
elements/Input/input.scarlet
Normal file
87
elements/Input/input.scarlet
Normal file
@ -0,0 +1,87 @@
|
||||
input, textarea, button, .button, select
|
||||
ui-element
|
||||
font-family inherit
|
||||
font-size 1em
|
||||
line-height 1.25em
|
||||
color text-color
|
||||
|
||||
input, textarea, select
|
||||
input-focus
|
||||
width 100%
|
||||
|
||||
:disabled
|
||||
ui-disabled
|
||||
|
||||
input, select
|
||||
padding 0.5rem 1rem
|
||||
|
||||
input
|
||||
height input-height
|
||||
|
||||
[pattern]
|
||||
:focus
|
||||
:invalid
|
||||
border-color red !important
|
||||
|
||||
:valid
|
||||
border-color green !important
|
||||
|
||||
:active
|
||||
transform translateY(3px)
|
||||
|
||||
.color-picker-container
|
||||
horizontal
|
||||
|
||||
.color-picker
|
||||
ui-element
|
||||
flex 1
|
||||
height input-height
|
||||
margin-right content-padding-half
|
||||
|
||||
:hover
|
||||
cursor pointer
|
||||
|
||||
:active
|
||||
transform translateY(3px)
|
||||
|
||||
button, .button
|
||||
horizontal
|
||||
padding 0rem 1rem
|
||||
color button-color
|
||||
align-items center
|
||||
pointer-events all
|
||||
height input-height
|
||||
|
||||
button-hover
|
||||
|
||||
:disabled
|
||||
ui-disabled
|
||||
|
||||
select
|
||||
appearance none
|
||||
-webkit-appearance none
|
||||
-moz-appearance none
|
||||
|
||||
option
|
||||
color text-color
|
||||
background bg-color
|
||||
|
||||
label
|
||||
width 100%
|
||||
padding 0.5rem 0
|
||||
text-align left
|
||||
|
||||
textarea
|
||||
padding 0.4em 0.8em
|
||||
line-height 1.5em
|
||||
min-height 10rem
|
||||
transition none
|
||||
|
||||
.number-input-container
|
||||
horizontal
|
||||
|
||||
button
|
||||
justify-content center
|
||||
margin-left 0.2rem
|
||||
width input-height
|
||||
height input-height
|
45
elements/Input/widgets.scarlet
Normal file
45
elements/Input/widgets.scarlet
Normal file
@ -0,0 +1,45 @@
|
||||
.widget
|
||||
vertical
|
||||
flex 1
|
||||
margin content-padding-half
|
||||
|
||||
.widget-section
|
||||
vertical
|
||||
width 100%
|
||||
|
||||
.widget-section-with-preview
|
||||
horizontal
|
||||
|
||||
.widget-section-preview
|
||||
display flex
|
||||
justify-content center
|
||||
align-items center
|
||||
margin-left 1rem
|
||||
|
||||
img
|
||||
anime-mini-item-image
|
||||
|
||||
.widget-title
|
||||
horizontal
|
||||
align-items center
|
||||
padding-bottom 0.5rem
|
||||
border-bottom 1px solid rgba(0, 0, 0, 0.1)
|
||||
// We need !important here to overwrite the h3:first-child rule
|
||||
margin 1rem 0 !important
|
||||
|
||||
.widget-ui-element
|
||||
vertical-wrap
|
||||
ui-element
|
||||
transition border transition-speed ease, background transition-speed ease, transform transition-speed ease, color transition-speed ease
|
||||
margin-bottom 1rem
|
||||
padding 0.5rem 1rem
|
||||
width 100%
|
||||
// max-width 700px
|
||||
|
||||
.widget-form
|
||||
width 100%
|
||||
max-width 650px
|
||||
margin 0 auto
|
||||
|
||||
.indent
|
||||
margin-left 1rem
|
12
elements/Japanese.pixy
Normal file
12
elements/Japanese.pixy
Normal file
@ -0,0 +1,12 @@
|
||||
component Japanese(text string)
|
||||
if stringutils.ContainsUnicodeLetters(text)
|
||||
for _, token := range arn.JapaneseTokenizer.Tokenize(text)
|
||||
if token.Furigana
|
||||
a.japanese(href="http://jisho.org/search/" + token.Original, target="_blank", rel="noopener")
|
||||
ruby(title=token.Romaji)= token.Original
|
||||
rt.furigana= token.Hiragana
|
||||
else
|
||||
ruby.japanese(title=token.Romaji)= token.Original
|
||||
rt.furigana
|
||||
else
|
||||
span.japanese= text
|
29
elements/Like.pixy
Normal file
29
elements/Like.pixy
Normal file
@ -0,0 +1,29 @@
|
||||
component LikeButton(label string, icon string, typeName string, likeable arn.Likeable, user *arn.User)
|
||||
if user == nil
|
||||
button.tip.action(aria-label="Login to like this " + typeName)
|
||||
Icon(icon)
|
||||
span= label
|
||||
else
|
||||
if likeable.LikedBy(user.ID)
|
||||
button.tip.action(data-api="/api" + likeable.Link(), data-action="unlike", data-trigger="click", aria-label="Click to unlike this " + typeName)
|
||||
Icon(icon)
|
||||
span= label
|
||||
else
|
||||
button.tip.action(data-api="/api" + likeable.Link(), data-action="like", data-trigger="click", aria-label="Click to like this " + typeName)
|
||||
Icon(icon + "-o")
|
||||
span= label
|
||||
|
||||
component LikeTab(label string, icon string, typeName string, likeable arn.Likeable, user *arn.User)
|
||||
if user == nil
|
||||
.tab.action(aria-label=label, title="Login to like this " + typeName)
|
||||
Icon(icon)
|
||||
span.tab-text= label
|
||||
else
|
||||
if likeable.LikedBy(user.ID)
|
||||
.tab.action(data-api="/api" + likeable.Link(), data-action="unlike", data-trigger="click", aria-label=label, title="Click to unlike this " + typeName)
|
||||
Icon(icon)
|
||||
span.tab-text= label
|
||||
else
|
||||
.tab.action(data-api="/api" + likeable.Link(), data-action="like", data-trigger="click", aria-label=label, title="Click to like this " + typeName)
|
||||
Icon(icon + "-o")
|
||||
span.tab-text= label
|
4
elements/LoadMore.pixy
Normal file
4
elements/LoadMore.pixy
Normal file
@ -0,0 +1,4 @@
|
||||
component LoadMore(index int)
|
||||
button#load-more-button.action(data-action="loadMore", data-trigger="click", data-index=index)
|
||||
Icon("refresh")
|
||||
span Load more
|
11
elements/LoadingAnimation/LoadingAnimation.pixy
Normal file
11
elements/LoadingAnimation/LoadingAnimation.pixy
Normal file
@ -0,0 +1,11 @@
|
||||
component LoadingAnimation
|
||||
#loading.sk-cube-grid.fade
|
||||
.sk-cube.hide
|
||||
.sk-cube
|
||||
.sk-cube.hide
|
||||
.sk-cube
|
||||
.sk-cube.sk-cube-center
|
||||
.sk-cube
|
||||
.sk-cube.hide
|
||||
.sk-cube
|
||||
.sk-cube.hide
|
42
elements/LoadingAnimation/LoadingAnimation.scarlet
Normal file
42
elements/LoadingAnimation/LoadingAnimation.scarlet
Normal file
@ -0,0 +1,42 @@
|
||||
const loading-anim-duration = 0.8s
|
||||
const loading-anim-size = 24px
|
||||
|
||||
#loading
|
||||
position fixed
|
||||
bottom 1.15rem
|
||||
right 1.15rem
|
||||
z-index 1
|
||||
pointer-events none
|
||||
|
||||
.sk-cube-grid
|
||||
horizontal-wrap
|
||||
width loading-anim-size
|
||||
height loading-anim-size
|
||||
transform rotateZ(0deg)
|
||||
animation sk-rotate loading-anim-duration infinite linear
|
||||
|
||||
.sk-cube
|
||||
width 33.3%
|
||||
height 33.3%
|
||||
background-color loading-anim-color
|
||||
opacity 0.7
|
||||
border-radius 100%
|
||||
animation sk-pulse loading-anim-duration infinite linear
|
||||
|
||||
.sk-cube-center
|
||||
opacity 1.0
|
||||
|
||||
.hide
|
||||
visibility hidden
|
||||
|
||||
animation sk-rotate
|
||||
0%
|
||||
transform rotateZ(0deg)
|
||||
100%
|
||||
transform rotateZ(360deg)
|
||||
|
||||
animation sk-pulse
|
||||
0%, 100%
|
||||
transform scale3D(0.4, 0.4, 0.4)
|
||||
50%
|
||||
transform scale3D(0.9, 0.9, 0.9)
|
25
elements/NewPostArea.pixy
Normal file
25
elements/NewPostArea.pixy
Normal file
@ -0,0 +1,25 @@
|
||||
component NewPostArea(parent arn.PostParent, user *arn.User, placeholder string)
|
||||
#new-post.post.mountable
|
||||
.post-parent
|
||||
.post-author
|
||||
Avatar(user)
|
||||
|
||||
textarea#new-post-text.post-content(placeholder=placeholder + "...", aria-label=placeholder, maxlength=limits.DefaultTextAreaMaxLength)
|
||||
|
||||
if !arn.IsLocked(parent)
|
||||
NewPostActions(parent, false)
|
||||
|
||||
component NewPostActions(parent arn.PostParent, cancelButton bool)
|
||||
.buttons.new-post-actions
|
||||
button#reply-button.mountable.action(data-action="createPost", data-trigger="click", data-parent-type=parent.TypeName(), data-parent-id=parent.GetID())
|
||||
Icon("mail-reply")
|
||||
|
||||
if parent.TypeName() == "Post" || parent.TypeName() == "Thread"
|
||||
span= "Reply to " + parent.Creator().Nick
|
||||
else
|
||||
span Submit
|
||||
|
||||
if cancelButton
|
||||
button#reply-cancel-button.mountable.action(data-action="cancelReply", data-trigger="click")
|
||||
Icon("close")
|
||||
span Cancel
|
75
elements/Postable/Postable.pixy
Normal file
75
elements/Postable/Postable.pixy
Normal file
@ -0,0 +1,75 @@
|
||||
component Postable(post arn.Postable, user *arn.User, includeReplies bool, showParent bool, highlightAuthorID string)
|
||||
.post.mountable(id=fmt.Sprintf("%s-%s", strings.ToLower(post.TypeName()), post.GetID()), data-pro=post.Creator().IsPro(), data-api=fmt.Sprintf("/api/%s/%s", strings.ToLower(post.TypeName()), post.GetID()))
|
||||
.post-parent
|
||||
.post-author
|
||||
Avatar(post.Creator())
|
||||
|
||||
.post-box(data-highlight=post.Creator().ID == highlightAuthorID)
|
||||
.post-header
|
||||
.post-header-info
|
||||
a(href=post.Creator().Link())= post.Creator().Nick
|
||||
|
||||
if showParent
|
||||
if post.TypeName() == "Thread"
|
||||
span in
|
||||
a(href=post.Link())= post.TitleByUser(user)
|
||||
else if post.GetParentType() == "User"
|
||||
if post.GetParentID() != post.Creator().ID
|
||||
span to
|
||||
a(href=post.Parent().Link())= post.Parent().TitleByUser(user)
|
||||
else if post.GetParentType() != ""
|
||||
span in
|
||||
a(href=post.Parent().Link())= post.Parent().TitleByUser(user)
|
||||
|
||||
if user != nil
|
||||
if user.ID == post.Creator().ID
|
||||
button.post-action.post-header-action.tip.action(data-action="editPost", data-trigger="click", data-id=post.GetID(), aria-label="Edit")
|
||||
RawIcon("pencil")
|
||||
|
||||
if post.TypeName() != "Thread"
|
||||
if user != nil && (user.Role == "admin" || user.Role == "editor")
|
||||
button.post-action.post-header-action.tip.action(data-action="deletePost", data-trigger="click", data-id=post.GetID(), aria-label="Delete")
|
||||
RawIcon("trash")
|
||||
|
||||
a.post-action.post-header-action.tip(href=post.Link(), aria-label="Link")
|
||||
RawIcon("link")
|
||||
|
||||
.post-date.utc-date(data-date=post.GetCreated())
|
||||
|
||||
.post-content(id="render-" + post.GetID())!= post.HTML()
|
||||
|
||||
if user != nil && user.ID == post.Creator().ID
|
||||
.post-edit-interface
|
||||
if post.TypeName() == "Thread"
|
||||
input.post-title-input.hidden(id="title-" + post.GetID(), value=post.TitleByUser(user), type="text", placeholder="Thread title")
|
||||
|
||||
textarea.post-text-input.hidden(id="source-" + post.GetID(), maxlength=limits.DefaultTextAreaMaxLength)= post.GetText()
|
||||
|
||||
.buttons.hidden(id="edit-toolbar-" + post.GetID())
|
||||
a.button.post-save.action(data-action="savePost", data-trigger="click", data-id=post.GetID())
|
||||
Icon("save")
|
||||
span Save
|
||||
|
||||
a.button.post-cancel-edit.action(data-action="editPost", data-trigger="click", data-id=post.GetID())
|
||||
Icon("close")
|
||||
span Cancel
|
||||
|
||||
.post-toolbar
|
||||
if user != nil
|
||||
button.post-action.post-toolbar-action.tip.action(data-post-id=post.GetID(), aria-label="Reply", data-action="reply", data-trigger="click")
|
||||
Icon("reply")
|
||||
span= post.CountPosts()
|
||||
|
||||
if user != nil && post.LikedBy(user.ID)
|
||||
button.post-action.post-toolbar-action.tip.action(id="unlike-" + post.GetID(), aria-label="Unlike", data-action="unlike", data-trigger="click", data-like="true")
|
||||
Icon("heart")
|
||||
span= post.CountLikes()
|
||||
else
|
||||
button.post-action.post-toolbar-action.tip.action(id="like-" + post.GetID(), aria-label="Like", data-action="like", data-trigger="click", data-like="false")
|
||||
Icon("heart-o")
|
||||
span= post.CountLikes()
|
||||
|
||||
.replies(id="replies-" + post.GetID())
|
||||
if includeReplies
|
||||
each reply in post.Posts()
|
||||
Postable(reply, user, true, false, highlightAuthorID)
|
109
elements/Postable/Postable.scarlet
Normal file
109
elements/Postable/Postable.scarlet
Normal file
@ -0,0 +1,109 @@
|
||||
post-content-padding-y = 0.75rem
|
||||
|
||||
.post-author
|
||||
horizontal
|
||||
justify-content center
|
||||
align-items flex-start
|
||||
margin-right post-avatar-text-margin
|
||||
|
||||
.post-header
|
||||
horizontal
|
||||
horizontal-line-bottom
|
||||
|
||||
.post-header-info
|
||||
flex 1
|
||||
clip-long-text
|
||||
|
||||
.post-action
|
||||
display flex
|
||||
align-items center
|
||||
border none
|
||||
background none
|
||||
padding 0
|
||||
height auto
|
||||
color hsla(text-color-h, text-color-s, text-color-l, 0.5)
|
||||
|
||||
:hover
|
||||
color link-hover-color
|
||||
background none
|
||||
|
||||
.post-header-action
|
||||
opacity 0
|
||||
margin-right 0.5rem
|
||||
|
||||
.post-date
|
||||
color hsla(text-color-h, text-color-s, text-color-l, 0.5)
|
||||
white-space nowrap
|
||||
|
||||
.post-box
|
||||
ui-element
|
||||
flex-grow 1
|
||||
padding 0.75rem 1rem
|
||||
position relative
|
||||
overflow hidden
|
||||
|
||||
h1, h2, h3
|
||||
font-weight bold
|
||||
text-align left
|
||||
line-height 1.5em
|
||||
margin 1rem 0
|
||||
|
||||
h1
|
||||
font-size 1.5rem
|
||||
|
||||
h2
|
||||
font-size 1.3rem
|
||||
|
||||
h3
|
||||
font-size 1.1rem
|
||||
|
||||
img
|
||||
max-width 100%
|
||||
max-height 450px
|
||||
width 100%
|
||||
object-fit cover
|
||||
|
||||
:hover
|
||||
.post-header-action
|
||||
opacity 1
|
||||
|
||||
.post-toolbar
|
||||
horizontal
|
||||
justify-content flex-end
|
||||
margin-top typography-margin
|
||||
padding-top typography-margin
|
||||
border-top 1px solid reverse-light-color
|
||||
|
||||
.post-toolbar-action
|
||||
margin-left 1rem
|
||||
|
||||
[data-like="true"]
|
||||
color hsla(0, 90%, 50%, 1)
|
||||
|
||||
.new-post-actions
|
||||
justify-content flex-end
|
||||
opacity 0
|
||||
height 0
|
||||
transform translateY(-50%)
|
||||
transition all transition-speed ease
|
||||
|
||||
button
|
||||
pointer-events none
|
||||
|
||||
.new-post-actions-enabled
|
||||
opacity 1
|
||||
height auto
|
||||
margin-bottom 0.75rem
|
||||
transform translateY(0)
|
||||
|
||||
button
|
||||
pointer-events all
|
||||
|
||||
.post-edit-interface
|
||||
vertical
|
||||
|
||||
.post-title-input
|
||||
margin-bottom post-content-padding-y
|
||||
|
||||
.post-text-input
|
||||
min-height 200px
|
5
elements/PostableList.pixy
Normal file
5
elements/PostableList.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component PostableList(postables []arn.Postable, user *arn.User)
|
||||
.thread
|
||||
.posts
|
||||
each post in postables
|
||||
Postable(post, user, false, false, "")
|
14
elements/Quote/Quote.pixy
Normal file
14
elements/Quote/Quote.pixy
Normal file
@ -0,0 +1,14 @@
|
||||
component Quote(quote *arn.Quote, user *arn.User)
|
||||
.quote.mountable
|
||||
QuoteContent(quote, user)
|
||||
QuoteFooter(quote)
|
||||
|
||||
component QuoteContent(quote *arn.Quote, user *arn.User)
|
||||
.quote-content
|
||||
a.quotation(href=quote.Link())
|
||||
QuoteText(quote)
|
||||
|
||||
QuoteCharacter(quote, user)
|
||||
|
||||
component QuoteText(quote *arn.Quote)
|
||||
blockquote!= utils.RenderQuoteText(quote.Text.English)
|
56
elements/Quote/Quote.scarlet
Normal file
56
elements/Quote/Quote.scarlet
Normal file
@ -0,0 +1,56 @@
|
||||
const quote-margin = 1rem
|
||||
|
||||
.quote
|
||||
vertical
|
||||
flex 1
|
||||
flex-basis 500px
|
||||
margin quote-margin 0
|
||||
|
||||
> 500px
|
||||
.quote
|
||||
margin quote-margin
|
||||
|
||||
.quote-content
|
||||
vertical
|
||||
ui-element
|
||||
border-left 5px solid quote-side-border-color !important
|
||||
box-shadow shadow-light
|
||||
|
||||
.quote-line
|
||||
// ...
|
||||
|
||||
.quote-character
|
||||
horizontal
|
||||
align-self flex-end
|
||||
margin 0 1em 1em 0
|
||||
|
||||
.character
|
||||
margin 0
|
||||
|
||||
.quote-footer
|
||||
media-footer
|
||||
|
||||
blockquote
|
||||
flex-grow 1
|
||||
padding 1em
|
||||
|
||||
p
|
||||
line-height 2em
|
||||
quotes "\201C""\201D"
|
||||
color text-color
|
||||
|
||||
:before
|
||||
color quote-color
|
||||
content open-quote
|
||||
font-size 4em
|
||||
line-height 0.1em
|
||||
margin-right 0.25em
|
||||
vertical-align -0.4em
|
||||
|
||||
:after
|
||||
color quote-color
|
||||
content close-quote
|
||||
font-size 4em
|
||||
line-height 0.1em
|
||||
margin-left 0.25em
|
||||
vertical-align -0.4em
|
4
elements/Quote/QuoteCharacter.pixy
Normal file
4
elements/Quote/QuoteCharacter.pixy
Normal file
@ -0,0 +1,4 @@
|
||||
component QuoteCharacter(quote *arn.Quote, user *arn.User)
|
||||
if quote.CharacterID != "" && quote.Character() != nil
|
||||
footer.quote-character
|
||||
CharacterSmall(quote.Character(), user)
|
6
elements/Quote/QuoteFooter.pixy
Normal file
6
elements/Quote/QuoteFooter.pixy
Normal file
@ -0,0 +1,6 @@
|
||||
component QuoteFooter(quote *arn.Quote)
|
||||
footer.quote-footer
|
||||
span posted
|
||||
span.utc-date.no-tip(data-date=quote.Created)
|
||||
span by
|
||||
a(href=quote.Creator().Link())= quote.Creator().Nick
|
14
elements/Quote/QuotePreview.pixy
Normal file
14
elements/Quote/QuotePreview.pixy
Normal file
@ -0,0 +1,14 @@
|
||||
component QuotePreview(quote *arn.Quote, user *arn.User)
|
||||
.quote.mountable
|
||||
QuoteContentPreview(quote, user)
|
||||
QuoteFooter(quote)
|
||||
|
||||
component QuoteContentPreview(quote *arn.Quote, user *arn.User)
|
||||
.quote-content
|
||||
a.quotation(href=quote.Link())
|
||||
QuoteTextPreview(quote)
|
||||
|
||||
QuoteCharacter(quote, user)
|
||||
|
||||
component QuoteTextPreview(quote *arn.Quote)
|
||||
blockquote!= utils.RenderQuoteText(utils.CutLongDescription(quote.Text.English))
|
5
elements/Rating.pixy
Normal file
5
elements/Rating.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component Rating(value float64, userCount int, user *arn.User)
|
||||
if user == nil
|
||||
.anime-rating.tip(aria-label="Rated by " + stringutils.Plural(userCount, "user"))= fmt.Sprintf("%.1f", value)
|
||||
else
|
||||
.anime-rating.tip(aria-label="Rated by " + stringutils.Plural(userCount, "user"))= fmt.Sprintf("%." + strconv.Itoa(user.Settings().Format.RatingsPrecision) + "f", value)
|
2
elements/Search/Search.pixy
Normal file
2
elements/Search/Search.pixy
Normal file
@ -0,0 +1,2 @@
|
||||
component Search(value string)
|
||||
input#search.action(data-action="search", data-trigger="input", type="search", autocomplete="off", autocorrect="off", autocapitalize="none", spellcheck="false", placeholder="Search...", title="Shortcut: F", maxlength="100", value=value)
|
36
elements/Search/Search.scarlet
Normal file
36
elements/Search/Search.scarlet
Normal file
@ -0,0 +1,36 @@
|
||||
#search
|
||||
background transparent
|
||||
border none !important
|
||||
box-shadow none !important
|
||||
font-size 1em
|
||||
padding 0
|
||||
width 0
|
||||
height auto
|
||||
flex-grow 1
|
||||
opacity 0.5
|
||||
-webkit-appearance none
|
||||
|
||||
:focus
|
||||
color link-color
|
||||
opacity 1.0
|
||||
|
||||
::-webkit-search-cancel-button
|
||||
display none
|
||||
|
||||
// Microphone icon
|
||||
.speech-input
|
||||
display none
|
||||
opacity 0
|
||||
default-transition
|
||||
|
||||
:hover
|
||||
cursor pointer
|
||||
opacity 1
|
||||
|
||||
.speech-input-available
|
||||
display block
|
||||
opacity 0.25
|
||||
|
||||
.speech-listening
|
||||
color link-hover-color
|
||||
opacity 1
|
36
elements/SocialMedia.pixy
Normal file
36
elements/SocialMedia.pixy
Normal file
@ -0,0 +1,36 @@
|
||||
component SocialMediaLinks
|
||||
a.footer-element(href="https://discord.gg/0kimAmMCeXGXuzNF", target="_blank", rel="noopener")
|
||||
Icon("discord")
|
||||
span Discord
|
||||
|
||||
a.footer-element(href="https://www.facebook.com/animenotifier", target="_blank", rel="noopener")
|
||||
Icon("facebook")
|
||||
span Facebook
|
||||
|
||||
a.footer-element(href="https://twitter.com/animenotifier", target="_blank", rel="noopener")
|
||||
Icon("twitter")
|
||||
span Twitter
|
||||
|
||||
a.footer-element(href="https://patreon.com/eduardurbach", target="_blank", rel="noopener")
|
||||
Icon("patreon")
|
||||
span Patreon
|
||||
|
||||
a.footer-element(href="https://github.com/animenotifier/notify.moe", target="_blank", rel="noopener")
|
||||
Icon("github")
|
||||
span GitHub
|
||||
|
||||
component SocialMediaButtons
|
||||
a.social-media-button.circle-1(href="https://discord.gg/0kimAmMCeXGXuzNF", title="Discord", target="_blank", rel="noopener")
|
||||
RawIcon("discord")
|
||||
|
||||
a.social-media-button.circle-2(href="https://www.facebook.com/animenotifier", title="Facebook", target="_blank", rel="noopener")
|
||||
RawIcon("facebook-square")
|
||||
|
||||
a.social-media-button.circle-3(href="https://twitter.com/animenotifier", title="Twitter", target="_blank", rel="noopener")
|
||||
RawIcon("twitter-square")
|
||||
|
||||
a.social-media-button.circle-4(href="https://patreon.com/eduardurbach", title="Patreon", target="_blank", rel="noopener")
|
||||
RawIcon("patreon")
|
||||
|
||||
a.social-media-button.circle-5(href="https://github.com/animenotifier/notify.moe", title="GitHub", target="_blank", rel="noopener")
|
||||
RawIcon("github")
|
39
elements/SoundTrack/SoundTrack.pixy
Normal file
39
elements/SoundTrack/SoundTrack.pixy
Normal file
@ -0,0 +1,39 @@
|
||||
component SoundTrack(track *arn.SoundTrack, user *arn.User)
|
||||
.soundtrack.mountable(id=track.ID)
|
||||
SoundTrackContent(track, user)
|
||||
SoundTrackFooter(track, user)
|
||||
|
||||
component SoundTrackContent(track *arn.SoundTrack, user *arn.User)
|
||||
.soundtrack-content
|
||||
if track.MainAnime() != nil
|
||||
a.soundtrack-anime-link(href="/anime/" + track.MainAnime().ID, title=track.MainAnime().Title.ByUser(user))
|
||||
img.soundtrack-anime-image.lazy(data-src=track.MainAnime().ImageLink("medium"), data-webp="true", data-color=track.MainAnime().AverageColor(), alt=track.MainAnime().Title.Canonical)
|
||||
|
||||
SoundTrackMedia(track)
|
||||
|
||||
component SoundTrackMedia(track *arn.SoundTrack)
|
||||
if track.File != "" && track.HasMediaByService("Youtube")
|
||||
.soundtrack-media
|
||||
.media-play-area.action(data-action="toggleAudio", data-trigger="click", data-audio-src="https://notify.moe/audio/" + track.File, data-media-id=track.ID)
|
||||
img.media-image.lazy(data-src="https://img.youtube.com/vi/" + track.MediaByService("Youtube")[0].ServiceID + "/0.jpg", alt=track.Title)
|
||||
|
||||
button.media-play-button(aria-label="Play soundtrack")
|
||||
RawIcon("play")
|
||||
|
||||
.media-visualizer
|
||||
.visualizer-box.visualizer-box-1
|
||||
.visualizer-box.visualizer-box-2
|
||||
.visualizer-box.visualizer-box-3
|
||||
else if len(track.Media) > 0
|
||||
ExternalMedia(track.Media[0])
|
||||
|
||||
component SoundTrackFooter(track *arn.SoundTrack, user *arn.User)
|
||||
footer.soundtrack-footer
|
||||
if track.Title.ByUser(user) == ""
|
||||
a(href=track.Link() + "/edit") untitled
|
||||
else
|
||||
a(href=track.Link())= track.Title.ByUser(user)
|
||||
span posted
|
||||
span.utc-date.no-tip(data-date=track.Created)
|
||||
span by
|
||||
a(href=track.Creator().Link())= track.Creator().Nick + " "
|
11
elements/SoundTrack/SoundTrackMini.pixy
Normal file
11
elements/SoundTrack/SoundTrackMini.pixy
Normal file
@ -0,0 +1,11 @@
|
||||
component SoundTrackMini(track *arn.SoundTrack, user *arn.User)
|
||||
.soundtrack.mountable(id=track.ID)
|
||||
SoundTrackContent(track, user)
|
||||
SoundTrackMiniFooter(track, user)
|
||||
|
||||
component SoundTrackMiniFooter(track *arn.SoundTrack, user *arn.User)
|
||||
footer.soundtrack-footer
|
||||
if track.Title.ByUser(user) == ""
|
||||
a(href=track.Link() + "/edit") untitled
|
||||
else
|
||||
a(href=track.Link())= track.Title.ByUser(user)
|
5
elements/StatusMessage/StatusMessage.pixy
Normal file
5
elements/StatusMessage/StatusMessage.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component StatusMessage
|
||||
#status-message.fade.fade-out
|
||||
#status-message-text
|
||||
a.status-message-action.action(href="#", data-trigger="click", data-action="closeStatusMessage", aria-label="Close status message")
|
||||
RawIcon("close")
|
33
elements/StatusMessage/StatusMessage.scarlet
Normal file
33
elements/StatusMessage/StatusMessage.scarlet
Normal file
@ -0,0 +1,33 @@
|
||||
#status-message
|
||||
horizontal
|
||||
position fixed
|
||||
bottom 0
|
||||
left 0
|
||||
width 100%
|
||||
padding 0.5rem content-padding
|
||||
pointer-events none
|
||||
z-index 1000
|
||||
|
||||
&.fade-out
|
||||
z-index 1
|
||||
|
||||
#status-message-text
|
||||
flex 1
|
||||
text-align center
|
||||
line-height content-line-height
|
||||
|
||||
.status-message-action
|
||||
color white !important
|
||||
pointer-events auto !important
|
||||
display flex
|
||||
justify-content center
|
||||
align-items center
|
||||
margin-left 0.5rem
|
||||
|
||||
.error-message
|
||||
color white
|
||||
background-color hsl(0, 75%, 50%)
|
||||
|
||||
.info-message
|
||||
color white
|
||||
background tab-active-background
|
7
elements/StatusTabs.pixy
Normal file
7
elements/StatusTabs.pixy
Normal file
@ -0,0 +1,7 @@
|
||||
component StatusTabs(urlPrefix string, statusLists map[string]*arn.AnimeList)
|
||||
.tabs
|
||||
TabWithCount("Watching", len(statusLists[arn.AnimeListStatusWatching].Items), "play", urlPrefix + "/watching")
|
||||
TabWithCount("Completed", len(statusLists[arn.AnimeListStatusCompleted].Items), "check", urlPrefix + "/completed")
|
||||
TabWithCount("Planned", len(statusLists[arn.AnimeListStatusPlanned].Items), "forward", urlPrefix + "/planned")
|
||||
TabWithCount("On Hold", len(statusLists[arn.AnimeListStatusHold].Items), "pause", urlPrefix + "/hold")
|
||||
TabWithCount("Dropped", len(statusLists[arn.AnimeListStatusDropped].Items), "stop", urlPrefix + "/dropped")
|
4
elements/Tab/Tab.pixy
Normal file
4
elements/Tab/Tab.pixy
Normal file
@ -0,0 +1,4 @@
|
||||
component Tab(label string, icon string, url string)
|
||||
a.tab.action(href=url, data-action="diff", data-trigger="click", aria-label=label, dropzone="move")
|
||||
Icon(icon)
|
||||
span.tab-text= label
|
57
elements/Tab/Tab.scarlet
Normal file
57
elements/Tab/Tab.scarlet
Normal file
@ -0,0 +1,57 @@
|
||||
const tab-padding-x = 1rem
|
||||
|
||||
.tab
|
||||
horizontal
|
||||
align-items center
|
||||
color text-color
|
||||
padding 0.5rem tab-padding-x
|
||||
background-color tab-background
|
||||
border ui-border
|
||||
border-left none
|
||||
white-space nowrap
|
||||
|
||||
:hover
|
||||
color text-color
|
||||
background-color tab-hover-background
|
||||
cursor pointer
|
||||
|
||||
:active
|
||||
transform none
|
||||
|
||||
&.active
|
||||
background-color tab-active-background
|
||||
color tab-active-color
|
||||
|
||||
:first-child
|
||||
border-left ui-border
|
||||
border-top-left-radius ui-element-border-radius
|
||||
border-bottom-left-radius ui-element-border-radius
|
||||
|
||||
:last-child
|
||||
border-top-right-radius ui-element-border-radius
|
||||
border-bottom-right-radius ui-element-border-radius
|
||||
|
||||
.tab-count
|
||||
margin-left typography-margin
|
||||
opacity 0.5
|
||||
|
||||
< 920px
|
||||
.tab
|
||||
padding 0.75rem tab-padding-x
|
||||
|
||||
.padded-icon
|
||||
margin-right 0
|
||||
|
||||
.tab-text,
|
||||
.tab-count
|
||||
display none
|
||||
|
||||
.tabs
|
||||
horizontal
|
||||
justify-content center
|
||||
margin content-padding calc(content-padding / 4)
|
||||
margin-top 0
|
||||
|
||||
.tab-groups
|
||||
horizontal
|
||||
justify-content center
|
5
elements/Tab/TabWithCount.pixy
Normal file
5
elements/Tab/TabWithCount.pixy
Normal file
@ -0,0 +1,5 @@
|
||||
component TabWithCount(label string, count int, icon string, url string)
|
||||
a.tab.action(href=url, data-action="diff", data-trigger="click", aria-label=label, dropzone="move")
|
||||
Icon(icon)
|
||||
span.tab-text= label
|
||||
span.tab-count= count
|
13
elements/ThreadLink.pixy
Normal file
13
elements/ThreadLink.pixy
Normal file
@ -0,0 +1,13 @@
|
||||
component ThreadLink(thread *arn.Thread)
|
||||
.thread-link.mountable(data-sticky=thread.Sticky)
|
||||
.post-author.thread-author
|
||||
Avatar(thread.Creator())
|
||||
.thread-content-container
|
||||
.thread-content
|
||||
if thread.Sticky != 0
|
||||
Icon("thumb-tack")
|
||||
a.thread-link-title(href="/thread/" + thread.ID)= thread.Title
|
||||
.spacer
|
||||
.thread-reply-count= len(thread.PostIDs)
|
||||
.thread-icons
|
||||
Icon(arn.GetForumIcon(thread.Tags[0]))
|
7
elements/UserCard/UserCard.pixy
Normal file
7
elements/UserCard/UserCard.pixy
Normal file
@ -0,0 +1,7 @@
|
||||
component UserCard(user *arn.User, note string)
|
||||
a.user-card.mountable(href=user.Link(), data-pro=user.IsPro())
|
||||
.user-card-image-container
|
||||
AvatarNoLink(user)
|
||||
.user-card-info
|
||||
.user-card-info-main= user.Nick
|
||||
.user-card-info-details= note
|
33
elements/UserCard/UserCard.scarlet
Normal file
33
elements/UserCard/UserCard.scarlet
Normal file
@ -0,0 +1,33 @@
|
||||
.user-cards
|
||||
horizontal-wrap
|
||||
justify-content center
|
||||
|
||||
.user-card
|
||||
card
|
||||
|
||||
> 600px
|
||||
.user-card
|
||||
max-width 230px
|
||||
|
||||
.user-card-image-container
|
||||
width avatar-size
|
||||
height avatar-size
|
||||
|
||||
img
|
||||
width avatar-size
|
||||
height avatar-size
|
||||
border-radius ui-element-border-radius
|
||||
box-shadow none !important
|
||||
|
||||
.user-card-info
|
||||
vertical
|
||||
margin-left card-padding
|
||||
overflow hidden
|
||||
|
||||
.user-card-info-main
|
||||
clip-long-text
|
||||
|
||||
.user-card-info-details
|
||||
clip-long-text
|
||||
color text-color
|
||||
opacity 0.5
|
19
elements/VideoControls.pixy
Normal file
19
elements/VideoControls.pixy
Normal file
@ -0,0 +1,19 @@
|
||||
component VideoControls(containerID string, duration time.Duration)
|
||||
.video-controls
|
||||
button.video-control.video-control-play.action(data-action="togglePlayVideo", data-trigger="click", data-media-id=containerID, aria-label="Play")
|
||||
RawIcon("play")
|
||||
|
||||
button.video-control.video-control-pause.action(data-action="togglePlayVideo", data-trigger="click", data-media-id=containerID, aria-label="Pause")
|
||||
RawIcon("pause")
|
||||
|
||||
.video-progress-clickable
|
||||
.video-progress-container
|
||||
.video-progress
|
||||
|
||||
.video-time= fmt.Sprintf("%d:%02d", int(duration.Minutes()), int(duration.Seconds()) % 60)
|
||||
|
||||
//- button.video-control.action(data-action="like", data-trigger="click")
|
||||
//- RawIcon("heart-o")
|
||||
|
||||
button.video-control.video-control-fullscreen.action(data-action="toggleFullscreen", data-trigger="click", data-id=containerID, aria-label="Fullscreen")
|
||||
RawIcon("fullscreen")
|
Reference in New Issue
Block a user