Added cover image upload
This commit is contained in:
parent
22f3a767a8
commit
d583d9d6f9
2
images/covers/.gitignore
vendored
Normal file
2
images/covers/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
@ -30,10 +30,10 @@ component InputSelection(id string, value string, label string, placeholder stri
|
|||||||
each option in options
|
each option in options
|
||||||
option(value=option.Value)= option.Label
|
option(value=option.Value)= option.Label
|
||||||
|
|
||||||
component InputImage(id string, label string)
|
component InputImage(id string, label string, endpoint string)
|
||||||
.widget-section
|
.widget-section
|
||||||
label(for=id)= label + ":"
|
label(for=id)= label + ":"
|
||||||
button.action(data-action="selectFile", data-trigger="click", data-preview-image-id=id + "-preview")
|
button.action(data-action="selectFile", data-trigger="click", data-preview-image-id=id + "-preview", data-endpoint=endpoint)
|
||||||
Icon("upload")
|
Icon("upload")
|
||||||
span Select file
|
span Select file
|
||||||
|
|
||||||
|
@ -190,6 +190,7 @@ func Configure(app *aero.Application) {
|
|||||||
|
|
||||||
// Upload
|
// Upload
|
||||||
app.Post("/api/upload/avatar", upload.Avatar)
|
app.Post("/api/upload/avatar", upload.Avatar)
|
||||||
|
app.Post("/api/upload/cover", upload.Cover)
|
||||||
|
|
||||||
// Admin
|
// Admin
|
||||||
l.Page("/admin", admin.Get)
|
l.Page("/admin", admin.Get)
|
||||||
|
@ -39,7 +39,7 @@ component ProfileHeader(viewUser *arn.User, user *arn.User, uri string)
|
|||||||
|
|
||||||
component ProfileHead(viewUser *arn.User, user *arn.User, uri string)
|
component ProfileHead(viewUser *arn.User, user *arn.User, uri string)
|
||||||
.profile
|
.profile
|
||||||
img.profile-cover.lazy(data-src=viewUser.CoverImageURL(), data-webp="true", alt="Cover image")
|
img.profile-cover.lazy(data-src=viewUser.CoverLink("large"), data-webp="true", alt="Cover image")
|
||||||
|
|
||||||
.profile-image-container.mountable.never-unmount
|
.profile-image-container.mountable.never-unmount
|
||||||
ProfileImage(viewUser)
|
ProfileImage(viewUser)
|
||||||
|
@ -27,7 +27,7 @@ component SettingsPersonal(user *arn.User)
|
|||||||
|
|
||||||
.widget.mountable(data-api="/api/settings/" + user.ID)
|
.widget.mountable(data-api="/api/settings/" + user.ID)
|
||||||
h3.widget-title
|
h3.widget-title
|
||||||
Icon("picture-o")
|
Icon("camera")
|
||||||
span Avatar
|
span Avatar
|
||||||
|
|
||||||
//- .widget-section
|
//- .widget-section
|
||||||
@ -55,16 +55,26 @@ component SettingsPersonal(user *arn.User)
|
|||||||
//- //- File upload
|
//- //- File upload
|
||||||
//- if user.Settings().Avatar.Source == "FileSystem"
|
//- if user.Settings().Avatar.Source == "FileSystem"
|
||||||
|
|
||||||
InputImage("avatar-input", "File")
|
InputImage("avatar-input", "File", "/api/upload/avatar")
|
||||||
|
|
||||||
.profile-image-container.avatar-preview
|
.profile-image-container.avatar-preview
|
||||||
if user.HasAvatar()
|
if user.HasAvatar()
|
||||||
img#avatar-input-preview.profile-image.mountable(src=user.AvatarLink("large"), alt="Profile image", title="Recommended: 560 x 560 | PNG or JPG")
|
img#avatar-input-preview.profile-image.lazy(data-src=user.AvatarLink("large"), data-webp="true", alt="Profile image", title="Recommended: 560 x 560 | PNG or JPG")
|
||||||
else
|
else
|
||||||
img#avatar-input-preview.profile-image.hidden(src=user.AvatarLink("large"), alt="Profile image", title="Recommended: 560 x 560 | PNG or JPG")
|
img#avatar-input-preview.profile-image.hidden(src=user.AvatarLink("large"), alt="Profile image", title="Recommended: 560 x 560 | PNG or JPG")
|
||||||
|
|
||||||
#avatar-input-preview-svg
|
#avatar-input-preview-svg
|
||||||
SVGProfileImage(user)
|
SVGProfileImage(user)
|
||||||
|
|
||||||
|
.widget.mountable(data-api="/api/settings/" + user.ID)
|
||||||
|
h3.widget-title
|
||||||
|
Icon("picture-o")
|
||||||
|
span Cover
|
||||||
|
|
||||||
|
InputImage("cover-input", "File", "/api/upload/cover")
|
||||||
|
|
||||||
|
.cover-preview
|
||||||
|
img#cover-input-preview.profile-cover.lazy(data-src=user.CoverLink("small"), data-webp="true", alt="Cover image")
|
||||||
|
|
||||||
component SettingsNotifications(user *arn.User)
|
component SettingsNotifications(user *arn.User)
|
||||||
SettingsTabs
|
SettingsTabs
|
||||||
@ -237,13 +247,13 @@ component SettingsAccounts(user *arn.User)
|
|||||||
|
|
||||||
ImportLists(user)
|
ImportLists(user)
|
||||||
|
|
||||||
.widget.mountable
|
//- .widget.mountable
|
||||||
h3.widget-title
|
//- h3.widget-title
|
||||||
Icon("upload")
|
//- Icon("upload")
|
||||||
span Export
|
//- span Export
|
||||||
|
|
||||||
.widget-section
|
//- .widget-section
|
||||||
label JSON:
|
//- label JSON:
|
||||||
a.button(href="/api/animelist/" + user.ID)
|
//- a.button(href="/api/animelist/" + user.ID)
|
||||||
Icon("upload")
|
//- Icon("upload")
|
||||||
span Export anime list as JSON
|
//- span Export anime list as JSON
|
@ -16,6 +16,16 @@
|
|||||||
.avatar-preview
|
.avatar-preview
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
|
||||||
|
.cover-preview
|
||||||
|
width 100%
|
||||||
|
height 0
|
||||||
|
padding-top 25%
|
||||||
|
position relative
|
||||||
|
margin 0 auto
|
||||||
|
|
||||||
|
#cover-input-preview
|
||||||
|
border-radius 3px
|
||||||
|
|
||||||
.settings-info-text
|
.settings-info-text
|
||||||
text-align center
|
text-align center
|
||||||
font-size 0.9rem
|
font-size 0.9rem
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/animenotifier/notify.moe/utils"
|
"github.com/animenotifier/notify.moe/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Avatar ...
|
// Avatar handles the avatar upload.
|
||||||
func Avatar(ctx *aero.Context) string {
|
func Avatar(ctx *aero.Context) string {
|
||||||
user := utils.GetUser(ctx)
|
user := utils.GetUser(ctx)
|
||||||
|
|
||||||
|
36
pages/upload/cover.go
Normal file
36
pages/upload/cover.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package upload
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/aerogo/aero"
|
||||||
|
"github.com/animenotifier/notify.moe/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cover handles the cover image upload.
|
||||||
|
func Cover(ctx *aero.Context) string {
|
||||||
|
user := utils.GetUser(ctx)
|
||||||
|
|
||||||
|
if user == nil {
|
||||||
|
return ctx.Error(http.StatusUnauthorized, "Not logged in", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve file from post body
|
||||||
|
data, err := ctx.Request().Body().Bytes()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ctx.Error(http.StatusInternalServerError, "Reading request body failed", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set cover image file
|
||||||
|
err = user.SetCoverBytes(data)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ctx.Error(http.StatusInternalServerError, "Invalid image format", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save cover image information
|
||||||
|
user.Save()
|
||||||
|
|
||||||
|
return "ok"
|
||||||
|
}
|
@ -3,8 +3,11 @@ import { StatusMessage } from "../StatusMessage"
|
|||||||
|
|
||||||
// Select file
|
// Select file
|
||||||
export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
|
export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
|
||||||
let input = document.createElement("input")
|
|
||||||
let preview = document.getElementById(button.dataset.previewImageId) as HTMLImageElement
|
let preview = document.getElementById(button.dataset.previewImageId) as HTMLImageElement
|
||||||
|
let endpoint = button.dataset.endpoint
|
||||||
|
|
||||||
|
// Click on virtual file input element
|
||||||
|
let input = document.createElement("input")
|
||||||
input.setAttribute("type", "file")
|
input.setAttribute("type", "file")
|
||||||
|
|
||||||
input.onchange = () => {
|
input.onchange = () => {
|
||||||
@ -19,22 +22,24 @@ export function selectFile(arn: AnimeNotifier, button: HTMLButtonElement) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
previewImage(file, preview)
|
previewImage(file, endpoint, preview)
|
||||||
uploadFile(file, "/api/upload/avatar", arn)
|
uploadFile(file, endpoint, arn)
|
||||||
}
|
}
|
||||||
|
|
||||||
input.click()
|
input.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preview image
|
// Preview image
|
||||||
function previewImage(file: File, preview: HTMLImageElement) {
|
function previewImage(file: File, endpoint: string, preview: HTMLImageElement) {
|
||||||
let reader = new FileReader()
|
let reader = new FileReader()
|
||||||
|
|
||||||
reader.onloadend = () => {
|
reader.onloadend = () => {
|
||||||
let svgPreview = document.getElementById("avatar-input-preview-svg") as HTMLImageElement
|
if(endpoint === "/api/upload/avatar") {
|
||||||
|
let svgPreview = document.getElementById("avatar-input-preview-svg") as HTMLImageElement
|
||||||
|
|
||||||
if(svgPreview) {
|
if(svgPreview) {
|
||||||
svgPreview.classList.add("hidden")
|
svgPreview.classList.add("hidden")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preview.classList.remove("hidden")
|
preview.classList.remove("hidden")
|
||||||
@ -49,7 +54,7 @@ function uploadFile(file: File, endpoint: string, arn: AnimeNotifier) {
|
|||||||
let reader = new FileReader()
|
let reader = new FileReader()
|
||||||
|
|
||||||
reader.onloadend = async () => {
|
reader.onloadend = async () => {
|
||||||
arn.statusMessage.showInfo("Uploading avatar...", 60000)
|
arn.statusMessage.showInfo("Uploading image...", 60000)
|
||||||
|
|
||||||
let response = await fetch(endpoint, {
|
let response = await fetch(endpoint, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@ -60,13 +65,15 @@ function uploadFile(file: File, endpoint: string, arn: AnimeNotifier) {
|
|||||||
body: reader.result
|
body: reader.result
|
||||||
})
|
})
|
||||||
|
|
||||||
let newURL = await response.text()
|
if(endpoint === "/api/upload/avatar") {
|
||||||
updateSideBarAvatar(newURL)
|
let newURL = await response.text()
|
||||||
|
updateSideBarAvatar(newURL)
|
||||||
|
}
|
||||||
|
|
||||||
if(response.ok) {
|
if(response.ok) {
|
||||||
arn.statusMessage.showInfo("Successfully uploaded your new avatar.")
|
arn.statusMessage.showInfo("Successfully uploaded your new image.")
|
||||||
} else {
|
} else {
|
||||||
arn.statusMessage.showError("Failed uploading your new avatar.")
|
arn.statusMessage.showError("Failed uploading your new image.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user