This commit is contained in:
tonyrewin 2023-01-26 08:30:39 +03:00
parent cdb0bab8c3
commit fb6673c3cd
5 changed files with 757 additions and 664 deletions

View File

@ -62,7 +62,7 @@ def upload():
print(request.path) print(request.path)
print(request.form) print(request.form)
print(request.files) print(request.files)
img = request.files['file'] img = request.files['userpic']
if img: if img:
# Perform the file upload # Perform the file upload
filename = secure_filename(img.filename) filename = secure_filename(img.filename)

View File

@ -33,47 +33,49 @@
"vercel-build": "astro build" "vercel-build": "astro build"
}, },
"dependencies": { "dependencies": {
"@connorskees/grass": "^0.12.0",
"mailgun.js": "^8.0.6" "mailgun.js": "^8.0.6"
}, },
"devDependencies": { "devDependencies": {
"@astrojs/solid-js": "^1.2.3", "@astrojs/solid-js": "^1.2.3",
"@astrojs/vercel": "^2.4.0", "@astrojs/vercel": "^2.4.0",
"@babel/core": "^7.20.12", "@babel/core": "^7.20.12",
"@graphql-codegen/cli": "^2.16.3", "@graphql-codegen/cli": "^2.16.4",
"@graphql-codegen/typescript": "^2.8.7", "@graphql-codegen/typescript": "^2.8.7",
"@graphql-codegen/typescript-operations": "^2.5.12", "@graphql-codegen/typescript-operations": "^2.5.12",
"@graphql-codegen/typescript-urql": "^3.7.3", "@graphql-codegen/typescript-urql": "^3.7.3",
"@graphql-codegen/urql-introspection": "^2.2.1", "@graphql-codegen/urql-introspection": "^2.2.1",
"@graphql-tools/url-loader": "^7.16.29", "@graphql-tools/url-loader": "^7.17.3",
"@graphql-typed-document-node/core": "^3.1.1", "@graphql-typed-document-node/core": "^3.1.1",
"@nanostores/router": "^0.8.0", "@nanostores/router": "^0.8.0",
"@nanostores/solid": "^0.3.2", "@nanostores/solid": "^0.3.2",
"@popperjs/core": "^2.11.6", "@popperjs/core": "^2.11.6",
"@solid-primitives/memo": "^1.1.2", "@solid-primitives/memo": "^1.1.3",
"@solid-primitives/storage": "^1.3.3", "@solid-primitives/storage": "^1.3.4",
"@solid-primitives/upload": "^0.0.105", "@solid-primitives/upload": "^0.0.105",
"@types/express": "^4.17.15", "@types/express": "^4.17.15",
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@types/uuid": "^8.3.4", "@types/uuid": "^8.3.4",
"@typescript-eslint/eslint-plugin": "^5.48.0", "@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.0", "@typescript-eslint/parser": "^5.48.2",
"@urql/core": "^3.1.1", "@urql/core": "^3.1.1",
"@urql/devtools": "^2.0.3", "@urql/devtools": "^2.0.3",
"@urql/exchange-graphcache": "^5.0.8", "@urql/exchange-graphcache": "^5.0.8",
"astro": "^1.9.1", "astro": "^1.9.2",
"astro-eslint-parser": "^0.9.3", "astro-eslint-parser": "^0.9.5",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"bootstrap": "^5.2.3", "bootstrap": "^5.2.3",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"cookie": "^0.5.0", "cookie": "^0.5.0",
"cookie-signature": "^1.2.0", "cookie-signature": "^1.2.0",
"cosmiconfig-toml-loader": "^1.0.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^8.31.0", "eslint": "^8.32.0",
"eslint-config-stylelint": "^17.1.0", "eslint-config-stylelint": "^17.1.0",
"eslint-import-resolver-typescript": "^3.5.2", "eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-astro": "^0.21.1", "eslint-plugin-astro": "^0.21.1",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.1.1",
"eslint-plugin-solid": "^0.8.0", "eslint-plugin-solid": "^0.8.0",
"eslint-plugin-sonarjs": "^0.16.0", "eslint-plugin-sonarjs": "^0.16.0",
@ -82,7 +84,7 @@
"graphql-sse": "^1.3.2", "graphql-sse": "^1.3.2",
"graphql-tag": "^2.12.6", "graphql-tag": "^2.12.6",
"graphql-ws": "^5.11.2", "graphql-ws": "^5.11.2",
"hast-util-select": "^5.0.3", "hast-util-select": "^5.0.4",
"husky": "^8.0.3", "husky": "^8.0.3",
"idb": "^7.1.1", "idb": "^7.1.1",
"jest": "^29.3.1", "jest": "^29.3.1",
@ -98,7 +100,7 @@
"orderedmap": "^2.1.0", "orderedmap": "^2.1.0",
"postcss": "^8.4.21", "postcss": "^8.4.21",
"postcss-modules": "5.0.0", "postcss-modules": "5.0.0",
"prettier": "^2.8.2", "prettier": "^2.8.3",
"prettier-eslint": "^15.0.1", "prettier-eslint": "^15.0.1",
"prosemirror-commands": "^1.5.0", "prosemirror-commands": "^1.5.0",
"prosemirror-dropcursor": "^1.6.1", "prosemirror-dropcursor": "^1.6.1",
@ -109,17 +111,17 @@
"prosemirror-keymap": "^1.2.0", "prosemirror-keymap": "^1.2.0",
"prosemirror-markdown": "^1.10.1", "prosemirror-markdown": "^1.10.1",
"prosemirror-menu": "^1.2.1", "prosemirror-menu": "^1.2.1",
"prosemirror-model": "^1.18.3", "prosemirror-model": "^1.19.0",
"prosemirror-schema-list": "^1.2.2", "prosemirror-schema-list": "^1.2.2",
"prosemirror-state": "^1.4.2", "prosemirror-state": "^1.4.2",
"prosemirror-view": "^1.29.1", "prosemirror-view": "^1.30.0",
"rollup": "^2.79.1", "rollup": "^2.79.1",
"rollup-plugin-visualizer": "^5.9.0", "rollup-plugin-visualizer": "^5.9.0",
"sass": "1.32.13", "sass": "1.32.13",
"solid-js": "^1.6.8", "solid-js": "^1.6.9",
"solid-js-form": "^0.1.7", "solid-js-form": "^0.1.8",
"solid-jsx": "^0.9.1", "solid-jsx": "^0.9.1",
"solid-social": "^0.9.5", "solid-social": "^0.9.6",
"solid-utils": "^0.8.1", "solid-utils": "^0.8.1",
"sort-package-json": "^2.1.0", "sort-package-json": "^2.1.0",
"stylelint": "^14.16.1", "stylelint": "^14.16.1",
@ -128,17 +130,17 @@
"stylelint-config-standard-scss": "^6.1.0", "stylelint-config-standard-scss": "^6.1.0",
"stylelint-order": "^5.0.0", "stylelint-order": "^5.0.0",
"stylelint-scss": "^4.3.0", "stylelint-scss": "^4.3.0",
"swiper": "^8.4.5", "swiper": "^8.4.6",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "^4.9.4", "typescript": "^4.9.4",
"undici": "^5.14.0", "undici": "^5.15.1",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"vite": "^3.2.5", "vite": "^3.2.5",
"ws": "^8.12.0", "ws": "^8.12.0",
"y-prosemirror": "^1.2.0", "y-prosemirror": "^1.2.0",
"y-protocols": "^1.0.5", "y-protocols": "^1.0.5",
"y-webrtc": "^10.2.3", "y-webrtc": "^10.2.4",
"yjs": "^13.5.44" "yjs": "^13.5.44"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,14 +7,14 @@ import { For, createSignal, Show, onMount } from 'solid-js'
import { clsx } from 'clsx' import { clsx } from 'clsx'
import styles from './Settings.module.scss' import styles from './Settings.module.scss'
import { useProfileForm } from '../../../context/profile' import { useProfileForm } from '../../../context/profile'
import { createFileUploader } from '@solid-primitives/upload'
import validateUrl from '../../../utils/validateUrl' import validateUrl from '../../../utils/validateUrl'
export const ProfileSettingsPage = (props: PageProps) => { export const ProfileSettingsPage = (props: PageProps) => {
const [addLinkForm, setAddLinkForm] = createSignal<boolean>(false) const [addLinkForm, setAddLinkForm] = createSignal<boolean>(false)
const [incorrectUrl, setIncorrectUrl] = createSignal<boolean>(false) const [incorrectUrl, setIncorrectUrl] = createSignal<boolean>(false)
const { form, updateFormField, submit, slugError } = useProfileForm() const { form, updateFormField, submit, slugError } = useProfileForm()
const handleChangeSocial = (value) => { let updateForm: HTMLFormElement
const handleChangeSocial = (value: string) => {
if (validateUrl(value)) { if (validateUrl(value)) {
updateFormField('links', value) updateFormField('links', value)
setAddLinkForm(false) setAddLinkForm(false)
@ -26,28 +26,30 @@ export const ProfileSettingsPage = (props: PageProps) => {
event.preventDefault() event.preventDefault()
submit(form) submit(form)
} }
let userpicFile: HTMLInputElement
const { files, selectFiles: selectFilesAsync } = createFileUploader({ accept: 'image/*' }) const handleUserpicUpload = async (ev) => {
// TODO: show progress
const handleUpload = () => { try {
selectFilesAsync(async ([{ source, name, size, file }]) => { console.debug('handleUserpicUpload trigger')
const image = { source, name, size, file } const f = ev.target.files[0]
try { if (f) {
const formData = new FormData() const reader = new FileReader()
formData.append('type', file.type) reader.onloadend = () => {
formData.append('name', image.source.split('/').pop()) f.fileData = reader.result
formData.append('ext', image.name.split('.').pop()) const data = new FormData()
// formData.append('data', image.file) data.append('file', f)
const resp = await fetch('/api/upload', { fetch('/api/upload', {
method: 'POST', method: 'POST',
body: formData body: data
}) }).then((resp) => {
const url = await resp.json() resp.json().then((url) => updateFormField('userpic', url))
updateFormField('userpic', url) })
} catch (error) { }
console.error('[upload] error', error) reader.readAsDataURL(f)
} }
}) } catch (error) {
console.error('[upload] error', error)
}
} }
const [hostname, setHostname] = createSignal('new.discours.io') const [hostname, setHostname] = createSignal('new.discours.io')
onMount(() => setHostname(window?.location.host)) onMount(() => setHostname(window?.location.host))
@ -66,12 +68,24 @@ export const ProfileSettingsPage = (props: PageProps) => {
<div class="col-md-10 col-lg-9 col-xl-8"> <div class="col-md-10 col-lg-9 col-xl-8">
<h1>{t('Profile settings')}</h1> <h1>{t('Profile settings')}</h1>
<p class="description">{t('Here you can customize your profile the way you want.')}</p> <p class="description">{t('Here you can customize your profile the way you want.')}</p>
<form onSubmit={handleSubmit}> <form ref={updateForm} onSubmit={handleSubmit} enctype="multipart/form-data">
<h4>{t('Userpic')}</h4> <h4>{t('Userpic')}</h4>
<div class="pretty-form__item"> <div class="pretty-form__item">
<div class={styles.avatarContainer}> <div class={styles.avatarContainer}>
<img class={styles.avatar} src={form.userpic} alt={form.name} /> <img
<input type="button" class={styles.avatarInput} onClick={handleUpload} /> class={styles.avatar}
src={form.userpic}
alt={form.name}
onClick={() => userpicFile.click()}
/>
<input
ref={userpicFile}
type="file"
name="userpic"
value="userpic"
hidden
onChange={handleUserpicUpload}
/>
</div> </div>
</div> </div>
<h4>{t('Name')}</h4> <h4>{t('Name')}</h4>

View File

@ -13,7 +13,10 @@ const excludes = [
'topics', 'topics',
'welcome', 'welcome',
'confirm', 'confirm',
'feed' 'feed',
'api/upload',
'api/feedback',
'api/newsletter'
] ]
const slug = Astro.params.slug?.toString() const slug = Astro.params.slug?.toString()