Skip to content

Commit e5578c3

Browse files
authored
Merge pull request #842 from Stremio/feat/library-login-placeholder
Library: Align Guest placeholder with Calendar guest placeholder
2 parents 235d09f + e1e77c9 commit e5578c3

File tree

6 files changed

+231
-85
lines changed

6 files changed

+231
-85
lines changed

images/library_placeholder.png

202 KB
Loading

src/routes/Library/Library.js

+47-53
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ const PropTypes = require('prop-types');
55
const classnames = require('classnames');
66
const NotFound = require('stremio/routes/NotFound');
77
const { useProfile, useNotifications, routesRegexp, useOnScrollToBottom, withCoreSuspender } = require('stremio/common');
8-
const { Button, DelayedRenderer, Chips, Image, MainNavBars, Multiselect, LibItem } = require('stremio/components');
8+
const { DelayedRenderer, Chips, Image, MainNavBars, Multiselect, LibItem } = require('stremio/components');
9+
const { default: Placeholder } = require('./Placeholder');
910
const useLibrary = require('./useLibrary');
1011
const useSelectableInputs = require('./useSelectableInputs');
1112
const styles = require('./styles');
@@ -58,65 +59,58 @@ const Library = ({ model, urlParams, queryParams }) => {
5859
}, [hasNextPage, loadNextPage]);
5960
const onScroll = useOnScrollToBottom(onScrollToBottom, SCROLL_TO_BOTTOM_TRESHOLD);
6061
React.useLayoutEffect(() => {
61-
if (profile.auth !== null && library.selected && library.selected.request.page === 1 && library.catalog.length !== 0 ) {
62+
if (profile.auth !== null && library.selected && library.selected.request.page === 1 && library.catalog.length !== 0) {
6263
scrollContainerRef.current.scrollTop = 0;
6364
}
6465
}, [profile.auth, library.selected]);
6566
return (
6667
<MainNavBars className={styles['library-container']} route={model}>
67-
<div className={styles['library-content']}>
68-
{
69-
model === 'continue_watching' || profile.auth !== null ?
70-
<div className={styles['selectable-inputs-container']}>
71-
<Multiselect {...typeSelect} className={styles['select-input-container']} />
72-
<Chips {...sortChips} className={styles['select-input-container']} />
73-
</div>
74-
:
75-
null
76-
}
77-
{
78-
model === 'library' && profile.auth === null ?
79-
<div className={classnames(styles['message-container'], styles['no-user-message-container'])}>
80-
<Image
81-
className={styles['image']}
82-
src={require('/images/anonymous.png')}
83-
alt={' '}
84-
/>
85-
<div className={styles['message-label']}>Library is only available for logged in users!</div>
86-
<Button className={styles['login-button-container']} href={'#/intro'}>
87-
<div className={styles['label']}>LOG IN</div>
88-
</Button>
89-
</div>
90-
:
91-
library.selected === null ?
92-
<DelayedRenderer delay={500}>
93-
<div className={styles['message-container']}>
94-
<Image
95-
className={styles['image']}
96-
src={require('/images/empty.png')}
97-
alt={' '}
98-
/>
99-
<div className={styles['message-label']}>{model === 'library' ? 'Library' : 'Continue Watching'} not loaded!</div>
100-
</div>
101-
</DelayedRenderer>
102-
:
103-
library.catalog.length === 0 ?
104-
<div className={styles['message-container']}>
105-
<Image
106-
className={styles['image']}
107-
src={require('/images/empty.png')}
108-
alt={' '}
109-
/>
110-
<div className={styles['message-label']}>Empty {model === 'library' ? 'Library' : 'Continue Watching'}</div>
68+
{
69+
profile.auth === null ?
70+
<Placeholder />
71+
: <div className={styles['library-content']}>
72+
{
73+
model === 'continue_watching' ?
74+
<div className={styles['selectable-inputs-container']}>
75+
<Multiselect {...typeSelect} className={styles['select-input-container']} />
76+
<Chips {...sortChips} className={styles['select-input-container']} />
11177
</div>
11278
:
113-
<div ref={scrollContainerRef} className={classnames(styles['meta-items-container'], 'animation-fade-in')} onScroll={onScroll}>
114-
{library.catalog.map((libItem, index) => (
115-
<LibItem {...libItem} notifications={notifications} removable={model === 'library'} key={index} />
116-
))}
117-
</div>
118-
}
119-
</div>
79+
null
80+
}
81+
{
82+
model === 'library' ?
83+
library.selected === null ?
84+
<DelayedRenderer delay={500}>
85+
<div className={styles['message-container']}>
86+
<Image
87+
className={styles['image']}
88+
src={require('/images/empty.png')}
89+
alt={' '}
90+
/>
91+
<div className={styles['message-label']}>{model === 'library' ? 'Library' : 'Continue Watching'} not loaded!</div>
92+
</div>
93+
</DelayedRenderer>
94+
:
95+
library.catalog.length === 0 ?
96+
<div className={styles['message-container']}>
97+
<Image
98+
className={styles['image']}
99+
src={require('/images/empty.png')}
100+
alt={' '}
101+
/>
102+
<div className={styles['message-label']}>Empty {model === 'library' ? 'Library' : 'Continue Watching'}</div>
103+
</div>
104+
:
105+
<div ref={scrollContainerRef} className={classnames(styles['meta-items-container'], 'animation-fade-in')} onScroll={onScroll}>
106+
{library.catalog.map((libItem, index) => (
107+
<LibItem {...libItem} notifications={notifications} removable={model === 'library'} key={index} />
108+
))}
109+
</div>
110+
: null
111+
}
112+
</div>
113+
}
120114
</MainNavBars>
121115
);
122116
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Copyright (C) 2017-2025 Smart code 203358507
2+
3+
@import (reference) '~stremio/common/screen-sizes.less';
4+
5+
.placeholder {
6+
position: relative;
7+
display: flex;
8+
flex-direction: column;
9+
align-items: center;
10+
justify-content: center;
11+
min-height: 100%;
12+
width: 100%;
13+
overflow-y: auto;
14+
15+
.title {
16+
font-size: 1.75rem;
17+
font-weight: 400;
18+
text-align: center;
19+
color: var(--primary-foreground-color);
20+
margin-bottom: 1rem;
21+
opacity: 0.5;
22+
}
23+
24+
.image-container {
25+
padding: 1.5rem 0;
26+
27+
.image {
28+
height: 100%;
29+
max-height: 14rem;
30+
object-fit: contain;
31+
}
32+
}
33+
34+
.overview {
35+
display: flex;
36+
flex-direction: row;
37+
align-items: center;
38+
gap: 4rem;
39+
margin-bottom: 1rem;
40+
41+
.point {
42+
display: flex;
43+
flex-direction: row;
44+
align-items: center;
45+
gap: 1.5rem;
46+
width: 18rem;
47+
48+
.icon {
49+
flex: none;
50+
height: 3.25rem;
51+
width: 3.25rem;
52+
color: var(--primary-foreground-color);
53+
opacity: 0.3;
54+
}
55+
56+
.text {
57+
flex: auto;
58+
font-size: 1.1rem;
59+
font-size: 500;
60+
color: var(--primary-foreground-color);
61+
opacity: 0.9;
62+
}
63+
}
64+
}
65+
66+
.button-container {
67+
margin: 1rem 0;
68+
69+
.button {
70+
display: flex;
71+
justify-content: center;
72+
height: 4rem;
73+
line-height: 4rem;
74+
padding: 0 5rem;
75+
font-size: 1.1rem;
76+
color: var(--primary-foreground-color);
77+
text-align: center;
78+
border-radius: 3.5rem;
79+
background-color: var(--overlay-color);
80+
81+
&:hover {
82+
outline: var(--focus-outline-size) solid var(--primary-foreground-color);
83+
background-color: transparent;
84+
}
85+
}
86+
}
87+
}
88+
89+
@media only screen and (max-width: @xsmall) {
90+
.placeholder {
91+
padding: 1rem 2rem;
92+
93+
.title {
94+
margin-bottom: 0;
95+
}
96+
97+
.image-container {
98+
padding: 1rem;
99+
100+
.image {
101+
max-height: 10rem;
102+
}
103+
}
104+
105+
.button-container {
106+
margin: 1rem 0 0;
107+
}
108+
}
109+
}
110+
111+
@media only screen and (max-width: @minimum) {
112+
.placeholder {
113+
padding: 1rem 2rem;
114+
115+
.overview {
116+
flex-direction: column;
117+
gap: 1rem;
118+
119+
.point {
120+
.text {
121+
font-size: 1rem;
122+
}
123+
}
124+
}
125+
126+
.button-container {
127+
.button {
128+
width: 100%;
129+
}
130+
}
131+
}
132+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (C) 2017-2025 Smart code 203358507
2+
3+
import React from 'react';
4+
import { useTranslation } from 'react-i18next';
5+
import Icon from '@stremio/stremio-icons/react';
6+
import { Button, Image } from 'stremio/components';
7+
import styles from './Placeholder.less';
8+
9+
const Placeholder = () => {
10+
const { t } = useTranslation();
11+
12+
return (
13+
<div className={styles['placeholder']}>
14+
<div className={styles['title']}>
15+
{t('LIBRARY_NOT_LOGGED_IN')}
16+
</div>
17+
<div className={styles['image-container']}>
18+
<Image
19+
className={styles['image']}
20+
src={require('/images/library_placeholder.png')}
21+
alt={' '}
22+
/>
23+
</div>
24+
<div className={styles['overview']}>
25+
<div className={styles['point']}>
26+
<Icon className={styles['icon']} name={'cloud-library'} />
27+
<div className={styles['text']}>
28+
{t('NOT_LOGGED_IN_CLOUD')}
29+
</div>
30+
</div>
31+
<div className={styles['point']}>
32+
<Icon className={styles['icon']} name={'actors'} />
33+
<div className={styles['text']}>
34+
{t('NOT_LOGGED_IN_RECOMMENDATIONS')}
35+
</div>
36+
</div>
37+
</div>
38+
<div className={styles['button-container']}>
39+
<Button className={styles['button']} href={'#/intro?form=login'}>
40+
{t('LOG_IN')}
41+
</Button>
42+
</div>
43+
</div>
44+
);
45+
};
46+
47+
export default Placeholder;
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (C) 2017-2025 Smart code 203358507
2+
3+
import Placeholder from './Placeholder';
4+
5+
export default Placeholder;

src/routes/Library/styles.less

-32
Original file line numberDiff line numberDiff line change
@@ -66,38 +66,6 @@
6666
padding: 4rem;
6767
}
6868

69-
&.no-user-message-container {
70-
.login-button-container {
71-
flex: none;
72-
display: flex;
73-
flex-direction: row;
74-
align-items: center;
75-
justify-content: center;
76-
width: 20rem;
77-
height: 3.5rem;
78-
border-radius: 3.5rem;
79-
padding: 0.5rem 1rem;
80-
margin-bottom: 1rem;
81-
background-color: var(--secondary-accent-color);
82-
83-
&:hover {
84-
outline: var(--focus-outline-size) solid var(--secondary-accent-color);
85-
background-color: transparent;
86-
}
87-
88-
.label {
89-
flex-grow: 0;
90-
flex-shrink: 1;
91-
flex-basis: auto;
92-
max-height: 4.8em;
93-
font-size: 1.2rem;
94-
font-weight: 700;
95-
color: var(--primary-foreground-color);
96-
text-align: center;
97-
}
98-
}
99-
}
100-
10169
.image {
10270
flex: none;
10371
width: 12rem;

0 commit comments

Comments
 (0)