From 6e4897f435fff504990e9be4f461f52fab0aac9a Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Mon, 9 Oct 2017 15:47:40 +0200 Subject: [PATCH] Refactor --- main.go | 9 ++- mixins/Input.pixy | 29 ++++++-- pages/animelistitem/animelistitem.pixy | 4 +- pages/animelistitem/animelistitem.scarlet | 2 +- pages/dashboard/dashboard.pixy | 44 +++++------ pages/listimport/listimport.pixy | 6 +- pages/newsoundtrack/newsoundtrack.pixy | 16 ++-- pages/newthread/newthread.pixy | 6 +- pages/settings/settings.pixy | 26 +++---- pages/settings/settings.scarlet | 2 +- pages/soundtrack/edit.go | 74 +++++++++++++++++++ pages/soundtrack/soundtrack.go | 2 +- pages/soundtrack/soundtrack.pixy | 7 +- pages/soundtracks/soundtracks.go | 8 +- pages/soundtracks/soundtracks.pixy | 2 +- patches/add-draft-index/add-draft-index.go | 22 ++++++ .../reset-inventories/reset-inventories.go | 2 +- .../update-soundtracks/update-soundtracks.go | 11 +++ scripts/Actions.ts | 9 +++ styles/tags.scarlet | 24 ++++++ styles/widgets.scarlet | 6 +- 21 files changed, 236 insertions(+), 75 deletions(-) create mode 100644 pages/soundtrack/edit.go create mode 100644 patches/add-draft-index/add-draft-index.go create mode 100644 patches/update-soundtracks/update-soundtracks.go create mode 100644 styles/tags.scarlet diff --git a/main.go b/main.go index 94aee30f..ff6132eb 100644 --- a/main.go +++ b/main.go @@ -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) diff --git a/mixins/Input.pixy b/mixins/Input.pixy index 766b67af..9a9d6ba2 100644 --- a/mixins/Input.pixy +++ b/mixins/Input.pixy @@ -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") + \ No newline at end of file diff --git a/pages/animelistitem/animelistitem.pixy b/pages/animelistitem/animelistitem.pixy index 3b9ced93..02e2ff47 100644 --- a/pages/animelistitem/animelistitem.pixy +++ b/pages/animelistitem/animelistitem.pixy @@ -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 diff --git a/pages/animelistitem/animelistitem.scarlet b/pages/animelistitem/animelistitem.scarlet index a515568c..9fa47362 100644 --- a/pages/animelistitem/animelistitem.scarlet +++ b/pages/animelistitem/animelistitem.scarlet @@ -14,5 +14,5 @@ horizontal-wrap justify-content space-between width 100% - .widget-input + .widget-section max-width 20% \ No newline at end of file diff --git a/pages/dashboard/dashboard.pixy b/pages/dashboard/dashboard.pixy index 37753eb9..abf934f4 100644 --- a/pages/dashboard/dashboard.pixy +++ b/pages/dashboard/dashboard.pixy @@ -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 ... diff --git a/pages/listimport/listimport.pixy b/pages/listimport/listimport.pixy index 17a65ab6..aff1e117 100644 --- a/pages/listimport/listimport.pixy +++ b/pages/listimport/listimport.pixy @@ -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 \ No newline at end of file diff --git a/pages/newsoundtrack/newsoundtrack.pixy b/pages/newsoundtrack/newsoundtrack.pixy index 9d29aea0..80dbd8cd 100644 --- a/pages/newsoundtrack/newsoundtrack.pixy +++ b/pages/newsoundtrack/newsoundtrack.pixy @@ -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") diff --git a/pages/newthread/newthread.pixy b/pages/newthread/newthread.pixy index 9ddebcbe..cd28f085 100644 --- a/pages/newthread/newthread.pixy +++ b/pages/newthread/newthread.pixy @@ -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 diff --git a/pages/settings/settings.pixy b/pages/settings/settings.pixy index 32bb50f4..1195d8da 100644 --- a/pages/settings/settings.pixy +++ b/pages/settings/settings.pixy @@ -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") diff --git a/pages/settings/settings.scarlet b/pages/settings/settings.scarlet index 85f1c180..cb0cb0ca 100644 --- a/pages/settings/settings.scarlet +++ b/pages/settings/settings.scarlet @@ -1,4 +1,4 @@ -.widget-input +.widget-section button, .button margin-bottom 1rem diff --git a/pages/soundtrack/edit.go b/pages/soundtrack/edit.go new file mode 100644 index 00000000..9571056e --- /dev/null +++ b/pages/soundtrack/edit.go @@ -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(`
`) + b.WriteString(`
`) + b.WriteString(`

