Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 739302c

Browse files
unfinished img
1 parent 8be6f81 commit 739302c

File tree

19 files changed

+468
-30
lines changed

19 files changed

+468
-30
lines changed

‎client/src/Hooks/http.hook.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const useHttp = () => {
2222
if (body) {
2323
body = JSON.stringify(body)
2424
headers['Content-Type'] = 'application/json'
25+
headers['Content-Length'] = String(Number(String(body).length) + 100)
2526
}
2627
/**отправка запроса */
2728
const response = await fetch(url, { method, body, headers })

‎client/src/Hooks/useFetchNotes.hook.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ function useFetchNotes(token) {
1818
*/
1919
async function fetchNotes(url = "", method = "GET", body = null, resCallback = () => { }) {
2020
try {
21-
/**запрос к серверу с определенными параметрами*/
21+
/**запрос к серверу о заметках с определенными параметрами*/
2222
const fetched = await request(`/api/notes${url ? ("/" + url) : ""}`, method, body, { Authorization: `Bearer ${token}` })
2323
resCallback(tryParce(fetched))
2424
} catch (e) { }
2525
}
2626

27+
async function fetchMedia(url = "", method = "GET", body = null, resCallback = () => { }) {
28+
try {
29+
/**запрос к серверу о медиа с определенными параметрами*/
30+
const fetched = await request(`/api/media${url ? ("/" + url) : ""}`, method, body, { Authorization: `Bearer ${token}` })
31+
resCallback(tryParce(fetched))
32+
} catch (e) { }
33+
}
34+
2735
function tryParce(str) {
2836
try {
2937
return JSON.parse(str);
@@ -32,7 +40,7 @@ function useFetchNotes(token) {
3240
}
3341
}
3442

35-
return { loading, fetchNotes, error, clearError }
43+
return { loading, fetchNotes, fetchMedia,error, clearError }
3644
}
3745

3846
export default useFetchNotes

‎client/src/NoteComponents/ModalNoteEdit.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import NotesContext from '../Context/NotesContext'
66
import TextareaAutosize from 'react-textarea-autosize'
77
import Modal, { ModalProps } from "../Shared/Components/Modal/Modal"
88
import Palette from './palette/palette'
9+
import Media from './media/media'
910

1011
/**расчет числа строк */
1112
function calcMaxRows() {
@@ -25,7 +26,7 @@ function calcMaxRows() {
2526
*/
2627
function ModalNoteEdit() {
2728
/**получение контекста */
28-
const { removeNote, changeNoteColor, unsetEditNoteId, editNoteContent, getNoteById, editNoteId } = React.useContext(NotesContext)
29+
const { removeNote, changeNoteColor, unsetEditNoteId, editNoteMedia,editNoteContent, getNoteById, editNoteId } = React.useContext(NotesContext)
2930

3031
/** обьект заметки */
3132
const note = getNoteById(editNoteId)
@@ -76,6 +77,14 @@ function ModalNoteEdit() {
7677
changeNoteColor(editNoteId, color)
7778
}
7879

80+
/**
81+
* Изменение медиа заметки
82+
* @param {*} media
83+
*/
84+
function trySetNoteMedia(media) {
85+
editNoteMedia(editNoteId, media)
86+
}
87+
7988
/**
8089
* удаление
8190
*/
@@ -144,6 +153,14 @@ function ModalNoteEdit() {
144153
disabled={!note}
145154
setColor={tryChangeColor}
146155
></Palette>
156+
<Media
157+
className="btn btn-light mx-1"
158+
style={{ boxShadow: "none" }}
159+
disabled={!note}
160+
mediaList={note ? note.media || [] : []}
161+
setNoteMedia={trySetNoteMedia}
162+
noteId={note ? note.id : null}
163+
></Media>
147164
<button
148165
className="btn btn-light"
149166
style={{ boxShadow: "none" }}
@@ -153,7 +170,7 @@ function ModalNoteEdit() {
153170
</div>
154171
{/**Индикатор номера заметки */}
155172
<div className="mx-auto">
156-
<span style={{ color: "lightgray", fontWeight: "400" }}>{note && note.order}</span>
173+
<span style={{ color: "lightgray", fontWeight: "400" }}>{note && String(note.order)}</span>
157174
</div>
158175
{/**Зактрытие окна */}
159176
<div>

‎client/src/NoteComponents/NoteItem.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ function fixLineBreaks(mdStr) {
1919
*/
2020
function NoteItem({ note }) {
2121
/**Подключение контекста */
22-
const { setEditNoteId, editNoteOrder } = useContext(NotesContext)
22+
const { setEditNoteId, editNoteOrder, getMediaById } = useContext(NotesContext)
2323

2424
const lineClip = 12
25-
const bgColor = note.color
25+
const bgColor = note.color || "#f8f9fa"
26+
const mediaList = note.media ? note.media || [] : []
2627

2728
const footerBtn = {
2829
className: `btn btn-light p-0 text-secondary item-footer-btn`,
@@ -37,6 +38,15 @@ function NoteItem({ note }) {
3738
return (
3839
<div className="p-1" >
3940
<div className="card" style={{ backgroundColor: bgColor }} >
41+
42+
{/**Изображение заметки*/}
43+
{Array.isArray(mediaList) ? (mediaList.map((imgId) => {
44+
const media = getMediaById(imgId)
45+
const src = typeof media === "object" && media && media.data
46+
return (
47+
<img key={imgId} onClick={() => setEditNoteId(note.id)} className="card-img-top" src={src} alt="note img"></img>
48+
)
49+
})) : null}
4050
{/**Заголовок и текст заметки с обработчиками отображения markdown*/}
4151
<div className="card-body" onClick={() => setEditNoteId(note.id)} >
4252
<div
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.media-btn:focus {
2+
box-shadow: 0 0 0 0.2rem rgb(216 217 219 / 50%) !important;
3+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/**
2+
* @file media.js
3+
*/
4+
import React, { useContext } from "react"
5+
import PropTypes from 'prop-types'
6+
import "./media.css"
7+
import NotesContext from "../../Context/NotesContext"
8+
import Modal, { ModalProps } from "../../Shared/Components/Modal/Modal"
9+
10+
const MAX_PAYLOAD_SIZE = 100 * 1024
11+
12+
/**
13+
* компонент палитры
14+
* @param {*} param0
15+
*
16+
*/
17+
function Media({ setNoteMedia, mediaList = [], style, className, disabled, noteId }) {
18+
const { addMedia, removeMedia, getMediaById, getNoteById } = useContext(NotesContext)
19+
20+
const limited = getNoteById(noteId).media.length >= 3
21+
22+
/**хук состояния формы */
23+
const [showForm, setShowForm] = React.useState(false)
24+
25+
/**создание параметров модального окна*/
26+
const modalProps = new ModalProps()
27+
modalProps.isOpen = showForm
28+
modalProps.setOpenState = setShowForm
29+
modalProps.sideClose = true
30+
31+
/**открытие окна */
32+
function open() {
33+
setShowForm(true)
34+
}
35+
36+
/**закрытие окна */
37+
function close() {
38+
setShowForm(false)
39+
}
40+
41+
function encodeImageFileAsURLAndPost(e) {
42+
var file = e.target.files[0]
43+
var reader = new FileReader()
44+
45+
reader.onloadend = function () {
46+
const res = reader.result
47+
if (res.length < MAX_PAYLOAD_SIZE) {
48+
console.log("readed suc", res.length)
49+
const mediaId = addMedia(res, noteId)
50+
Array.isArray(mediaList) ? mediaList.push(mediaId) : (mediaList = [mediaId])
51+
setNoteMedia(mediaList)
52+
} else {
53+
console.error("readed unsuc", res.length)
54+
}
55+
e.target.value = null
56+
}
57+
58+
if (file !== undefined) reader.readAsDataURL(file)
59+
}
60+
61+
function delImg(imgId, index) {
62+
removeMedia(imgId)
63+
mediaList.splice(index, 1)
64+
setNoteMedia(mediaList)
65+
}
66+
67+
return (
68+
<React.Fragment>
69+
{/**Кнопка вызова media */}
70+
<button
71+
disabled={disabled}
72+
className={`btn ${className}`}
73+
style={style}
74+
type="button"
75+
onClick={open}
76+
>
77+
<i className="bi bi-image" ></i>
78+
</button>
79+
80+
{/**Форма media */}
81+
<Modal {...modalProps.bind()} >
82+
<div className="p-1 d-flex flex-row flex-wrap justify-content-center align-items-center">
83+
84+
<div className="form-group container d-flex flex-row flex-wrap mb-0">
85+
{Array.isArray(mediaList) ? (mediaList.map((imgId, index) => {
86+
const media = getMediaById(imgId)
87+
const src = typeof media === "object" && media && media.data
88+
return (
89+
<div className="card p-1 m-1" key={imgId} style={{ position: "relative" }}>
90+
<img style={{ maxWidth: "8em", maxHeight: "8em" }} src={src} alt="note img"></img>
91+
<button
92+
style={{ position: "absolute", bottom: "0", right: "0", lineHeight: "1em", padding: "0.05em" }}
93+
className={`btn btn-danger m-1`}
94+
onClick={() => delImg(imgId, index)}
95+
>&#10007;</button>
96+
</div>
97+
)
98+
})) : null}
99+
</div>
100+
101+
<div className="form-group container d-flex flex-wrap justify-content-between mb-0">
102+
<div className="custom-file mb-0 m-1" style={{ maxWidth: "14em" }}>
103+
<input disabled={limited} onChange={encodeImageFileAsURLAndPost} type="file" className="custom-file-input" id="noteImgFile" accept=".jpg, .jpeg, .png" />
104+
<label className="custom-file-label" htmlFor="noteImgFile">{"Img - 100Kb max"}</label>
105+
</div>
106+
<button
107+
className="btn btn-light m-1"
108+
style={{ boxShadow: "none" }}
109+
onClick={close}
110+
>Close</button>
111+
</div>
112+
113+
</div>
114+
</Modal>
115+
116+
</React.Fragment>
117+
);
118+
}
119+
120+
// Валидация
121+
Media.propTypes = {
122+
setNoteMedia: PropTypes.func,
123+
style: PropTypes.object,
124+
className: PropTypes.string,
125+
}
126+
127+
export default Media;
128+
129+
130+
131+
132+
133+

‎client/src/NoteComponents/palette/palette.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ function Palette({ setColor, style, className, disabled }) {
3232
className={`btn ${className}`}
3333
style={style}
3434
type="button"
35-
id="dropdownMenuButton"
35+
id="dropdownMenuButtonPalette"
3636
data-toggle="dropdown"
3737
aria-haspopup="true"
3838
aria-expanded="false"
3939
>
4040
<i className="bi bi-palette" ></i>
4141
</button>
4242
{/**Форма выбора цвета */}
43-
<div className="dropdown-menu tab-content mt-1" aria-labelledby="dropdownMenuButton">
43+
<div className="dropdown-menu tab-content mt-1" aria-labelledby="dropdownMenuButtonPalette">
4444
<form>
4545
<div className="d-flex flex-row flex-wrap justify-content-center">
4646
{colors.map((color, key) => (

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /