Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 203 additions & 0 deletions src/components/IFrameWidget/editor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import React, { Component } from 'react';
import styled from 'styled-components';
import { FirebaseDatabaseMutation } from '@react-firebase/database'
import {
TextField,
Button,
Typography,
} from '@material-ui/core';
import type { IFrameWidgetProps } from './types';

type Props = {
id: string;
props: IFrameWidgetProps;
};

const FormGroup = styled.div`
display: flex;
margin-bottom: 1rem;
min-width: 480px;
& > div {
flex-grow: 1;
margin-left: 0.25rem;
}
`
class IFrameWidgetEditor extends Component<Props, IFrameWidgetProps> {
constructor(props) {
super(props);
this.state = this.props.props;
}

render() {
return (
<div>
<Typography variant="h6">
IFrameWidget : {this.props.id}
</Typography>
<FormGroup>
<TextField
type="text"
label="url"
fullWidth
variant="outlined"
onChange={(e) => {
this.setState({ ...this.state, url: e.target.value });
}}
value={this.state.url}
/>
<TextField
type="number"
label="retry time(sec)"
fullWidth
variant="outlined"
onChange={(e) => {
this.setState({ ...this.state, retry_time: parseFloat(e.target.value) });
}}
/>
<TextField
type="number"
label="retry time(sec)"
fullWidth
variant="outlined"
onChange={(e) => {
this.setState({ ...this.state, retry_count: parseInt(e.target.value) });
}}
/>
</FormGroup>
<FormGroup>
<TextField
type="number"
label="width"
fullWidth
variant="outlined"
onChange={(e) => {
this.setState({ ...this.state, width: parseFloat(e.target.value) });
}}
value={this.state.width}
/>
<TextField
type="number"
label="height"
fullWidth
variant="outlined"
onChange={(e) => {
this.setState({ ...this.state, height: parseFloat(e.target.value) });
}}
value={this.state.height}
/>
</FormGroup>
<FormGroup>
<TextField
type="number"
label="position top"
fullWidth
variant="outlined"
onChange={(e) => {
const pos = this.state.position || {};
if (e.target.value !== "") {
const v = parseInt(e.target.value);
if (isNaN(v)) {
delete pos.top;
} else {
pos.top = v;
}
} else {
delete pos.top;
}
this.setState({ ...this.state, position: pos });
}}
value={this.state?.position?.top}
/>
<TextField
type="number"
label="position right"
fullWidth
variant="outlined"
onChange={(e) => {
const pos = this.state.position || {};
if (e.target.value !== "") {
const v = parseInt(e.target.value);
if (isNaN(v)) {
delete pos.right;
} else {
pos.right = v;
}
} else {
delete pos.right;
}
this.setState({ ...this.state, position: pos });
}}
value={this.state.position?.right}
/>
<TextField
type="number"
label="position bottom"
fullWidth
variant="outlined"
onChange={(e) => {
const pos = this.state.position || {};
if (e.target.value !== "") {
const v = parseInt(e.target.value);
if (isNaN(v)) {
delete pos.bottom;
} else {
pos.bottom = v;
}
} else {
delete pos.bottom;
}
this.setState({ ...this.state, position: pos });
}}
value={this.state.position?.bottom}
/>
<TextField
type="number"
label="position left"
fullWidth
variant="outlined"
onChange={(e) => {
const pos = this.state.position || {};
if (e.target.value !== "") {
const v = parseInt(e.target.value);
if (isNaN(v)) {
delete pos.left;
} else {
pos.left = v;
}
} else {
delete pos.left;
}
this.setState({ ...this.state, position: pos });
}}
value={this.state.position?.left}
/>
</FormGroup>

<FirebaseDatabaseMutation
type="set"
path={`/widgets/${this.props.id}/props`}
>
{({ runMutation }) => {
return (
<FormGroup>
<Button
type="button"
color="primary"
variant="contained"
onClick={async (e: any) => {
e.preventDefault();
await runMutation(this.state);
}}
>
Save
</Button>
</FormGroup>
);
}}
</FirebaseDatabaseMutation>
</div>
);
}
}

export { IFrameWidgetEditor };
2 changes: 2 additions & 0 deletions src/components/IFrameWidget/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { IFrameWidget } from './widget';
export { IFrameWidgetEditor } from './editor';
17 changes: 17 additions & 0 deletions src/components/IFrameWidget/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
type Position = {
top?: number; // px
right?: number; // px
bottom?: number; // px
left?: number; // px
};

type IFrameWidgetProps = {
url: string;
retry_time: number;
retry_count: number;
width: number;
height: number;
position?: Position;
}

export type { Position, IFrameWidgetProps };
43 changes: 43 additions & 0 deletions src/components/IFrameWidget/widget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { VFC, useState, CSSProperties } from 'react';
import styled from 'styled-components';
import type { IFrameWidgetProps } from './types';

const IFrameWidget: VFC<IFrameWidgetProps> = ({ url, retry_time, retry_count, width, height, position }) => {
const [count, setCount] = useState(0);

const handleLoaded = () => {
console.log(`iframe: ${url} loaded`);
};

const handleError = (e) => {
console.warn(`iframe: ${url}`, e);
if (count < retry_count) {
setTimeout(() => {
setCount(count + 1);
}, retry_time * 1000);
}
};

const style: CSSProperties = {
position: 'absolute',
};

if (position?.top !== undefined) style.top = position.top;
if (position?.right !== undefined) style.right = position.right;
if (position?.bottom !== undefined) style.bottom = position.bottom;
if (position?.left !== undefined) style.left = position.left;

return (
<iframe
key={count}
src={url}
width={`${width}px`}
height={`${height}px`}
onLoad={handleLoaded}
onError={handleError}
style={style}
/>
);
};

export { IFrameWidget };
2 changes: 2 additions & 0 deletions src/components/Preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { FirebaseDatabaseNode } from '@react-firebase/database';

import { TextWidget } from '@/components/TextWidget';
import { TimeWidget } from '@/components/TimeWidget';
import { IFrameWidget } from '@/components/IFrameWidget';

const Widgets = {
'text': TextWidget,
'time': TimeWidget,
'iframe': IFrameWidget,
};

const Preview: VFC = () => {
Expand Down
2 changes: 2 additions & 0 deletions src/components/admin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ import { auth } from '@/lib/firebase';
import { Signin } from '@/components/admin/signin';
import { TextWidgetEditor } from '@/components/TextWidget';
import { TimeWidgetEditor } from '@/components/TimeWidget';
import { IFrameWidgetEditor } from '@/components/IFrameWidget';

const Editors = {
text: TextWidgetEditor,
time: TimeWidgetEditor,
iframe: IFrameWidgetEditor,
};

const useStyles = makeStyles((theme) => ({
Expand Down