`) + b.WriteString(title) + b.WriteString(`

`) + + // 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("
") + b.WriteString("
") + return b.String() +} diff --git a/pages/soundtrack/soundtrack.go b/pages/soundtrack/soundtrack.go index f1f13266..86adaa19 100644 --- a/pages/soundtrack/soundtrack.go +++ b/pages/soundtrack/soundtrack.go @@ -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", diff --git a/pages/soundtrack/soundtrack.pixy b/pages/soundtrack/soundtrack.pixy index 37e9237c..99bf4654 100644 --- a/pages/soundtrack/soundtrack.pixy +++ b/pages/soundtrack/soundtrack.pixy @@ -1,5 +1,8 @@ component Track(track *arn.SoundTrack) - h1= track.Media[0].Title + h1= track.Title .sound-tracks - SoundTrackAllMedia(track) \ No newline at end of file + SoundTrackAllMedia(track) + + p + a.ajax(href=track.Link() + "/edit") Edit \ No newline at end of file diff --git a/pages/soundtracks/soundtracks.go b/pages/soundtracks/soundtracks.go index 1d1f6c3b..93c8c7f6 100644 --- a/pages/soundtracks/soundtracks.go +++ b/pages/soundtracks/soundtracks.go @@ -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)) } diff --git a/pages/soundtracks/soundtracks.pixy b/pages/soundtracks/soundtracks.pixy index fb81d56d..82bbdf01 100644 --- a/pages/soundtracks/soundtracks.pixy +++ b/pages/soundtracks/soundtracks.pixy @@ -1,4 +1,4 @@ -component Music(tracks []*arn.SoundTrack) +component SoundTracks(tracks []*arn.SoundTrack) h1 Soundtracks .music-buttons diff --git a/patches/add-draft-index/add-draft-index.go b/patches/add-draft-index/add-draft-index.go new file mode 100644 index 00000000..260f4810 --- /dev/null +++ b/patches/add-draft-index/add-draft-index.go @@ -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.") +} diff --git a/patches/reset-inventories/reset-inventories.go b/patches/reset-inventories/reset-inventories.go index 6ab25c83..5e4e8149 100644 --- a/patches/reset-inventories/reset-inventories.go +++ b/patches/reset-inventories/reset-inventories.go @@ -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()) diff --git a/patches/update-soundtracks/update-soundtracks.go b/patches/update-soundtracks/update-soundtracks.go new file mode 100644 index 00000000..833156c2 --- /dev/null +++ b/patches/update-soundtracks/update-soundtracks.go @@ -0,0 +1,11 @@ +package main + +import ( + "github.com/animenotifier/arn" +) + +func main() { + for track := range arn.MustStreamSoundTracks() { + arn.PanicOnError(track.Save()) + } +} diff --git a/scripts/Actions.ts b/scripts/Actions.ts index bcba55c4..01f413fa 100644 --- a/scripts/Actions.ts +++ b/scripts/Actions.ts @@ -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"] diff --git a/styles/tags.scarlet b/styles/tags.scarlet new file mode 100644 index 00000000..45366e80 --- /dev/null +++ b/styles/tags.scarlet @@ -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 \ No newline at end of file diff --git a/styles/widgets.scarlet b/styles/widgets.scarlet index f60c3534..f21dc066 100644 --- a/styles/widgets.scarlet +++ b/styles/widgets.scarlet @@ -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%