Added multiple home layouts
continuous-integration/drone/push Build is passing

This commit is contained in:
2024-05-20 22:43:07 +02:00
parent 6bb2d32f8c
commit b58844bc30
22 changed files with 618 additions and 233 deletions
+171 -103
View File
@@ -79,126 +79,141 @@
border: 2px solid $borderColor; border: 2px solid $borderColor;
border-radius: $borderRadius; border-radius: $borderRadius;
position: relative; position: relative;
}
.cover-photo { .cover-photo {
position: relative; position: relative;
height: 350px; height: 350px;
flex: 0 0 350px; flex: 0 0 350px;
margin-bottom: 3px; margin-bottom: 3px;
cursor: pointer; cursor: pointer;
width: 100%;
max-width: 100%;
border-radius: $borderRadius;
box-shadow: #333 5px 5px 5px;
overflow: hidden;
img {
width: 100%; width: 100%;
max-width: 100%; transform: scale(1);
border-radius: $borderRadius; }
box-shadow: #333 5px 5px 5px;
overflow: hidden;
img { &:hover {
width: 100%; img,
transform: scale(1); svg {
} transform: scale(1.05);
&:hover {
img,
svg {
transform: scale(1.05);
}
}
.file-name {
position: absolute;
bottom: 0;
background: white;
width: 100%;
text-align: center;
font-size: 0.8em;
font-style: italic;
line-height: 1.2em;
padding: 0 20px;
}
&.cover-photo--no-img {
//padding-left: calc(350px / 2 - 37.5px);
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
#page-loader {
padding: 9px;
}
svg.no-photos {
width: 75px;
height: 75px;
color: $accentColor;
}
} }
} }
.card-details { .file-name {
flex: 1 1 auto; position: absolute;
margin-left: 25px; bottom: 0;
margin-top: 25px; background: white;
width: 100%;
@media(max-width: 968px) { text-align: center;
margin-left: 0; font-size: 0.8em;
width: 100%; font-style: italic;
max-width: 450px; line-height: 1.2em;
} padding: 0 20px;
.input-element {
margin-bottom: 25px;
.input-error {
visibility: hidden;
position: absolute;
bottom: -1.4em;
left: 25px;
font-size: 11pt;
color: red;
font-style: italic;
}
}
} }
.input-buttons { &.cover-photo--no-img {
//padding-left: calc(350px / 2 - 37.5px);
display: flex; display: flex;
justify-content: space-between; align-items: center;
flex-direction: column;
justify-content: center;
#page-loader {
padding: 9px;
}
svg.no-photos {
width: 75px;
height: 75px;
color: $accentColor;
}
}
}
.card-details {
flex: 1 1 auto;
margin-left: 25px;
margin-top: 25px;
@media(max-width: 968px) {
margin-left: 0;
width: 100%;
max-width: 450px;
}
&.card-details--flex {
flex: 0 0 100%;
display: flex;
align-items: flex-start;
justify-content: center;
}
.card-details-left {
flex: 0 0 50%;
}
.card-details-right {
flex: 0 0 50%;
}
.input-element {
margin-bottom: 25px;
.input-error {
visibility: hidden;
position: absolute;
bottom: -1.4em;
left: 25px;
font-size: 11pt;
color: red;
font-style: italic;
}
}
}
.input-buttons {
display: flex;
justify-content: space-between;
@media(max-width: 968px) {
flex-direction: column;
}
.left-buttons {
display: flex;
button {
margin-right: 15px;
}
@media(max-width: 968px) { @media(max-width: 968px) {
flex-direction: column; justify-content: space-between;
} margin-bottom: 15px;
.left-buttons {
display: flex;
button { button {
margin-right: 15px; margin-right: 0;
}
@media(max-width: 968px) {
justify-content: space-between;
margin-bottom: 15px;
button {
margin-right: 0;
}
} }
} }
}
.right-buttons { .right-buttons {
display: flex; display: flex;
button {
margin-left: 15px;
}
@media(max-width: 968px) {
justify-content: space-between;
margin-bottom: 15px;
button { button {
margin-left: 15px; margin-left: 0;
}
@media(max-width: 968px) {
justify-content: space-between;
margin-bottom: 15px;
button {
margin-left: 0;
}
} }
} }
} }
@@ -239,4 +254,57 @@
font-size: 1rem; font-size: 1rem;
margin-bottom: 15px; margin-bottom: 15px;
} }
}
.pos--rel {
position: relative;
}
.pointer {
cursor: pointer;
}
.pad {
padding: 15px;
}
.bold {
font-weight: bold;
}
.border {
border: 2px solid $borderColor;
}
.border--round {
border-radius: $borderRadius;
}
.inline-block {
display: inline-block;
}
.flex {
display: flex;
align-items: center;
justify-content: center;
}
.flex--vert {
flex-direction: column;
}
.flex--vert-sm {
@media(max-width: 768px) {
flex-direction: column;
}
}
.flex--align-center-sm {
@media(max-width: 768px) {
align-items: center;
}
}
.flex--stretch {
justify-content: space-between;
}
.flex--align-start {
align-items: flex-start;
} }
+5 -5
View File
@@ -15,10 +15,10 @@ import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css'; import '@fontsource/roboto/700.css';
import Keycloak from "./services/authentication/keycloak"; import Keycloak from "./services/authentication/keycloak";
import PortfolioManager from "./pages/portfolio-manager"; import InstanceAlbumsPage from "./pages/instance-albums-page";
import AlbumManager from "./pages/album-manager"; import AlbumPage from "./pages/album-page";
import {InstancesPage} from "./pages/instances-page"; import {InstancesPage} from "./pages/instances-page";
import {NoAccessPage} from "./pages/no-access"; import {NoAccessPage} from "./pages/no-access-page";
import {InstancesProvider} from "./services/instances/instances-context"; import {InstancesProvider} from "./services/instances/instances-context";
import {AdminLayout} from "./layout"; import {AdminLayout} from "./layout";
import {Home} from "@mui/icons-material"; import {Home} from "@mui/icons-material";
@@ -37,8 +37,8 @@ const router = createBrowserRouter(
<Route path="albums/*" element={<Outlet />} handle={{ <Route path="albums/*" element={<Outlet />} handle={{
crumb: (routeData) => <Link to={`/${routeData?.params?.instanceId}/albums`}>albums</Link> crumb: (routeData) => <Link to={`/${routeData?.params?.instanceId}/albums`}>albums</Link>
}}> }}>
<Route index element={<PortfolioManager/>} /> <Route index element={<InstanceAlbumsPage/>} />
<Route path=":albumId" element={<AlbumManager/>} handle={{ <Route path=":albumId" element={<AlbumPage />} handle={{
crumb: (routeData) => <Link to={`/${routeData?.params?.instanceId}/albums/${routeData.params.albumId}`}>{routeData.params.albumId}</Link> crumb: (routeData) => <Link to={`/${routeData?.params?.instanceId}/albums/${routeData.params.albumId}`}>{routeData.params.albumId}</Link>
}}/> }}/>
</Route> </Route>
+1
View File
@@ -7,6 +7,7 @@ export class Instance {
this.title = instance?.title; this.title = instance?.title;
this.subtitle = instance?.subtitle; this.subtitle = instance?.subtitle;
this.coverPhoto = instance?.coverPhoto ? new Photo(instance.coverPhoto) : null; this.coverPhoto = instance?.coverPhoto ? new Photo(instance.coverPhoto) : null;
this.homeLayout = instance?.homeLayout;
this.urls = instance?.urls?.map(u => u) || []; this.urls = instance?.urls?.map(u => u) || [];
} }
} }
@@ -9,10 +9,10 @@ import DragAndDrop from "../components/drag-and-drop/drag-and-drop";
import {Album} from "../models/album"; import {Album} from "../models/album";
import Loader from "../components/Loader"; import Loader from "../components/Loader";
import "./album-manager.scss"; import "./album-page.scss";
import {useInstances} from "../services/instances/use-instances"; import {useInstances} from "../services/instances/use-instances";
function AlbumManager() { function AlbumPage() {
const {state} = useLocation(); const {state} = useLocation();
const {album} = state; // Read values passed on state const {album} = state; // Read values passed on state
const {selectedInstance} = useInstances(); const {selectedInstance} = useInstances();
@@ -299,4 +299,4 @@ function AlbumManager() {
</div>; </div>;
} }
export default AlbumManager; export default AlbumPage;
@@ -13,10 +13,10 @@ import Loader from "../components/Loader";
import {Button, TextField} from "@mui/material"; import {Button, TextField} from "@mui/material";
import {Album} from "../models/album"; import {Album} from "../models/album";
import "./portfolio-manager.scss" import "./instance-albums-page.scss"
import {useInstances} from "../services/instances/use-instances"; import {useInstances} from "../services/instances/use-instances";
function PortfolioManager() { function InstanceAlbumsPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const {selectedInstance} = useInstances(); const {selectedInstance} = useInstances();
@@ -208,4 +208,4 @@ function PortfolioManager() {
</div> </div>
} }
export default PortfolioManager; export default InstanceAlbumsPage;
+105 -83
View File
@@ -6,8 +6,7 @@ import {useAuth} from "../services/authentication/use-auth";
import {useInstances} from "../services/instances/use-instances"; import {useInstances} from "../services/instances/use-instances";
import {Instance} from "../models/instance"; import {Instance} from "../models/instance";
import { import {
AddAPhoto, AddCircle, AddAPhoto, AddCircle, ArrowRightAltOutlined, Edit, RadioButtonChecked, RadioButtonUnchecked, RemoveCircle
ArrowRightAltOutlined, Edit, RemoveCircle
} from "@mui/icons-material"; } from "@mui/icons-material";
import "./instances-page.scss"; import "./instances-page.scss";
@@ -16,12 +15,7 @@ import DragAndDrop from "../components/drag-and-drop/drag-and-drop";
export function InstancesPage() { export function InstancesPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const { const {
instances, instances, createInstance, deleteInstance, updateInstance, uploadCoverPhoto, instanceApiError
createInstance,
deleteInstance,
updateInstance,
uploadCoverPhoto,
instanceApiError
} = useInstances(); } = useInstances();
const [instancesToUpdate, setInstancesToUpdate] = useState(null); const [instancesToUpdate, setInstancesToUpdate] = useState(null);
const {userData} = useAuth(); const {userData} = useAuth();
@@ -59,9 +53,10 @@ export function InstancesPage() {
} }
const instanceHasChanges = (idx) => { const instanceHasChanges = (idx) => {
return (instancesToUpdate[idx].title || "") !== (instances[idx]?.title || "") || return (instancesToUpdate[idx].title || "") !== (instances[idx]?.title || "")
(instancesToUpdate[idx].subtitle || "") !== (instances[idx]?.subtitle || "") || || (instancesToUpdate[idx].subtitle || "") !== (instances[idx]?.subtitle || "")
JSON.stringify(instancesToUpdate[idx].urls) !== JSON.stringify(instances[idx]?.urls); || JSON.stringify(instancesToUpdate[idx].urls) !== JSON.stringify(instances[idx]?.urls)
|| instancesToUpdate[idx].homeLayout !== instances[idx]?.homeLayout;
} }
const handleCreateInstance = async () => { const handleCreateInstance = async () => {
await createInstance(new Instance({ await createInstance(new Instance({
@@ -92,7 +87,20 @@ export function InstancesPage() {
const handleDrop = async (e, idx) => { const handleDrop = async (e, idx) => {
await handleFiles(e, idx) await handleFiles(e, idx)
} }
const handleSelectLayout = (idx, layout) => {
instancesToUpdate[idx].homeLayout = layout;
setInstancesToUpdate([...instancesToUpdate]);
}
const homeLayouts = [{
id: 1,
name: "Layout 1"
}, {
id: 2,
name: "Layout 2"
}, {
id: 3,
name: "Layout 3"
}]
return <div id="instance-selector-page"> return <div id="instance-selector-page">
<div id="page-title"> <div id="page-title">
<div id="left-part"> <div id="left-part">
@@ -120,87 +128,101 @@ export function InstancesPage() {
</>} </>}
</div> </div>
<div id="instance-list"> <div id="instance-list">
{instancesToUpdate?.map((instance, idx) => {instancesToUpdate?.map((instance, idx) => <div
<div className="card-layout instance" key={instance.instanceId}> className="pad flex flex--stretch flex--align-start border border--round instance"
<div key={instance.instanceId}>
className={`${idx} cover-photo ${(!isUploading[idx] && instance.coverPhoto ? "" : "cover-photo--no-img")}`}> <div
<DragAndDrop onDrop={(e) => handleDrop(e, idx)} className={`${idx} cover-photo ${(!isUploading[idx] && instance.coverPhoto ? "" : "cover-photo--no-img")}`}>
onClick={(e) => fileInputRefs.current[idx].click(e)} <DragAndDrop onDrop={(e) => handleDrop(e, idx)}
isLoading={isUploading[idx]}> onClick={(e) => fileInputRefs.current[idx].click(e)}
{!isUploading[idx] && instance.coverPhoto isLoading={isUploading[idx]}>
? <> {!isUploading[idx] && instance.coverPhoto ? <>
<img src={`${instance.coverPhoto.url}?width=450&height=450&fit=cover`} <img src={`${instance.coverPhoto.url}?width=450&height=450&fit=cover`}
alt={instance.coverPhoto.name}/> alt={instance.coverPhoto.name}/>
<div className="btn-edit-photo"><Edit /></div> <div className="btn-edit-photo"><Edit/></div>
</> </> : <AddAPhoto className="no-photos"/>}
: <AddAPhoto className="no-photos"/> </DragAndDrop>
} <input type="file" id={`photosUpload`} ref={(element) => fileInputRefs.current[idx] = element}
</DragAndDrop> accept="image/*"
<input type="file" id={`photosUpload`} ref={(element) => fileInputRefs.current[idx] = element} onChange={(e) => handleFiles(e, idx)}></input>
accept="image/*" </div>
onChange={(e) => handleFiles(e, idx)}></input> <div className="card-details">
</div> <div className="flex flex--align-start flex--vert-sm flex--align-center-sm">
<div className="card-details"> <div className="card-details-left">
<div className="title input-element"> <div className="title input-element">
<TextField fullWidth={true} variant="standard" <TextField fullWidth={true} variant="standard"
value={instance.title} value={instance.title}
placeholder="Title..." placeholder="Title..."
onChange={(e) => handleInstanceTitleChange(e, idx)} onChange={(e) => handleInstanceTitleChange(e, idx)}
/> />
</div> </div>
<div className="description input-element"> <div className="description input-element">
<TextField fullWidth={true} variant="standard" <TextField fullWidth={true} variant="standard"
value={instance.subtitle || ""} value={instance.subtitle || ""}
placeholder="Subtitle..." placeholder="Subtitle..."
onChange={(e) => handleInstanceSubtitleChange(e, idx)} onChange={(e) => handleInstanceSubtitleChange(e, idx)}
/> />
</div> </div>
<div className="url input-element"> <div className="url input-element">
<TextField fullWidth={true} variant="standard" <TextField fullWidth={true} variant="standard"
value={instance.newInstanceUrl || ""} value={instance.newInstanceUrl || ""}
placeholder="https://my-photos.be" placeholder="https://my-photos.be"
onChange={(e) => handleNewInstanceUrlChange(e, idx)} onChange={(e) => handleNewInstanceUrlChange(e, idx)}
InputProps={{ InputProps={{
endAdornment: ( endAdornment: (<InputAdornment position="end">
<InputAdornment position="end">
<IconButton color="warning" <IconButton color="warning"
onClick={(e) => handleAddNewInstanceUrl(e, idx)}> onClick={(e) => handleAddNewInstanceUrl(e, idx)}>
<AddCircle/> <AddCircle/>
</IconButton> </IconButton>
</InputAdornment> </InputAdornment>)
) }}/>
}}/> <div className="instance-links">
<div className="instance-links"> {instance.urls.map(url => <div className="instance-link" key={url}>
{instance.urls.map(url => <div className="instance-link" key={url}> <IconButton color="error" onClick={(e) => handleDeleteUrl(e, idx, url)}>
<IconButton color="error" onClick={(e) => handleDeleteUrl(e, idx, url)}> <RemoveCircle/>
<RemoveCircle/> </IconButton>
</IconButton> <NavLink to={url}>{url}</NavLink>
<NavLink to={url}>{url}</NavLink> </div>)}
</div>)} </div>
</div> </div>
</div> </div>
<div className="input-buttons"> <div className="card-details-right">
<div className="left-buttons"> <div className="flex flex--vert flex--align-start pad">
<Button className="photo-save" variant="contained" color="error" <span className="inline-block bold">Home layout:</span>
onClick={(e) => handleDeleteInstance(e, instance.instanceId)}> <div className="flex flex--vert pad">
Delete {homeLayouts.map(layout =>
</Button> <div key={layout.id} className="flex pointer" onClick={() => handleSelectLayout(idx, layout.id)}>
<Button className="photo-save" variant="contained" color="info" <span>{instance.homeLayout === layout.id ? <RadioButtonChecked/> :
disabled={!instanceHasChanges(idx)} <RadioButtonUnchecked/>}
onClick={() => handleSaveInstance(idx)}> </span>
Save <span> {layout.name}</span>
</Button> </div>
</div> )}
<div className="right-buttons"> </div>
<Button className="photo-save" variant="contained" color="info"
onClick={() => navigate(`/${instance.instanceId}`)}>
Albums <ArrowRightAltOutlined/>
</Button>
</div> </div>
</div> </div>
</div> </div>
<div className="input-buttons">
<div className="left-buttons">
<Button className="photo-save" variant="contained" color="error"
onClick={(e) => handleDeleteInstance(e, instance.instanceId)}>
Delete
</Button>
<Button className="photo-save" variant="contained" color="info"
disabled={!instanceHasChanges(idx)}
onClick={() => handleSaveInstance(idx)}>
Save
</Button>
</div>
<div className="right-buttons">
<Button className="photo-save" variant="contained" color="info"
onClick={() => navigate(`/${instance.instanceId}`)}>
Manage <ArrowRightAltOutlined/>
</Button>
</div>
</div>
</div> </div>
)} </div>)}
</div> </div>
</div>; </div>;
} }
+3 -1
View File
@@ -13,9 +13,11 @@
img { img {
position: relative; position: relative;
} }
.btn-edit-photo { .btn-edit-photo {
display: none; display: none;
} }
&:hover { &:hover {
.btn-edit-photo { .btn-edit-photo {
position: absolute; position: absolute;
@@ -27,6 +29,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(255, 255, 255, 0.2); background-color: rgba(255, 255, 255, 0.2);
svg { svg {
color: white; color: white;
font-size: 48px; font-size: 48px;
@@ -70,5 +73,4 @@
} }
} }
} }
} }
@@ -0,0 +1,20 @@
import {NavLink} from "react-router-dom";
import {ArrowRightAlt} from "@mui/icons-material";
import "./home-layout1.scss";
export function HomeLayout1({instance}) {
return <div id="homeLayout1">
<div className="cover-photo">
<img alt={instance.coverPhoto?.name} src={instance.coverPhoto?.url}/>
</div>
<div className="instance-details">
<div className="box">
<h1>{instance.title}</h1>
<h2>{instance.subtitle}</h2>
<NavLink to="/portfolio" className="goto-website-link">
<span>ENTER</span><ArrowRightAlt/>
</NavLink>
</div>
</div>
</div>;
}
@@ -1,4 +1,4 @@
#home { #homeLayout1 {
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
display: grid; display: grid;
@@ -36,15 +36,17 @@
padding: 60px; padding: 60px;
max-width: 620px; max-width: 620px;
text-align: center; text-align: center;
@media(max-width: 600px) {
padding: 0;
max-width: 90vw;
}
h1 { h1 {
text-align: center; text-align: center;
display: inline-block; display: inline-block;
font-size: 37px; font-size: 37px;
line-height: 1em; line-height: 1em;
margin: 0; margin: 0 0 22px;
margin-bottom: 22px;
//font-family: proxima-nova;
font-weight: 700; font-weight: 700;
font-style: normal; font-style: normal;
text-transform: uppercase; text-transform: uppercase;
@@ -65,29 +67,38 @@
letter-spacing: .28em; letter-spacing: .28em;
line-height: 1.7em; line-height: 1.7em;
color: #333; color: #333;
margin: 0; margin: 0 0 36px;
margin-bottom: 36px;
} }
.goto-website-link { .goto-website-link {
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
white-space: nowrap; white-space: nowrap;
line-height: 1em;
//font-family: proxima-nova; //font-family: proxima-nova;
font-weight: 500;
font-style: normal; font-style: normal;
font-size: 14px;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0; letter-spacing: 0;
text-align: center; text-align: center;
padding: 1em calc(1.44em - 0em) 1em 1.44em; padding: 1em 1.44em;
display: inline-block;
text-decoration: none; text-decoration: none;
background-color: transparent; background-color: transparent;
color: #333; color: #333;
border: 2px solid #333; border: 2px solid #333;
display: inline-block;
height: calc(22px + 2em);
transition: background-color 170ms ease-in-out, color 170ms ease-in-out; transition: background-color 170ms ease-in-out, color 170ms ease-in-out;
//transition: color 170ms ease-in-out, border-color 170ms ease-in-out;
span {
display: inline-block;
vertical-align: top;
line-height: 22px;
font-size: 14px;
font-weight: 500;
}
svg {
margin-left: 5px;
font-size: 22px;
}
&:hover { &:hover {
background-color: black; background-color: black;
@@ -0,0 +1,20 @@
import {NavLink} from "react-router-dom";
import {ArrowRightAlt} from "@mui/icons-material";
import "./home-layout2.scss";
export function HomeLayout2({instance}) {
return <div id="homeLayout2">
<div className="instance-details">
<div className="box">
<h1>{instance.title}</h1>
<h2>{instance.subtitle}</h2>
<NavLink to="/portfolio" className="goto-website-link">
<span>ENTER</span><ArrowRightAlt/>
</NavLink>
</div>
</div>
<div className="cover-photo">
<img alt={instance.coverPhoto?.name} src={instance.coverPhoto?.url}/>
</div>
</div>;
}
@@ -0,0 +1,110 @@
#homeLayout2 {
height: 100vh;
width: 100vw;
display: grid;
grid-template-columns: 1fr 1fr;
@media(max-width: 1200px) {
grid-template-columns: 1fr;
grid-template-rows: 1fr 1fr;
}
.cover-photo {
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
img {
width: 100%;
height: 100%;
object-position: 50% 50%;
object-fit: cover;
}
}
.instance-details {
display: flex;
justify-content: center;
flex-direction: column;
.box {
position: static !important;
transform: none;
margin-left: auto;
margin-right: auto;
padding: 60px;
max-width: 620px;
text-align: center;
@media(max-width: 600px) {
padding: 0;
max-width: 90vw;
}
h1 {
text-align: center;
display: inline-block;
font-size: 37px;
line-height: 1em;
margin: 0 0 22px;
font-weight: 700;
font-style: normal;
text-transform: uppercase;
letter-spacing: .1em;
color: #333;
@media(max-width: 600px) {
font-size: 24px;
}
}
h2 {
//font-family: minion-pro;
font-size: 19px;
font-weight: 400;
font-style: normal;
text-transform: uppercase;
letter-spacing: .28em;
line-height: 1.7em;
color: #333;
margin: 0 0 36px;
}
.goto-website-link {
text-rendering: optimizeLegibility;
white-space: nowrap;
//font-family: proxima-nova;
font-style: normal;
text-transform: uppercase;
letter-spacing: 0;
text-align: center;
padding: 1em 1.44em;
text-decoration: none;
background-color: transparent;
color: #333;
border: 2px solid #333;
display: inline-block;
height: calc(22px + 2em);
transition: background-color 170ms ease-in-out, color 170ms ease-in-out;
span {
display: inline-block;
vertical-align: top;
line-height: 22px;
font-size: 14px;
font-weight: 500;
}
svg {
margin-left: 5px;
font-size: 22px;
}
&:hover {
background-color: black;
color: white;
}
}
}
}
}
@@ -0,0 +1,20 @@
import {NavLink} from "react-router-dom";
import {ArrowRightAlt} from "@mui/icons-material";
import "./home-layout3.scss";
export function HomeLayout3({instance}) {
return <div id="homeLayout3">
<div className="cover-photo">
<img alt={instance.coverPhoto?.name} src={instance.coverPhoto?.url}/>
<div className="instance-details">
<div className="box">
<h1>{instance.title}</h1>
<h2>{instance.subtitle}</h2>
<NavLink to="/portfolio" className="goto-website-link">
<span>ENTER</span><ArrowRightAlt/>
</NavLink>
</div>
</div>
</div>
</div>;
}
@@ -0,0 +1,110 @@
#homeLayout3 {
height: 100vh;
width: 100vw;
.cover-photo {
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
img {
position: absolute;
top: 0;
width: 100%;
height: 100%;
object-position: 50% 50%;
object-fit: cover;
}
}
.instance-details {
margin-top: calc(50vh - 125px);
height: 250px;
width: 100vw;
background-color: white;
display: flex;
justify-content: center;
flex-direction: column;
position: relative;
.box {
position: static !important;
transform: none;
margin-left: auto;
margin-right: auto;
padding: 60px;
max-width: 620px;
text-align: center;
@media(max-width: 600px) {
padding: 0;
max-width: 90vw;
}
h1 {
text-align: center;
display: inline-block;
font-size: 37px;
line-height: 1em;
margin: 0 0 22px;
font-weight: 700;
font-style: normal;
text-transform: uppercase;
letter-spacing: .1em;
color: #333;
@media(max-width: 600px) {
font-size: 24px;
}
}
h2 {
//font-family: minion-pro;
font-size: 19px;
font-weight: 400;
font-style: normal;
text-transform: uppercase;
letter-spacing: .28em;
line-height: 1.7em;
color: #333;
margin: 0 0 36px;
}
.goto-website-link {
text-rendering: optimizeLegibility;
white-space: nowrap;
//font-family: proxima-nova;
font-style: normal;
text-transform: uppercase;
letter-spacing: 0;
text-align: center;
padding: 1em 1.44em;
text-decoration: none;
background-color: transparent;
color: #333;
border: 2px solid #333;
display: inline-block;
height: calc(22px + 2em);
transition: background-color 170ms ease-in-out, color 170ms ease-in-out;
span {
display: inline-block;
vertical-align: top;
line-height: 22px;
font-size: 14px;
font-weight: 500;
}
svg {
margin-left: 5px;
font-size: 22px;
}
&:hover {
background-color: black;
color: white;
}
}
}
}
}
+1
View File
@@ -7,5 +7,6 @@ export class Instance {
this.title = instance?.title; this.title = instance?.title;
this.subtitle = instance?.subtitle; this.subtitle = instance?.subtitle;
this.coverPhoto = instance?.coverPhoto ? new Photo(instance.coverPhoto) : null; this.coverPhoto = instance?.coverPhoto ? new Photo(instance.coverPhoto) : null;
this.homeLayout = instance?.homeLayout;
} }
} }
+6 -6
View File
@@ -30,7 +30,7 @@ export default function AlbumPage() {
dangerouslySetInnerHTML={{__html: selectedAlbum.description.replace(/\n/g, "<br />")}}> dangerouslySetInnerHTML={{__html: selectedAlbum.description.replace(/\n/g, "<br />")}}>
</div>} </div>}
</div> </div>
{selectedAlbum.photos && <div id="photo-list" className="photo-grid-layout"> {selectedAlbum.photos && <div id="photo-list" className="photo-grid-layout photo-grid-layout--no-details">
{selectedAlbum.photos.map((photo, idx) => {selectedAlbum.photos.map((photo, idx) =>
<div className="photo grid-cell" key={photo.photoId} <div className="photo grid-cell" key={photo.photoId}
onClick={() => setSelectedPhotoIndex(idx)}> onClick={() => setSelectedPhotoIndex(idx)}>
@@ -41,11 +41,11 @@ export default function AlbumPage() {
<ZoomOutMapSharp/> <ZoomOutMapSharp/>
</div> </div>
</div> </div>
<div className="details"> {/*<div className="details">*/}
<div className="name"> {/* <div className="name">*/}
{photo.name} {/* {photo.name}*/}
</div> {/* </div>*/}
</div> {/*</div>*/}
</div> </div>
)} )}
</div>} </div>}
+9 -17
View File
@@ -1,23 +1,15 @@
import {useCurrentInstance} from "../../services/current-instance/use-current-instance"; import {useCurrentInstance} from "../../services/current-instance/use-current-instance";
import "./home-page.scss"; import {HomeLayout1} from "../../components/home-layouts/home-layout1";
import {NavLink} from "react-router-dom"; import {HomeLayout2} from "../../components/home-layouts/home-layout2";
import {HomeLayout3} from "../../components/home-layouts/home-layout3";
export function HomePage() { export function HomePage() {
const {instance} = useCurrentInstance(); const {instance} = useCurrentInstance();
return instance && instance.homeLayout === 3
return instance && <div id="home"> ? <HomeLayout3 instance={instance}/>
<div className="cover-photo"> : instance.homeLayout === 2
<img alt={instance.coverPhoto?.name} src={instance.coverPhoto?.url}/> ? <HomeLayout2 instance={instance}/>
</div> : <HomeLayout1 instance={instance}/>
<div className="instance-details"> ;
<div className="box">
<h1>{instance.title}</h1>
<h2>{instance.subtitle}</h2>
<NavLink to="/portfolio" className="goto-website-link">
GO TO WEBSITE
</NavLink>
</div>
</div>
</div>;
} }
+4
View File
@@ -191,6 +191,10 @@ html:has(#photoViewer) {
column-gap: 30px; column-gap: 30px;
margin-bottom: 4em; margin-bottom: 4em;
&.photo-grid-layout--no-details {
row-gap: 30px;
}
//@media (max-width: 1920px) { //@media (max-width: 1920px) {
// grid-template-columns: repeat(4, 1fr); // grid-template-columns: repeat(4, 1fr);
//} //}
+3
View File
@@ -10,6 +10,7 @@ export class Instance {
this.title = instance?.title; this.title = instance?.title;
this.subtitle = instance?.subtitle; this.subtitle = instance?.subtitle;
this.coverPhoto = instance?.coverPhoto ? new Photo(instance?.coverPhoto) : null; this.coverPhoto = instance?.coverPhoto ? new Photo(instance?.coverPhoto) : null;
this.homeLayout = instance?.homeLayout;
this.urls = instance?.urls || []; this.urls = instance?.urls || [];
} }
@@ -23,6 +24,8 @@ export class Instance {
subtitle; subtitle;
/** @type {Photo} **/ /** @type {Photo} **/
coverPhoto; coverPhoto;
/** @type {Number} **/
homeLayout;
/** @type {string[]} **/ /** @type {string[]} **/
urls; urls;
} }
+1
View File
@@ -38,6 +38,7 @@ class InstancesService {
instance.title = instanceToUpdate.title; instance.title = instanceToUpdate.title;
instance.subtitle = instanceToUpdate.subtitle; instance.subtitle = instanceToUpdate.subtitle;
instance.urls = instanceToUpdate.urls; instance.urls = instanceToUpdate.urls;
instance.homeLayout = instanceToUpdate.homeLayout;
try { try {
await db.instances.update(instance); await db.instances.update(instance);