Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

πŸš€πŸŽ¨ ↝ Staking soft re-integration & profile page index/boilerplate completed #21

Merged
merged 7 commits into from
Feb 20, 2023
Merged
4 changes: 2 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"jira-plugin.workingProject": "",
"liveServer.settings.port": 5501,
"solidity.defaultCompiler": "localNodeModule",
"solidity.compileUsingRemoteVersion": "v0.8.17+commit.8df45f5f"
"solidity.defaultCompiler": "localFile",
"solidity.compileUsingRemoteVersion": "v0.8.11+commit.d7f03943"
}
34 changes: 0 additions & 34 deletions README.md

This file was deleted.

94 changes: 92 additions & 2 deletions components/AccountAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import { useSupabaseClient } from "@supabase/auth-helpers-react";
import { Database } from "../utils/database.types";

type Profiles = Database['public']['Tables']['profiles']['Row']
type Profiles = Database['public']['Tables']['profiles']['Row'];

export default function AccountAvatar ({
uid,
Expand Down Expand Up @@ -114,7 +114,7 @@ export function PostCardAvatar ({
}

return (
<div className="${width} rounded-full overflow-hidden">
<div className="${width} rounded-lg overflow-hidden">
{avatarUrl ? (
<img
src={avatarUrl}
Expand All @@ -127,4 +127,94 @@ export function PostCardAvatar ({
)}
</div>
);
}

export function AccountAvatarV1 ({
uid,
url,
size,
onUpload
}: {
uid: string,
url: Profiles['avatar_url']
size: number
onUpload: (url: string) => void
}) {
const supabase = useSupabaseClient<Database>();
const [avatarUrl, setAvatarUrl] = useState<Profiles['avatar_url']>(null);
const [uploading, setUploading] = useState(false);
useEffect(() => {
if (url) downloadImage(url);
}, [url]);

async function downloadImage(path: string) { // Get the avatar url from Supabase for the user (if it exists)
try {
const { data, error } = await supabase.storage.from('avatars').download(path);
if (error) {
throw error;
};
const url = URL.createObjectURL(data);
setAvatarUrl(url);
} catch (error) {
console.log('Error downloading image: ', error)
}
}

const uploadAvatar: React.ChangeEventHandler<HTMLInputElement> = async (event) => {
try {
setUploading(true);
if (!event.target.files || event.target.files.length === 0) { // If there is no file selected
throw new Error('You must select an image to upload');
};

const file = event.target.files[0];
const fileExt = file.name.split('.').pop();
const fileName = `${uid}.${fileExt}`;
const filePath = `${fileName}`;
let { error: uploadError } = await supabase.storage
.from('avatars')
.upload(filePath, file, { upsert: true })
if (uploadError) {
throw uploadError;
};

onUpload(filePath);
} catch (error) {
alert('Error uploading avatar, check console');
console.log(error);
} finally {
setUploading(false);
}
}

return (
<div>
{avatarUrl ? (
<img
src={avatarUrl}
alt='Avatar'
className="avatar image"
style={{ height: size, width: size }}
/>
) : (
<div className="avatar no-image" style={{ height: size, width: size }} />
)}
<div style={{ width: size }}>
<label className="button primary block" htmlFor='single'>
{uploading ? 'Uploading ...': 'Upload'}
</label>
<input
style={{
visibility: 'hidden',
position: 'absolute',
}}
type='file'
id='single'
accept='image/*'
onChange={uploadAvatar}
disabled={uploading} // Disabled once upload button/process clicked/initiated
/>
</div>
</div>
);
}
2 changes: 1 addition & 1 deletion components/Cover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function UserCoverImage ( { url, editable, onChange } ) {
cover: url,
})
.eq('id', session?.user?.id)
.then(({data, error}) => {
.then(({ data, error }) => {
if (error) throw error;
if (data && onChange) { onChange(); };
})
Expand Down
48 changes: 48 additions & 0 deletions components/Generator/Controls.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useState, useEffect } from 'react';

import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Form from 'react-bootstrap/Form';
import Tabs from 'react-bootstrap/Tabs';
import Tab from 'react-bootstrap/Tabs';

import LayerPanel from './Panels/LayerPanel';
import InfoPanel from './Panels/InfoPanel';
import GraphicsPanel from './Panels/GraphicsPanel';

import { useStatePersisted } from './Hooks/use-state-persisted';
import { PlanetEditorState } from './Hooks/use-planet-editor-state';

const tabClasses = 'border-left border-right border-bottom';
const tabStyles = {
paddingTop: '10px',
paddingLeft: '6px',
paddingRight: '6px'
};

export default function Controls ({ planetState }: { planetState: PlanetEditorState }) {
const [tab, setTab] = useStatePersisted('world-gen:active-tab', 'planet-info-tab');
console.log(tab);

return (
<>
<Row>
<Col>
<Form autoComplete='off' data-lpignore="true">
<Tabs id='control-tabs' activeKey={tab} onSelect={setTab} className='nav-fill' transition={false}>
<Tab id='planet-info-tab' eventKey='planet-info-tab' title='Info' className={tabClasses} style={tabStyles} tabIndex="-1" >
<InfoPanel {...{ planetState }} />
</Tab>
<Tab id='layers-tab' eventKey='layers-tab' title='Layers' className={tabClasses} style={{ ...tabStyles, paddingTop: 0, paddingLeft: 0, paddingRight: 0 }} tabIndex="-1">
<LayerPanel {...{ planetState }} />
</Tab>
<Tab id='graphics-tab' eventKey='graphics-tab' title='Graphics' className={tabClasses} style={tabStyles} tabIndex="-1">
<GraphicsPanel {...{ planetState }} />
</Tab>
</Tabs>
</Form>
</Col>
</Row>
</>
);
}
172 changes: 172 additions & 0 deletions components/Generator/FieldEditors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Form from 'react-bootstrap/Form';
import Button from 'react-bootstrap/Button';
import Octicon, { Sync } from '@primer/octicons-react';
import InputGroup from 'react-bootstrap/InputGroup';
import Tooltip from 'rc-tooltip';
import Slider from 'rc-slider';
import { Vector2, Vector3 } from 'three';

import { randomSeed } from './Services/helpers';
import { SliderPicker as ColorSlider } from 'react-color';

const sliderStyle = { height: '24px', };

export function TextBox ( props: { label: string, value: string, onChange: ( value: string ) => void } ) {
return (
<Form.Group as={Col}>
<Form.Label><strong>{props.label}:</strong> {props.value + ''}</Form.Label>
<Form.Control type='text' value={props.value + ''} onChange={handleChange} />
</Form.Group>
);

function handleChange ( e: any ) {
props.onChange && props.onChange( e.target.value );
}
}

export function SeedInput(props: { label?: string, value: string, onChange: (value: string) => void }) {
return (
<Form.Group as={Col}>
<Form.Label><strong>{props.label || 'Seed'}:</strong></Form.Label>
<InputGroup>
<Form.Control type="input" value={props.value + ''} onChange={handleChange} />
<InputGroup.Append>
<Button variant="outline-secondary" title='Randomize' onClick={handleRandomization}>
<Octicon icon={Sync} />
</Button>
</InputGroup.Append>
</InputGroup>
</Form.Group>
);

function handleRandomization() {
props.onChange && props.onChange(randomSeed());
}

function handleChange(e: any) {
props.onChange && props.onChange(e.target.value);
}
}

export function ColorPicker(props: { label: string, value: string, onChange: (value: string) => void }) {

return (
<Form.Group as={Col}>
<Form.Label>{props.label}: {props.value}</Form.Label>
<ColorSlider color={props.value} onChangeComplete={handleChange} />
</Form.Group>
);

function handleChange(e: any) {
props.onChange && props.onChange(e.hex.toUpperCase());
}
}

export function NumberSlider(props: { label: string, min: number, max: number, step: number, value: number, onChange: (value: number) => void }) {
return (
<Form.Group as={Col}>
<Form.Label><strong>{props.label}:</strong> {props.value}</Form.Label>
<Slider min={props.min} max={props.max} defaultValue={props.value} step={props.step} onChange={props.onChange} />
</Form.Group>
);
}

const VECTOR_LABEL_WIDTH = 3;
export function Vector2Slider({ label, min, max, step, value, onChange }: { label: string, min: Vector2 | number, max: Vector2 | number, step?: Vector2 | number, value: Vector2, onChange: (value: Vector2) => void }) {
step = typeof step === 'undefined' ? 1 : step;

let vectorMin = typeof min === 'number' ? new Vector2(min, min) : min;
let vectorMax = typeof max === 'number' ? new Vector2(max, max) : max;
let vectorStep = typeof step === 'number' ? new Vector2(step, step) : step;

return (<Form.Group as={Col}>
<Form.Label className='font-weight-bold mb-0'>{label}:</Form.Label>
<Row>
<Col xs={VECTOR_LABEL_WIDTH}><strong>X:</strong> {value.x}</Col>
<Col className='pl-0'>
<Slider min={vectorMin.x} max={vectorMax.x} defaultValue={value.x} step={vectorStep.x} onChange={handleChange('x')} />
</Col>
</Row>
<Row>
<Col xs={VECTOR_LABEL_WIDTH}><strong>Y:</strong> {value.y}</Col>
<Col className='pl-0'>
<Slider min={vectorMin.y} max={vectorMax.y} defaultValue={value.y} step={vectorStep.y} onChange={handleChange('y')} />
</Col>
</Row>
</Form.Group>);

function handleChange(part: 'x' | 'y') {
return (newValue: number) => {
if (onChange) {
if (part === 'x') {
onChange(new Vector2(newValue, value.y));
} else {
onChange(new Vector2(value.x, newValue));
}
}
}
}
}

export function Vector3Slider({ label, min, max, step, value, onChange }: { label: string, min: Vector3 | number, max: Vector3 | number, step?: Vector3 | number, value: Vector3, onChange: (value: Vector3) => void }) {
step = typeof step === 'undefined' ? 1 : step;

let vectorMin = typeof min === 'number' ? new Vector3(min, min, min) : min;
let vectorMax = typeof max === 'number' ? new Vector3(max, max, max) : max;
let vectorStep = typeof step === 'number' ? new Vector3(step, step, step) : step;

return (<Form.Group as={Col}>
<Form.Label className='font-weight-bold mb-0'>{label}:</Form.Label>
<Row>
<Col xs={VECTOR_LABEL_WIDTH}><strong>X:</strong> {value.x}</Col>
<Col className='pl-0'>
<Slider min={vectorMin.x} max={vectorMax.x} defaultValue={value.x} step={vectorStep.x} onChange={handleChange('x')} />
</Col>
</Row>
<Row>
<Col xs={VECTOR_LABEL_WIDTH}><strong>Y:</strong> {value.y}</Col>
<Col className='pl-0'>
<Slider min={vectorMin.y} max={vectorMax.y} defaultValue={value.y} step={vectorStep.y} onChange={handleChange('y')} />
</Col>
</Row>
<Row>
<Col xs={VECTOR_LABEL_WIDTH}><strong>Z:</strong> {value.z}</Col>
<Col className='pl-0'>
<Slider min={vectorMin.z} max={vectorMax.z} defaultValue={value.z} step={vectorStep.z} onChange={handleChange('z')} />
</Col>
</Row>
</Form.Group>);

function handleChange(part: 'x' | 'y' | 'z') {
return (newValue: number) => {
if (onChange) {
switch (part) {
case 'x':
onChange(new Vector3(newValue, value.y, value.z));
break;
case 'y':
onChange(new Vector3(value.x, newValue, value.z));
break;
case 'z':
onChange(new Vector3(value.x, value.y, newValue));
break;
}
}
}
}
}

export function CheckboxInput(props: { label: string, value: boolean, onChange: (value: boolean) => void }) {

return (
<Form.Group as={Col}>
<Form.Check type='checkbox' label={props.label} checked={props.value} onChange={handleChange} />
</Form.Group>
);

function handleChange(e: any) {
props.onChange && props.onChange(e.target.checked);
}
}
Loading