Skip to content
This repository was archived by the owner on Nov 26, 2023. It is now read-only.

Commit b2e4a6f

Browse files
committed
editor
1 parent e61ebd4 commit b2e4a6f

18 files changed

+571
-25
lines changed

package-lock.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"postcss-loader": "^6.2.1",
3737
"postcss-nested": "^5.0.6",
3838
"postcss-preset-env": "^7.3.1",
39+
"prop-types": "^15.7.2",
3940
"react-hot-loader": "^4.13.0",
4041
"react-pan-zoom-element": "^2.0.1",
4142
"run-sequence": "^2.2.1",
@@ -52,6 +53,7 @@
5253
},
5354
"dependencies": {
5455
"@demostf/parser-worker": "0.1.1",
56+
"@demostf/edit": "0.1.1",
5557
"promise-polyfill": "^8.2.1",
5658
"react": "^17.0.2",
5759
"react-dom": "^17.0.2",

src/App.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,12 @@ kbd, pre, samp {
263263
code {
264264
font-family: monospace;
265265
}
266+
267+
p.page-note {
268+
border-bottom: 1px solid #ddd;
269+
margin: -10px -30px 50px;
270+
padding: 15px 30px;
271+
background-color: var(--primary-color-accent);
272+
line-height: 32px;
273+
font-size: 120%;
274+
}

src/App.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ function AppRouter({demoListProvider, demoProvider, user, auth, logoutHandler}:
8383
element={<React.Suspense fallback={<Loading/>}><LoadableApiPage user={user}/></React.Suspense>}/>
8484
<Route path='/viewer/:id' element={<AnalysePageRoute user={user}/>}/>
8585
<Route path='/viewer' element={<AnalysePageRoute user={user}/>}/>
86+
<Route path='/edit' element={<EditPageRoute user={user}/>}/>
8687
<Route path='/:id'
8788
element={<DemoPageRoute demoProvider={demoProvider}/>}/>
8889
<Route path='/' element={<ListPageRoute demoListProvider={demoListProvider}/>}/>
@@ -117,6 +118,14 @@ function AnalysePageRoute({user}: { user: User | null }) {
117118
</React.Suspense>)
118119
}
119120

121+
function EditPageRoute({user}: { user: User | null }) {
122+
const match = useParams();
123+
return (
124+
<React.Suspense fallback={<Loading/>}>
125+
<LoadableEditPage match={match}/>
126+
</React.Suspense>)
127+
}
128+
120129
function DemoPageRoute({demoProvider}: { demoProvider: DemoProvider }) {
121130
const match = useParams();
122131
const location = useLocation();
@@ -131,6 +140,7 @@ const getApiComponent = () => import('./Pages/APIPage');
131140
const getAboutComponent = () => import('./Pages/AboutPage');
132141
const getUploadComponent = () => import('./Pages/UploadPage');
133142
const getAnalyseComponent = () => import('./Pages/AnalysePage');
143+
const getEditComponent = () => import('./Pages/EditPage');
134144

135145
const getLoadable = (loader) => {
136146
return (<React.Suspense fallback={<Loading/>}>
@@ -142,4 +152,5 @@ const LoadableApiPage = React.lazy(getApiComponent);
142152
const LoadableAboutPage = React.lazy(getAboutComponent);
143153
const LoadableUploadPage = React.lazy(getUploadComponent);
144154
const LoadableAnalysePage = React.lazy(getAnalyseComponent);
155+
const LoadableEditPage = React.lazy(getEditComponent);
145156

src/Components/Duration.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import * as React from 'react';
22

3-
function format(input) {
3+
export function formatDuration(input) {
44
if (!input) {
5-
return '-';
5+
return '0:00';
66
}
77
const hours = Math.floor(input / 3600);
88
const minutes = Math.floor((input - (hours * 3600)) / 60);
9-
const seconds = input - (hours * 3600) - (minutes * 60);
9+
const seconds = Math.floor(input - (hours * 3600) - (minutes * 60));
1010

1111
const hourString = (hours < 10) ? "0" + hours : "" + hours;
1212
const minuteString = (minutes < 10) ? "0" + minutes : "" + minutes;
@@ -25,7 +25,7 @@ export interface DurationProps {
2525
}
2626

2727
export function Duration(props: DurationProps) {
28-
const duration = format(props.duration);
28+
const duration = formatDuration(props.duration);
2929
return (
3030
<span className={props.className||''}>{duration}</span>
3131
);

src/Components/Header.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ header {
2323
padding: 0;
2424
float: left;
2525
max-width: 220px;
26+
position: relative;
27+
28+
&.beta {
29+
margin-right: 20px;
30+
31+
&:after {
32+
content: 'beta';
33+
color: var(--highlight-primary);
34+
text-transform: uppercase;
35+
font-size: 12px;
36+
position: absolute;
37+
right: -15px;
38+
top: 2px;
39+
font-weight: bold;
40+
}
41+
}
2642
}
2743

2844
a, a:visited {

src/Components/Header.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,10 @@ export function Header(props: HeaderProps) {
5050
<Link className="pure-menu-link link-analyse"
5151
to="/viewer">VIEWER</Link>
5252
</span>
53+
<span key="edit" className="beta">
54+
<Link className="pure-menu-link link-analyse"
55+
to="/edit">EDITOR</Link>
56+
</span>
5357

5458
{rightMenu}
5559
</header>

src/Components/MultiSlider.css

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
.container {
2+
padding-top: 30px;
3+
display: flex;
4+
height: 35px;
5+
}
6+
7+
.slider {
8+
position: relative;
9+
width: 400px;
10+
}
11+
12+
.slider__track,
13+
.slider__range,
14+
.slider__left-value,
15+
.slider__right-value,
16+
.slider__left-input,
17+
.slider__right-input {
18+
position: absolute;
19+
}
20+
21+
.slider__track,
22+
.slider__range {
23+
border-radius: 3px;
24+
height: 5px;
25+
}
26+
27+
.slider__track {
28+
background-color: #ced4da;
29+
width: 100%;
30+
z-index: 1;
31+
}
32+
33+
.slider__range {
34+
background-color: #9fe5e1;
35+
z-index: 2;
36+
}
37+
38+
.slider__left-value,
39+
.slider__right-value {
40+
font-size: 12px;
41+
margin-top: 20px;
42+
}
43+
44+
.slider__left-input,
45+
.slider__right-input {
46+
font-size: 12px;
47+
margin-top: -36px;
48+
}
49+
50+
51+
.slider__left-input input,
52+
.slider__right-input input {
53+
width: 80px;
54+
}
55+
56+
.slider__left-value, .slider__left-input {
57+
left: 6px;
58+
}
59+
60+
.slider__right-value, .slider__right-input {
61+
right: -4px;
62+
}
63+
64+
/* Removing the default appearance */
65+
.thumb,
66+
.thumb::-webkit-slider-thumb {
67+
-webkit-appearance: none;
68+
-webkit-tap-highlight-color: transparent;
69+
}
70+
71+
.thumb {
72+
pointer-events: none;
73+
position: absolute;
74+
height: 0;
75+
width: 400px;
76+
outline: none;
77+
}
78+
79+
.thumb--left {
80+
z-index: 3;
81+
}
82+
83+
.thumb--right {
84+
z-index: 4;
85+
}
86+
87+
/* For Chrome browsers */
88+
.thumb::-webkit-slider-thumb {
89+
background-color: #f1f5f7;
90+
border: none;
91+
border-radius: 50%;
92+
box-shadow: 0 0 1px 1px #ced4da;
93+
cursor: pointer;
94+
height: 18px;
95+
width: 18px;
96+
margin-top: 4px;
97+
pointer-events: all;
98+
position: relative;
99+
}
100+
101+
/* For Firefox browsers */
102+
.thumb::-moz-range-thumb {
103+
background-color: #f1f5f7;
104+
border: none;
105+
border-radius: 50%;
106+
box-shadow: 0 0 1px 1px #ced4da;
107+
cursor: pointer;
108+
height: 18px;
109+
width: 18px;
110+
margin-top: 4px;
111+
pointer-events: all;
112+
position: relative;
113+
}

src/Components/MultiSlider.tsx

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import React, { useCallback, useEffect, useState, useRef } from "react";
2+
import PropTypes from "prop-types";
3+
import "./MultiSlider.css";
4+
5+
export interface SliderProps {
6+
min: number,
7+
max: number,
8+
onChange: (min: number, max: number) => void,
9+
labelFn?: (value: number) => string,
10+
}
11+
12+
const MultiRangeSlider = ({ min, max, onChange, labelFn }: SliderProps) => {
13+
if (!labelFn) {
14+
labelFn = (_val) => '';
15+
}
16+
const [minVal, setMinVal] = useState<number>(min);
17+
const [maxVal, setMaxVal] = useState<number>(max);
18+
const minValRef = useRef<number>(min);
19+
const maxValRef = useRef<number>(max);
20+
const range = useRef<HTMLInputElement | null>(null);
21+
22+
// Convert to percentage
23+
const getPercent = useCallback(
24+
(value) => Math.round(((value - min) / (max - min)) * 100),
25+
[min, max]
26+
);
27+
28+
// Set width of the range to decrease from the left side
29+
useEffect(() => {
30+
const minPercent = getPercent(minVal);
31+
const maxPercent = getPercent(maxValRef.current);
32+
33+
if (range.current) {
34+
35+
range.current.style.left = `${minPercent}%`;
36+
range.current.style.width = `${maxPercent - minPercent}%`;
37+
}
38+
}, [minVal, getPercent]);
39+
40+
// Set width of the range to decrease from the right side
41+
useEffect(() => {
42+
const minPercent = getPercent(minValRef.current);
43+
const maxPercent = getPercent(maxVal);
44+
45+
if (range.current) {
46+
range.current.style.width = `${maxPercent - minPercent}%`;
47+
}
48+
}, [maxVal, getPercent]);
49+
50+
// Get min and max values when their state changes
51+
useEffect(() => {
52+
onChange(minVal, maxVal);
53+
}, [minVal, maxVal, onChange]);
54+
55+
return (
56+
<span className="container">
57+
<input
58+
type="range"
59+
min={min}
60+
max={max}
61+
value={minVal}
62+
onChange={(event) => {
63+
const value = Math.min(Number(event.target.value), maxVal - 1);
64+
setMinVal(value);
65+
minValRef.current = value;
66+
}}
67+
className="thumb thumb--left"
68+
style={{ zIndex: (minVal > max - 100) ? "5" : undefined }}
69+
/>
70+
<input
71+
type="range"
72+
min={min}
73+
max={max}
74+
value={maxVal}
75+
onChange={(event) => {
76+
const value = Math.max(Number(event.target.value), minVal + 1);
77+
setMaxVal(value);
78+
maxValRef.current = value;
79+
}}
80+
className="thumb thumb--right"
81+
/>
82+
83+
<span className="slider">
84+
<span className="slider__left-input">
85+
<input type="number" value={minVal} onChange={(event) => {
86+
const value = Math.max(Math.min(Number(event.target.value), maxVal - 1), min);
87+
setMinVal(value);
88+
minValRef.current = value;
89+
}}/>
90+
</span>
91+
<span className="slider__right-input">
92+
<input type="number" value={maxVal} onChange={(event) => {
93+
const value = Math.min(Math.max(Number(event.target.value), minVal + 1), max);
94+
setMaxVal(value);
95+
maxValRef.current = value;
96+
}}/>
97+
</span>
98+
<span className="slider__track" />
99+
<span ref={range} className="slider__range" />
100+
<span className="slider__left-value">
101+
{labelFn(minVal)}
102+
</span>
103+
<span className="slider__right-value">
104+
{labelFn(maxVal)}
105+
</span>
106+
</span>
107+
</span>
108+
);
109+
};
110+
111+
MultiRangeSlider.propTypes = {
112+
min: PropTypes.number.isRequired,
113+
max: PropTypes.number.isRequired,
114+
onChange: PropTypes.func.isRequired
115+
};
116+
117+
export default MultiRangeSlider;

0 commit comments

Comments
 (0)