From a4b8a36150fe99e3fea1f41faa6379c6f5d38539 Mon Sep 17 00:00:00 2001 From: ftwpala Date: Sun, 1 Feb 2026 22:22:51 +0100 Subject: [PATCH 1/2] rustla-side implementation of modal image preview and added dev-server starting command for windows machines --- package.json | 3 ++ src/INITIAL_STATE.js | 1 + src/actions/index.js | 8 ++++ src/components/ImagePreviewModal.jsx | 60 ++++++++++++++++++++++++++++ src/components/RoutesWithChat.jsx | 11 ++++- src/css/ImageModal.scss | 45 +++++++++++++++++++++ src/css/main.scss | 9 +++++ src/reducers/ui.js | 6 +++ src/redux/types.js | 1 + 9 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/components/ImagePreviewModal.jsx create mode 100644 src/css/ImageModal.scss diff --git a/package.json b/package.json index 0b879dd8..d94394cd 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,13 @@ }, "scripts": { "clean": "rm -rf public/assets public/index.html", + "clean-w": "rmdir /s /q public\\assets && del /f /q public\\index.html", "build": "npm run clean && npm run build:bundle", + "build-w": "npm run clean-w && npm run build:bundle", "build:bundle": "webpack --progress", "build:production": "npm run --prod build", "dev-server": "npm run build && webpack-dev-server --inline --hot", + "dev-server-w": "npm run build-w && webpack-dev-server --inline --hot", "flow": "flow check", "lint": "eslint webpack.config.js --ext .js --ext .jsx src" }, diff --git a/src/INITIAL_STATE.js b/src/INITIAL_STATE.js index be3541bd..e0ee34f8 100644 --- a/src/INITIAL_STATE.js +++ b/src/INITIAL_STATE.js @@ -13,6 +13,7 @@ export default { chatSize: localStorage ? Number(localStorage.getItem('chatSize')) || 400 : 400, showChat: localStorage ? !(localStorage.getItem('showChat') === 'false') : true, showHeader: true, + imageModalSrc: null, showFooter: true, }, self: { diff --git a/src/actions/index.js b/src/actions/index.js index 26c45c36..7803a371 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -175,6 +175,14 @@ export const showHeader = value => dispatch => { }); }; +export const IMAGE_MODAL_SRC = Symbol('IMAGE_MODAL_SRC'); +export const imageModalSrc = value => dispatch => { + dispatch({ + type: IMAGE_MODAL_SRC, + payload: value, + }); +}; + export const SHOW_FOOTER = Symbol('SHOW_FOOTER'); export const showFooter = value => dispatch => { dispatch({ diff --git a/src/components/ImagePreviewModal.jsx b/src/components/ImagePreviewModal.jsx new file mode 100644 index 00000000..37a4af6b --- /dev/null +++ b/src/components/ImagePreviewModal.jsx @@ -0,0 +1,60 @@ +// @flow + +import React from "react"; +import cs from "classnames"; + +import "../css/ImageModal"; +import { connect } from "react-redux"; +import { imageModalSrc } from "../actions"; + +const ImageModal = ({ dispatch, src, onClose }) => ( +
{ + if (e.key === "Escape") dispatch(imageModalSrc(null)); + }} + > +
{ + dispatch(imageModalSrc(null)); + }} + >
+ +
e.stopPropagation()}> +
+ + + + +
+ + +
+
+); + +export default connect()(ImageModal); diff --git a/src/components/RoutesWithChat.jsx b/src/components/RoutesWithChat.jsx index 107458f7..b0d44bd1 100644 --- a/src/components/RoutesWithChat.jsx +++ b/src/components/RoutesWithChat.jsx @@ -13,6 +13,7 @@ import Header from './Header'; import Footer from './Footer'; import CustomScrollbar from './CustomScrollbar'; +import ImageModal from './ImagePreviewModal'; import '../css/Stream'; @@ -22,7 +23,7 @@ import { showHeader as headerFunc } from '../actions'; -export const RoutesWithChat = ({showHeader, showFooter, setChatSize, showChat, showLeftChat=false, chatClosed, chatSize, headerFunc}) => +export const RoutesWithChat = ({showHeader, showFooter, setChatSize, showChat, showLeftChat=false, chatClosed, chatSize, headerFunc, imageModalSrc}) => { let left = (
@@ -53,6 +54,11 @@ export const RoutesWithChat = ({showHeader, showFooter, setChatSize, showChat, s
showHeader ? headerFunc(false) : headerFunc(true)}>›
+ {imageModalSrc && ( + + )} { @@ -80,6 +86,8 @@ RoutesWithChat.propTypes = { showLeftChat: PropTypes.bool, chatClosed: PropTypes.bool, + imageModalSrc: PropTypes.string, + chatSize: PropTypes.number.isRequired, setChatSize: PropTypes.func.isRequired, @@ -96,6 +104,7 @@ export default compose( showLeftChat: idx(state, _ => _.self.profile.data.left_chat), chatClosed: !state.ui.showChat || !state.self.isLoggedIn, headerClosed: !state.ui.showHeader, + imageModalSrc: state.ui.imageModalSrc, }), { setChatSize, diff --git a/src/css/ImageModal.scss b/src/css/ImageModal.scss new file mode 100644 index 00000000..bebb05d0 --- /dev/null +++ b/src/css/ImageModal.scss @@ -0,0 +1,45 @@ +// modal when image is opened +.image-modal { + position: fixed; + inset: 0; + z-index: 9999; +} + +.image-modal__backdrop { + position: absolute; + inset: 0; + background: rgba(0, 0, 0, 0.8); +} + +.image-modal__content { + height: 100%; + place-items: end; + margin-left: auto; + margin-right: auto; + display: flex; + justify-content: center; + flex-flow: column; + width: max-content; + z-index: 100; + position: relative; +} + +.image-modal__btn { + margin-left: 15px; + cursor: pointer; +} + +.image-modal__toolbar { + margin-bottom: 10px; + button { + span { + font-size: 25px; + } + } +} + +.image-modal img { + max-width: 90vw; + max-height: 90vh; + user-select: none; +} diff --git a/src/css/main.scss b/src/css/main.scss index 52a1df9b..4b8562f5 100644 --- a/src/css/main.scss +++ b/src/css/main.scss @@ -60,6 +60,15 @@ a { } } +.button-orange{ + border: none; + background-color: transparent; + color: $rustle-orange; + &:hover, &:focus { + color: darken($rustle-orange, 20%); + } +} + .form-control, .form-control, .btn-group > .navbar-btn, .input-group-btn > .btn { background-color: #222; color: #fff; diff --git a/src/reducers/ui.js b/src/reducers/ui.js index 92ba5569..93330e95 100644 --- a/src/reducers/ui.js +++ b/src/reducers/ui.js @@ -6,6 +6,7 @@ import { SHOW_CHAT, SHOW_HEADER, SHOW_FOOTER, + IMAGE_MODAL_SRC, } from '../actions'; import { actions } from '../actions/websocket'; @@ -38,6 +39,11 @@ function uiReducer(state = INITIAL_STATE.ui, action) { ...state, showHeader: action.payload, }; + case IMAGE_MODAL_SRC: + return { + ...state, + imageModalSrc: action.payload, + }; case SHOW_FOOTER: return { ...state, diff --git a/src/redux/types.js b/src/redux/types.js index a973a1f4..795b743a 100644 --- a/src/redux/types.js +++ b/src/redux/types.js @@ -51,5 +51,6 @@ export type State = {| +showChat: boolean, +showHeader: boolean, +showFooter: boolean, + +imageModalSrc: string, |} |}; From 6397da3efc42eca95b37d5611e0ecdacc1496d5e Mon Sep 17 00:00:00 2001 From: ftwpala Date: Sun, 1 Feb 2026 22:32:03 +0100 Subject: [PATCH 2/2] fix for some of the buttons not working --- src/components/ImagePreviewModal.jsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/ImagePreviewModal.jsx b/src/components/ImagePreviewModal.jsx index 37a4af6b..8f030667 100644 --- a/src/components/ImagePreviewModal.jsx +++ b/src/components/ImagePreviewModal.jsx @@ -27,9 +27,10 @@ const ImageModal = ({ dispatch, src, onClose }) => (
@@ -44,9 +45,11 @@ const ImageModal = ({ dispatch, src, onClose }) => (