This commit is contained in:
Eduard Urbach 2017-10-09 15:47:40 +02:00
parent be3dede5a9
commit 6e4897f435
21 changed files with 236 additions and 75 deletions

View File

@ -83,12 +83,9 @@ func configure(app *aero.Application) *aero.Application {
app.Ajax("/forum/:tag", forum.Get)
app.Ajax("/thread/:id", threads.Get)
app.Ajax("/post/:id", posts.Get)
app.Ajax("/soundtrack/:id", soundtrack.Get)
app.Ajax("/character/:id", character.Get)
app.Ajax("/new/thread", newthread.Get)
app.Ajax("/new/soundtrack", newsoundtrack.Get)
app.Ajax("/settings", settings.Get)
app.Ajax("/soundtracks", soundtracks.Get)
app.Ajax("/artworks", artworks.Get)
app.Ajax("/amvs", amvs.Get)
app.Ajax("/users", users.Active)
@ -99,6 +96,12 @@ func configure(app *aero.Application) *aero.Application {
app.Ajax("/statistics/anime", statistics.Anime)
app.Ajax("/login", login.Get)
// Soundtracks
app.Ajax("/soundtracks", soundtracks.Get)
app.Ajax("/new/soundtrack", newsoundtrack.Get)
app.Ajax("/soundtrack/:id", soundtrack.Get)
app.Ajax("/soundtrack/:id/edit", soundtrack.Edit)
// User profiles
app.Ajax("/user", user.Get)
app.Ajax("/user/:nick", profile.Get)

View File

@ -1,19 +1,32 @@
component InputText(id string, value string, label string, placeholder string)
.widget-input
.widget-section
label(for=id)= label + ":"
input.widget-element.action(id=id, data-field=id, type="text", value=value, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")
input.widget-ui-element.action(id=id, data-field=id, type="text", value=value, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")
component InputTextArea(id string, value string, label string, placeholder string)
.widget-input
.widget-section
label(for=id)= label + ":"
textarea.widget-element.action(id=id, data-field=id, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")= value
textarea.widget-ui-element.action(id=id, data-field=id, placeholder=placeholder, title=placeholder, data-action="save", data-trigger="change")= value
component InputNumber(id string, value float64, label string, placeholder string, min string, max string, step string)
.widget-input
.widget-section
label(for=id)= label + ":"
input.widget-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")
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 InputSelection(id string, value string, label string, placeholder string, values []string)
.widget-input
.widget-section
label(for=id)= label + ":"
select.widget-element.action(id=id, data-field=id, value=value, title=placeholder, data-action="save", data-trigger="change")
select.widget-ui-element.action(id=id, data-field=id, value=value, title=placeholder, data-action="save", data-trigger="change")
component InputTags(id string, value []string, label string)
.widget-section
label(for=id)= label + ":"
.tags(id=id)
each tag in value
.tag
span.tag-title= tag
.tag-remove.action(data-action="removeTag", data-trigger="click", data-tag=tag) x
button.tag-add
RawIcon("plus")

View File

@ -7,9 +7,9 @@ component AnimeListItem(viewUser *arn.User, item *arn.AnimeListItem, anime *arn.
.anime-list-item-episodes-edit
InputNumber("Episodes", float64(item.Episodes), "Episodes", "Number of episodes you watched", "0", arn.EpisodeCountMax(anime.EpisodeCount), "1")
.widget-input.anime-list-item-status-edit
.widget-section.anime-list-item-status-edit
label(for="Status") Status:
select.widget-element.action(id="Status", data-field="Status", value=item.Status, data-action="save", data-trigger="change")
select.widget-ui-element.action(id="Status", data-field="Status", value=item.Status, data-action="save", data-trigger="change")
option(value=arn.AnimeListStatusWatching) Watching
option(value=arn.AnimeListStatusCompleted) Completed
option(value=arn.AnimeListStatusPlanned) Plan to watch

View File

@ -14,5 +14,5 @@
horizontal-wrap
justify-content space-between
width 100%
.widget-input
.widget-section
max-width 20%

View File

@ -7,16 +7,16 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
for i := 0; i <= 4; i++
if i < len(schedule)
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
a.schedule-item-link.ajax(href=schedule[i].Anime.Link())
Icon("calendar-o")
.schedule-item-title= schedule[i].Anime.Title.Canonical
.spacer
.schedule-item-date.utc-airing-date(data-start-date=schedule[i].Episode.AiringDate.Start, data-end-date=schedule[i].Episode.AiringDate.End, data-episode-number=schedule[i].Episode.Number)
else
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("calendar-o")
span ...
@ -24,8 +24,8 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
h3.widget-title Forums
each post in posts
a.widget-element.ajax(href=post.Thread().Link())
.widget-element-text
a.widget-ui-element.ajax(href=post.Thread().Link())
.widget-ui-element-text
Icon(arn.GetForumIcon(post.Thread().Tags[0]))
span= post.Thread().Title
@ -33,8 +33,8 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
h3.widget-title Artworks
for i := 1; i <= 5; i++
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("paint-brush")
span ...
@ -43,13 +43,13 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
for i := 0; i <= 4; i++
if i < len(soundTracks)
a.widget-element.ajax(href=soundTracks[i].Link())
.widget-element-text
a.widget-ui-element.ajax(href=soundTracks[i].Link())
.widget-ui-element-text
Icon("music")
span(title=soundTracks[i].Media[0].Title)= soundTracks[i].Anime()[0].Title.Canonical
else
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("music")
span ...
@ -57,8 +57,8 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
h3.widget-title AMVs
for i := 1; i <= 5; i++
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("video-camera")
span ...
@ -66,8 +66,8 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
h3.widget-title Reviews
for i := 1; i <= 5; i++
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("book")
span ...
@ -75,8 +75,8 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
h3.widget-title Groups
for i := 1; i <= 5; i++
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("group")
span ...
@ -85,13 +85,13 @@ component Dashboard(schedule []*arn.UpcomingEpisode, posts []arn.Postable, sound
for i := 0; i <= 4; i++
if i < len(following)
a.widget-element.ajax(href="/+" + following[i].Nick)
.widget-element-text
a.widget-ui-element.ajax(href="/+" + following[i].Nick)
.widget-ui-element-text
Icon("address-card")
span= following[i].Nick
else
.widget-element
.widget-element-text
.widget-ui-element
.widget-ui-element-text
Icon("address-card")
span ...

View File

@ -2,21 +2,21 @@ component ImportLists(user *arn.User)
if user.Accounts.AniList.Nick != ""
label AniList:
.widget-input
.widget-section
a.button.mountable.ajax(href="/import/anilist/animelist")
Icon("download")
span Import AniList
if user.Accounts.Kitsu.Nick != ""
label Kitsu:
.widget-input
.widget-section
a.button.mountable.ajax(href="/import/kitsu/animelist")
Icon("download")
span Import Kitsu
if user.Accounts.MyAnimeList.Nick != ""
label MyAnimeList:
.widget-input
.widget-section
a.button.mountable.ajax(href="/import/myanimelist/animelist")
Icon("download")
span Import MyAnimeList

View File

@ -3,21 +3,21 @@ component NewSoundTrack(user *arn.User)
.widget
h1 New soundtrack
.widget-input
.widget-section
label(for="soundcloud-link") Soundcloud link:
input#soundcloud-link.widget-element(type="text", placeholder="https://soundcloud.com/abc/123")
input#soundcloud-link.widget-ui-element(type="text", placeholder="https://soundcloud.com/abc/123")
.widget-input
.widget-section
label(for="youtube-link") Youtube link:
input#youtube-link.widget-element(type="text", placeholder="https://www.youtube.com/watch?v=123")
input#youtube-link.widget-ui-element(type="text", placeholder="https://www.youtube.com/watch?v=123")
.widget-input
.widget-section
label(for="anime-link") Anime link:
input#anime-link.widget-element(type="text", placeholder="https://notify.moe/anime/123")
input#anime-link.widget-ui-element(type="text", placeholder="https://notify.moe/anime/123")
.widget-input
.widget-section
label(for="osu-link") Osu beatmap (optional):
input#osu-link.widget-element(type="text", placeholder="https://osu.ppy.sh/s/123")
input#osu-link.widget-ui-element(type="text", placeholder="https://osu.ppy.sh/s/123")
.buttons
button.action(data-action="createSoundTrack", data-trigger="click")

View File

@ -3,11 +3,11 @@ component NewThread(user *arn.User)
.widget-form
.widget
input#title.widget-element(type="text", placeholder="Title")
input#title.widget-ui-element(type="text", placeholder="Title")
textarea#text.widget-element(placeholder="Content")
textarea#text.widget-ui-element(placeholder="Content")
select#tag.widget-element(value="general")
select#tag.widget-ui-element(value="general")
option(value="general") General
option(value="news") News
option(value="anime") Anime

View File

@ -26,19 +26,19 @@ component Settings(user *arn.User)
Icon("bell")
span Notifications
#enable-notifications.widget-input
#enable-notifications.widget-section
label Enable:
button.action(data-action="enableNotifications", data-trigger="click")
Icon("toggle-off")
span Enable notifications
#disable-notifications.widget-input
#disable-notifications.widget-section
label Disable:
button.action(data-action="disableNotifications", data-trigger="click")
Icon("toggle-on")
span Disable notifications
#test-notification.widget-input
#test-notification.widget-section
label Test:
button.action(data-action="testNotification", data-trigger="click")
Icon("paper-plane")
@ -49,7 +49,7 @@ component Settings(user *arn.User)
Icon("user-plus")
span Connect
.widget-input.social-account
.widget-section.social-account
label(for="google") Google:
a#google.button.social-account-button(href="/auth/google")
@ -60,7 +60,7 @@ component Settings(user *arn.User)
Icon("circle-o")
span Not connected
.widget-input.social-account
.widget-section.social-account
label(for="facebook") Facebook:
a#facebook.button.social-account-button(href="/auth/facebook")
@ -84,7 +84,7 @@ component Settings(user *arn.User)
Icon("upload")
span Export
.widget-input
.widget-section
label JSON:
a.button(href="/api/animelist/" + user.ID)
Icon("upload")
@ -95,19 +95,19 @@ component Settings(user *arn.User)
Icon("puzzle-piece")
span Apps
.widget-input
.widget-section
label Chrome Extension:
button.action(data-action="installExtension", data-trigger="click")
Icon("chrome")
span Get the Chrome Extension
.widget-input
.widget-section
label Desktop App:
button.action(data-action="installApp", data-trigger="click")
Icon("desktop")
span Get the Desktop App
.widget-input
.widget-section
label Android App:
a.button(href="https://www.youtube.com/watch?v=opyt4cw0ep8", target="_blank", rel="noopener")
Icon("android")
@ -118,9 +118,9 @@ component Settings(user *arn.User)
Icon("picture-o")
span Avatar
.widget-input
.widget-section
label(for="Avatar.Source") Source:
select.widget-element.action(id="Avatar.Source", data-field="Avatar.Source", value=user.Settings().Avatar.Source, data-action="save", data-trigger="change")
select.widget-ui-element.action(id="Avatar.Source", data-field="Avatar.Source", value=user.Settings().Avatar.Source, data-action="save", data-trigger="change")
option(value="") Automatic
option(value="Gravatar") Gravatar
option(value="URL") Link
@ -143,7 +143,7 @@ component Settings(user *arn.User)
span PRO
if user.IsPro()
.widget-input
.widget-section
label
span Your PRO account expires in
span.utc-date(data-date=user.ProExpires)
@ -152,7 +152,7 @@ component Settings(user *arn.User)
Icon("star")
span Extend PRO account duration
else
.widget-input
.widget-section
label Would you like to support the site development?
a.button.ajax(href="/shop")
Icon("star")

View File

@ -1,4 +1,4 @@
.widget-input
.widget-section
button,
.button
margin-bottom 1rem

74
pages/soundtrack/edit.go Normal file
View File

@ -0,0 +1,74 @@
package soundtrack
import (
"bytes"
"net/http"
"reflect"
"strings"
"github.com/animenotifier/notify.moe/components"
"github.com/aerogo/aero"
"github.com/animenotifier/arn"
)
// Edit track.
func Edit(ctx *aero.Context) string {
id := ctx.Get("id")
track, err := arn.GetSoundTrack(id)
if err != nil {
return ctx.Error(http.StatusNotFound, "Track not found", err)
}
ctx.Data = &arn.OpenGraph{
Tags: map[string]string{
"og:title": track.Media[0].Title,
"og:image": track.MainAnime().Image.Large,
"og:url": "https://" + ctx.App.Config.Domain + track.Link(),
"og:site_name": "notify.moe",
"og:type": "music.song",
},
}
return ctx.HTML(EditForm(track, "Edit soundtrack"))
}
// EditForm ...
func EditForm(obj interface{}, title string) string {
t := reflect.TypeOf(obj).Elem()
v := reflect.ValueOf(obj).Elem()
lowerCaseTypeName := strings.ToLower(t.Name())
id := reflect.Indirect(v.FieldByName("ID"))
var b bytes.Buffer
b.WriteString(`<div class="widget-form">`)
b.WriteString(`<div class="widget" data-api="/api/` + lowerCaseTypeName + `/` + id.String() + `">`)
b.WriteString(`<h1>`)
b.WriteString(title)
b.WriteString(`</h1>`)
// Fields
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
if field.Anonymous || field.Tag.Get("editable") != "true" {
continue
}
fieldValue := reflect.Indirect(v.FieldByName(field.Name))
switch field.Type.String() {
case "string":
b.WriteString(components.InputText(field.Name, fieldValue.String(), field.Name, ""))
case "[]string":
b.WriteString(components.InputTags(field.Name, fieldValue.Interface().([]string), field.Name))
default:
panic("No edit form implementation for " + field.Name + " with type " + field.Type.String())
}
}
b.WriteString("</div>")
b.WriteString("</div>")
return b.String()
}

View File

@ -20,7 +20,7 @@ func Get(ctx *aero.Context) string {
ctx.Data = &arn.OpenGraph{
Tags: map[string]string{
"og:title": track.Media[0].Title,
"og:image": track.Anime()[0].Image.Large,
"og:image": track.MainAnime().Image.Large,
"og:url": "https://" + ctx.App.Config.Domain + track.Link(),
"og:site_name": "notify.moe",
"og:type": "music.song",

View File

@ -1,5 +1,8 @@
component Track(track *arn.SoundTrack)
h1= track.Media[0].Title
h1= track.Title
.sound-tracks
SoundTrackAllMedia(track)
p
a.ajax(href=track.Link() + "/edit") Edit

View File

@ -10,9 +10,11 @@ import (
const maxTracks = 9
// Get renders the music page.
// Get renders the soundtracks page.
func Get(ctx *aero.Context) string {
tracks, err := arn.AllSoundTracks()
tracks, err := arn.FilterSoundTracks(func(track *arn.SoundTrack) bool {
return !track.IsDraft
})
if err != nil {
return ctx.Error(http.StatusInternalServerError, "Error fetching soundtracks", err)
@ -24,5 +26,5 @@ func Get(ctx *aero.Context) string {
tracks = tracks[:maxTracks]
}
return ctx.HTML(components.Music(tracks))
return ctx.HTML(components.SoundTracks(tracks))
}

View File

@ -1,4 +1,4 @@
component Music(tracks []*arn.SoundTrack)
component SoundTracks(tracks []*arn.SoundTrack)
h1 Soundtracks
.music-buttons

View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/animenotifier/arn"
"github.com/fatih/color"
)
func main() {
color.Yellow("Addind draft indices")
// Iterate over the stream
for user := range arn.MustStreamUsers() {
fmt.Println(user.Nick)
draftIndex := arn.NewDraftIndex(user.ID)
arn.PanicOnError(draftIndex.Save())
}
color.Green("Finished.")
}

View File

@ -34,7 +34,7 @@ func main() {
fmt.Println(user.Nick)
inventory := arn.NewInventory(user.ID)
err = arn.DB.Set("Inventory", inventory.UserID, inventory)
err = inventory.Save()
if err != nil {
color.Red(err.Error())

View File

@ -0,0 +1,11 @@
package main
import (
"github.com/animenotifier/arn"
)
func main() {
for track := range arn.MustStreamSoundTracks() {
arn.PanicOnError(track.Save())
}
}

View File

@ -365,6 +365,15 @@ export function buyItem(arn: AnimeNotifier, button: HTMLElement) {
.then(() => arn.loading(false))
}
// Remove tag
export function removeTag(arn: AnimeNotifier, element: HTMLElement) {
let tag = element.dataset.tag
// arn.loading(true)
alert("Remove " + tag)
}
// Chrome extension installation
export function installExtension(arn: AnimeNotifier, button: HTMLElement) {
let browser: any = window["chrome"]

24
styles/tags.scarlet Normal file
View File

@ -0,0 +1,24 @@
.tags
horizontal-wrap
.tag
ui-element
padding 0.4rem 0.8rem
margin 0.4rem
.tag-input
horizontal
button
margin-left 0.8rem
.tag-remove
display inline-block
margin-left 0.4rem
opacity 0.5
:hover
cursor pointer
.tag-add
margin 0.4rem !important

View File

@ -20,7 +20,7 @@
margin-bottom 1rem
overflow hidden
.widget-element
.widget-ui-element
vertical-wrap
ui-element
transition border transition-speed ease, background transition-speed ease, transform transition-speed ease, transform color ease
@ -29,14 +29,14 @@
width 100%
// max-width 700px
.widget-element-text
.widget-ui-element-text
horizontal
clip-long-text
justify-content flex-start
align-items center
width 100%
.widget-input
.widget-section
vertical
width 100%