Compare commits
5 Commits
347791c878
...
673f647001
Author | SHA1 | Date | |
---|---|---|---|
673f647001 | |||
941cd0f5aa | |||
34db6374e1 | |||
b0641dfe40 | |||
6863bdb1c4 |
@ -105,6 +105,11 @@ def users_username(username):
|
||||
if request.method == 'GET': return util.jsonify(users.get(util.get_user(required=False), username))
|
||||
if request.method == 'PUT': return util.jsonify(users.update(util.get_user(), username, request.json))
|
||||
|
||||
@app.route('/users/<username>/tours/<tour>', methods=['PUT'])
|
||||
def users_tour(username, tour):
|
||||
status = request.args.get('status', 'completed')
|
||||
return util.jsonify(users.finish_tour(util.get_user(), username, tour, status))
|
||||
|
||||
@app.route('/users/me/projects', methods=['GET'])
|
||||
def me_projects_route():
|
||||
user = util.get_user()
|
||||
|
@ -13,7 +13,8 @@ def me(user):
|
||||
'avatarUrl': user.get('avatar') and uploads.get_presigned_url('users/{0}/{1}'.format(user['_id'], user['avatar'])),
|
||||
'roles': user.get('roles', []),
|
||||
'groups': user.get('groups', []),
|
||||
'subscriptions': user.get('subscriptions')
|
||||
'subscriptions': user.get('subscriptions'),
|
||||
'finishedTours': user.get('completedTours', []) + user.get('skippedTours', []),
|
||||
}
|
||||
|
||||
def get(user, username):
|
||||
@ -53,6 +54,14 @@ def update(user, username, data):
|
||||
db.users.update({'username': username}, updater)
|
||||
return get(user, data.get('username', username))
|
||||
|
||||
def finish_tour(user, username, tour, status):
|
||||
db = database.get_db()
|
||||
if user['username'] != username:
|
||||
raise util.errors.Forbidden('Not allowed')
|
||||
key = 'completedTours' if status == 'completed' else 'skippedTours'
|
||||
db.users.update_one({'_id': user['_id']}, {'$addToSet': {key: tour}})
|
||||
return {'finishedTour': tour}
|
||||
|
||||
def get_projects(user, id):
|
||||
db = database.get_db()
|
||||
u = db.users.find_one(id, {'username': 1, 'avatar': 1})
|
||||
|
@ -17,6 +17,7 @@
|
||||
"react-confirm": "^0.1.18",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-helmet": "^6.0.0",
|
||||
"react-joyride": "^2.4.0",
|
||||
"react-redux": "^7.2.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "3.4.1",
|
||||
|
@ -12,6 +12,9 @@ export const users = {
|
||||
update(username, data, success, fail) {
|
||||
api.authenticatedRequest('PUT', `/users/${username}`, data, success, fail);
|
||||
},
|
||||
finishTour(username, tour, status, success, fail) {
|
||||
api.authenticatedRequest('PUT', `/users/${username}/tours/${tour}?status=${status}`, null, success, fail)
|
||||
},
|
||||
getMyProjects(success, fail) {
|
||||
store.dispatch(actions.projects.request());
|
||||
api.authenticatedRequest('GET', '/users/me/projects', null, d => success && success(d.projects), fail);
|
||||
|
@ -91,11 +91,16 @@ function App({ user, groups, syncedToDrift, driftReady, onOpenRegister, onCloseA
|
||||
<Divider hidden section />
|
||||
</div>
|
||||
|
||||
<div style={{ background: 'rgb(240,240,240)', padding: '15px 0px' }}>
|
||||
<div style={{ background: 'rgb(240,240,240)', padding: '30px 0px' }}>
|
||||
<Container>
|
||||
<Grid>
|
||||
<Grid.Column computer={8}>
|
||||
<Link to="/"><img alt="Treadl logo" src={logo} style={{ width: '100px', paddingTop: 20, paddingBottom: 20 }} /></Link>
|
||||
<p style={{color: '#888888'}}>© Treadl 2022</p>
|
||||
<p style={{marginTop: 10}}><small>Treadl software is free and open-source. Contributions to the project are always welcome.
|
||||
<br />
|
||||
<Icon name="code" /> <a href="https://git.wilw.dev/seastorm/treadl" target="_blank" rel="noopener noreferrer">Project source homepage</a>
|
||||
</small></p>
|
||||
</Grid.Column>
|
||||
<Grid.Column computer={8} textAlign="right">
|
||||
<div style={{ paddingTop: 40 }}>
|
||||
@ -107,12 +112,7 @@ function App({ user, groups, syncedToDrift, driftReady, onOpenRegister, onCloseA
|
||||
<Icon name='book' />
|
||||
<a href='https://git.wilw.dev/seastorm/treadl/wiki' target='_blank' rel='noopener noreferrer'>Documentation</a>
|
||||
</p>
|
||||
<Divider />
|
||||
<p><small>Treadl software is free and open-source.<br />Contributions to the project are always welcome.</small></p>
|
||||
<p>
|
||||
<Icon name="code" />
|
||||
<a href="https://git.wilw.dev/seastorm/treadl" target="_blank" rel="noopener noreferrer">View source code</a>
|
||||
</p>
|
||||
|
||||
<Divider />
|
||||
<p>
|
||||
<Icon name="file alternate outline" />
|
||||
|
@ -14,11 +14,11 @@ const LinkContainer = styled.span`
|
||||
}
|
||||
`;
|
||||
|
||||
function HelpLink({ text, link, marginTop, marginLeft, marginBottom, style }) {
|
||||
function HelpLink({ className, text, link, marginTop, marginLeft, marginBottom, style }) {
|
||||
if (!link) return null;
|
||||
return (
|
||||
<LinkContainer style={style} marginTop={marginTop} marginLeft={marginLeft} marginBottom={marginBottom}>
|
||||
<a href={link} target='_blank' rel='noopener noreferrer'>
|
||||
<a className={className} href={link} target='_blank' rel='noopener noreferrer'>
|
||||
<span className='emoji'>🪧</span>
|
||||
{text || 'Get help with this page'}
|
||||
</a>
|
||||
|
@ -101,8 +101,8 @@ function NavBar({ user, groups, onOpenLogin, onOpenRegister, isAuthenticated, on
|
||||
<div className='nav-links'>
|
||||
<Popup basic on='focus' open={searchPopupOpen} onOpen={e => openSearchPopup(true)} onClose={e => openSearchPopup(false)}
|
||||
trigger={<SearchBar><input placeholder='Click to search...' value={searchTerm} onChange={e => updateSearchTerm(e.target.value)} onKeyDown={e => e.keyCode === 13 && search()} /></SearchBar>}
|
||||
content={<div style={{width: 300}}>
|
||||
{!searchResults?.users && !searchResults?.groups ?
|
||||
content={<div style={{width: 300}} className='joyride-search'>
|
||||
{!searchResults?.users && !searchResults?.groups ?
|
||||
<small>
|
||||
{searching
|
||||
? <span><Loader size='tiny' inline active style={{marginRight: 10}}/> Searching...</span>
|
||||
|
202
web/src/components/includes/Tour.js
Normal file
202
web/src/components/includes/Tour.js
Normal file
@ -0,0 +1,202 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Joyride from 'react-joyride';
|
||||
import api from '../../api';
|
||||
import actions from '../../actions';
|
||||
|
||||
const tours = {
|
||||
home: [{
|
||||
disableBeacon: true,
|
||||
disableOverlay: false,
|
||||
placement: 'center',
|
||||
target: 'body',
|
||||
title: 'Welcome to Treadl!',
|
||||
content: (<div>
|
||||
<p><strong>Thanks for signing-up 😀. We'd love to quickly show you around your homepage.</strong></p>
|
||||
<p>You can skip this tour if you just want to get on with things.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-projects',
|
||||
title: 'Projects',
|
||||
content: (<div>
|
||||
<p><strong>Treadl contents (patterns, images, files, and more) are stored in projects</strong></p>
|
||||
<p>Your projects will appear in this area. You can think of them like folders on your computer.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-createProject',
|
||||
title: 'Create a new project',
|
||||
content: (<div>
|
||||
<p>Use this button to create a new project. Projects can be public to the community or kept private.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-groups',
|
||||
title: 'Groups',
|
||||
content: (<div>
|
||||
<p><strong>Treadl groups</strong></p>
|
||||
<p>Your group memberships will show here. Groups allow you to talk and share content with other people on Treadl.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-createGroup',
|
||||
title: 'Creating groups',
|
||||
content: (<div>
|
||||
<p><strong>You can create your own groups to build a community</strong></p>
|
||||
<p>People use groups for weaving classes, organisation, community groups, and more.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-help',
|
||||
title: 'One last thing...',
|
||||
content: (<div>
|
||||
<p><strong>Help and support</strong></p>
|
||||
<p>These types of links point to places to get help and support, so please use them if you get stuck!</p>
|
||||
</div>)
|
||||
},
|
||||
],
|
||||
|
||||
pattern: [
|
||||
{
|
||||
disableBeacon: true,
|
||||
disableOverlay: false,
|
||||
placement: 'center',
|
||||
target: 'body',
|
||||
title: 'Welcome to the Treadl pattern editor!',
|
||||
content: (<div>
|
||||
<p><strong>The editor can look a bit daunting at first, and so we'd like to briefly show you how it works.</strong></p>
|
||||
<p>If you already know what you're doing, then feel free to skip this.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-drawdown',
|
||||
placement: 'top',
|
||||
title: 'The drawdown',
|
||||
content: (<div>
|
||||
<p><strong>This is where your pattern is displayed. It updates in real-time.</strong></p>
|
||||
<p>You need to have threads in both your warp and weft, as well as tieups specified, in order for a pattern to show.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-warp',
|
||||
title: 'The warp',
|
||||
content: (<div>
|
||||
<p><strong>Add threads to your warp by selecting a tool (from the sidebar) and clicking and dragging your mouse over this area.</strong></p>
|
||||
<p>Different tools produce different thread patterns.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-warpColourway',
|
||||
title: 'The warp colourway',
|
||||
content: (<div>
|
||||
<p><strong>Add colours to your threads</strong></p>
|
||||
<p>Select the colour tool (from the sidebar) and drag over your warp to change the thread colours.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-weft',
|
||||
title: 'The weft',
|
||||
content: (<div>
|
||||
<p><strong>The weft works in the same way as the warp</strong></p>
|
||||
<p>Drag drawing tools and colour tools over this area to change the thread patterns and colours.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-tieups',
|
||||
title: 'The tieups area',
|
||||
content: (<div>
|
||||
<p><strong>The tieups determine how your warp and weft threads will be linked</strong></p>
|
||||
<p>Select individual tieups by clicking the squares relevant to your pattern.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-threads',
|
||||
title: 'Shafts and treadles',
|
||||
content: (<div>
|
||||
<p><strong>You may need to update the shafts and treadles used by your pattern so that it can be used with your loom</strong></p>
|
||||
<p>Changing these values will update the available threads in your warp and weft.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-pan',
|
||||
title: 'Panning tool',
|
||||
content: (<div>
|
||||
<p><strong>Select this and click-and-drag over your drawdown to move it around</strong></p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-colour',
|
||||
title: 'Colour tool',
|
||||
content: (<div>
|
||||
<p><strong>Select this tool and click-and-drag over your warp and weft to add colours to your threads</strong></p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-straight',
|
||||
title: 'Straight draw tool',
|
||||
placement: 'left',
|
||||
content: (<div>
|
||||
<p><strong>Select this tool and click-and-drag over your warp and weft to add threads in a straight pattern</strong></p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-point',
|
||||
title: 'Point draw tool',
|
||||
placement: 'left',
|
||||
content: (<div>
|
||||
<p><strong>Select this tool and click-and-drag over your warp and weft to add threads in a point pattern</strong></p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-tools',
|
||||
title: 'Rich tooling',
|
||||
placement: 'left',
|
||||
content: (<div>
|
||||
<p><strong>Expand the sections in the toolbox to see what else is possible</strong></p>
|
||||
<p>For example, you can change your pattern's zoom level and view different types of interlacements.</p>
|
||||
</div>)
|
||||
},
|
||||
{
|
||||
target: '.joyride-help',
|
||||
title: 'Help is available',
|
||||
content: (<div>
|
||||
<p><strong>Click this link to view documentation about the editor</strong></p>
|
||||
<p>And you can always reach out to us directly if you're stuck or have questions.</p>
|
||||
</div>)
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function Tour({ id, run }) {
|
||||
const dispatch = useDispatch();
|
||||
const { user } = useSelector(state => {
|
||||
const user = state.users.users.filter(u => state.auth.currentUserId === u._id)[0];
|
||||
return { user };
|
||||
});
|
||||
|
||||
if (!user || user.finishedTours?.indexOf(id) > -1) return null;
|
||||
|
||||
const cb = event => {
|
||||
if (event.type === 'tour:end') {
|
||||
const status = event.status == 'skipped' ? 'skipped' : 'completed';
|
||||
api.users.finishTour(user.username, id, status);
|
||||
const finishedTours = user.finishedTours;
|
||||
finishedTours.push(id);
|
||||
dispatch(actions.users.update(id, { finishedTours }));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Joyride steps={tours[id]} run={run} continuous={true} scrollToFirstStep={true} showSkipButton={true} disableCloseOnEsc={true} locale={{last: 'Finish'}}
|
||||
styles={{
|
||||
options: {
|
||||
primaryColor: '#ed0176'
|
||||
}
|
||||
}}
|
||||
callback={cb}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default Tour;
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Loader, Divider, Button, Message, Container, Segment, Grid, Card, Icon, List } from 'semantic-ui-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
@ -11,8 +11,10 @@ import utils from 'utils/utils.js';
|
||||
import UserChip from 'components/includes/UserChip';
|
||||
import HelpLink from 'components/includes/HelpLink';
|
||||
import ProjectCard from 'components/includes/ProjectCard';
|
||||
import Tour from 'components/includes/Tour';
|
||||
|
||||
function Home({ user, groups, projects, invitations, loadingProjects, onReceiveProjects, onReceiveInvitations, onDismissInvitation, onReceiveGroup, onJoinGroup }) {
|
||||
const [runJoyride, setRunJoyride] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
api.invitations.get(({ invitations, sentInvitations}) => {
|
||||
@ -21,6 +23,8 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
}, [onReceiveInvitations]);
|
||||
useEffect(() => {
|
||||
api.users.getMyProjects(onReceiveProjects);
|
||||
setTimeout(() =>
|
||||
setRunJoyride(true), 2000);
|
||||
}, [onReceiveProjects]);
|
||||
|
||||
const declineInvite = (invite) => {
|
||||
@ -45,6 +49,8 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
|
||||
return (
|
||||
<Container style={{ marginTop: '40px' }}>
|
||||
<Tour id='home' run={runJoyride} />
|
||||
|
||||
<Helmet title='Dashboard' />
|
||||
<Grid stackable>
|
||||
<Grid.Column computer={5}>
|
||||
@ -88,7 +94,7 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
</Card>
|
||||
|
||||
{(groups && groups.length) ?
|
||||
<Card fluid>
|
||||
<Card fluid className='joyride-groups'>
|
||||
<Card.Content>
|
||||
<Card.Header>Your groups</Card.Header>
|
||||
|
||||
@ -103,7 +109,7 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
</List.Item>
|
||||
)}
|
||||
</List>
|
||||
<Button fluid size='small' icon='plus' content='Create a new group' as={Link} to='/groups/new' />
|
||||
<Button className='joyride-createGroup' fluid size='small' icon='plus' content='Create a new group' as={Link} to='/groups/new' />
|
||||
<HelpLink link='https://git.wilw.dev/seastorm/treadl/wiki/Groups' text='Learn more about groups' marginTop/>
|
||||
</Card.Content>
|
||||
</Card>
|
||||
@ -111,13 +117,13 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
<Message>
|
||||
<Message.Header>Groups</Message.Header>
|
||||
<p>Groups enable you to build communities of weavers and makers with similar interests. Create one for your weaving group or class today.</p>
|
||||
<Button as={Link} to='/groups/new' size='small' color='purple' icon='plus' content='Create a group' />
|
||||
<Button className='joyride-createGroup' as={Link} to='/groups/new' size='small' color='purple' icon='plus' content='Create a group' />
|
||||
</Message>
|
||||
}
|
||||
|
||||
</Grid.Column>
|
||||
|
||||
<Grid.Column computer={11}>
|
||||
<Grid.Column computer={11} className='joyride-projects'>
|
||||
{loadingProjects && !projects.length &&
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<h4>Loading your projects...</h4>
|
||||
@ -136,8 +142,8 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
<p>Projects can contain anything - from rough ideas or design experiments through to commissions and exhibitions. Treat them as if they were just weaving-related <span role="img" aria-label="folder">📁</span> folders on your computer.</p>
|
||||
<Divider />
|
||||
<h4>Start by creating a new project. Don't worry, you can keep it private.</h4>
|
||||
<p><HelpLink link='https://git.wilw.dev/seastorm/treadl/wiki/Projects' text='Learn more about projects' marginTop/></p>
|
||||
<Button as={Link} to="/projects/new" color="teal" icon="plus" content="Create a project" />
|
||||
<p><HelpLink className='joyride-help' link='https://git.wilw.dev/seastorm/treadl/wiki/Projects' text='Learn more about projects' marginTop/></p>
|
||||
<Button className='joyride-createProject' as={Link} to="/projects/new" color="teal" icon="plus" content="Create a project" />
|
||||
</Segment>
|
||||
|
||||
</div>
|
||||
@ -145,10 +151,10 @@ function Home({ user, groups, projects, invitations, loadingProjects, onReceiveP
|
||||
|
||||
{projects && projects.length > 0 &&
|
||||
<div>
|
||||
<Button as={Link} to="/projects/new" color='teal' content='Create a project' icon='plus' floated='right'/>
|
||||
<Button className='joyride-createProject' as={Link} to="/projects/new" color='teal' content='Create a project' icon='plus' floated='right'/>
|
||||
<h2><Icon name='book' /> Your projects</h2>
|
||||
<p>Projects contain the patterns and files that make up your creations.
|
||||
<HelpLink link='https://git.wilw.dev/seastorm/treadl/wiki/Projects' text='Learn more about projects' marginLeft/>
|
||||
<HelpLink className='joyride-help' link='https://git.wilw.dev/seastorm/treadl/wiki/Projects' text='Learn more about projects' marginLeft/>
|
||||
</p>
|
||||
<Divider clearing hidden />
|
||||
<Card.Group itemsPerRow={2} stackable>
|
||||
|
@ -7,6 +7,7 @@ import { toast } from 'react-toastify';
|
||||
import styled from 'styled-components';
|
||||
import ElementPan from 'components/includes/ElementPan';
|
||||
import HelpLink from 'components/includes/HelpLink';
|
||||
import Tour from 'components/includes/Tour';
|
||||
|
||||
import Warp from './Warp.js';
|
||||
import Weft from './Weft.js';
|
||||
@ -76,6 +77,7 @@ class Draft extends Component {
|
||||
when={unsaved ? true : false}
|
||||
message='You have unsaved changes. Are you sure you want to leave tnis page?'
|
||||
/>
|
||||
<Tour id='pattern' run={true} />
|
||||
<div style={{display: 'flex'}}>
|
||||
|
||||
<div style={{flex: 1, overflow: 'hidden'}}>
|
||||
@ -101,7 +103,7 @@ class Draft extends Component {
|
||||
</div>
|
||||
|
||||
<div style={{width: 300, marginLeft: 20}}>
|
||||
<HelpLink link='https://git.wilw.dev/seastorm/treadl/wiki/Editing-patterns#using-the-pattern-editor' marginBottom/>
|
||||
<HelpLink className='joyride-help' link='https://git.wilw.dev/seastorm/treadl/wiki/Editing-patterns#using-the-pattern-editor' marginBottom/>
|
||||
<Tools warp={warp} weft={weft} object={this.state} pattern={this.state.pattern} updateObject={this.updateObject} updatePattern={this.updatePattern} saveObject={this.saveObject} baseSize={baseSize} unsaved={unsaved} saving={saving}/>
|
||||
</div>
|
||||
|
||||
|
@ -105,7 +105,7 @@ class Drawdown extends Component {
|
||||
render() {
|
||||
const { warp, weft, baseSize } = this.props;
|
||||
return (
|
||||
<StyledDrawdown ref="drawdown" className="drawdown"
|
||||
<StyledDrawdown ref="drawdown" className="drawdown joyride-drawdown"
|
||||
width={warp.threads * baseSize}
|
||||
height={weft.threads * baseSize}
|
||||
weft={weft} warp={warp} baseSize={baseSize}
|
||||
|
@ -15,7 +15,7 @@ class Tieups extends Component {
|
||||
componentDidMount() {
|
||||
this.paintTieups();
|
||||
}
|
||||
|
||||
|
||||
fillUpTo = (tieups, limit) => {
|
||||
let i = tieups.length;
|
||||
while (i <= limit) {
|
||||
@ -71,7 +71,7 @@ class Tieups extends Component {
|
||||
render() {
|
||||
const { warp, weft, baseSize } = this.props;
|
||||
return (
|
||||
<StyledTieups ref='tieups' className='tieups' width={weft.treadles * baseSize} height= {warp.shafts * baseSize} style={{width: weft.treadles * baseSize, height: warp.shafts * baseSize}} onClick={this.click}/>
|
||||
<StyledTieups ref='tieups' className='tieups joyride-tieups' width={weft.treadles * baseSize} height= {warp.shafts * baseSize} style={{width: weft.treadles * baseSize, height: warp.shafts * baseSize}} onClick={this.click}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class Tools extends Component {
|
||||
render() {
|
||||
const { warp, weft, editor, unsaved, saving } = this.props;
|
||||
return (
|
||||
<div className="pattern-toolbox">
|
||||
<div className="pattern-toolbox joyride-tools">
|
||||
{unsaved &&
|
||||
<Segment attached="top">
|
||||
<Button fluid color="teal" icon="save" content="Save pattern" onClick={() => this.props.saveObject(this.refs.canvas)} loading={saving}/>
|
||||
@ -176,7 +176,7 @@ class Tools extends Component {
|
||||
<small>Name</small>
|
||||
<Input type="text" size="small" fluid style={{ marginBottom: '5px' }} value={this.props.object.name} onChange={this.setName} />
|
||||
<Grid columns={2}>
|
||||
<Grid.Row>
|
||||
<Grid.Row className='joyride-threads'>
|
||||
<Grid.Column>
|
||||
<small>Shafts</small>
|
||||
<Input fluid type="number" value={warp.shafts} onKeyDown={e => false} onChange={this.setShafts} size="mini" />
|
||||
@ -189,13 +189,13 @@ class Tools extends Component {
|
||||
<Grid.Row style={{paddingTop: 0}}>
|
||||
<Grid.Column>
|
||||
<small>Width</small>
|
||||
<Input fluid readOnly value={warp.threading?.length || 0} size="mini"
|
||||
<Input fluid readOnly value={warp.threading?.length || 0} size="mini"
|
||||
action={{icon: 'edit', onClick: this.changeWidth}}
|
||||
/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<small>Height</small>
|
||||
<Input fluid readOnly value={weft.treadling?.length || 0} size="mini"
|
||||
<Input fluid readOnly value={weft.treadling?.length || 0} size="mini"
|
||||
action={{icon: 'edit', onClick: this.changeHeight}}
|
||||
/>
|
||||
</Grid.Column>
|
||||
@ -208,10 +208,10 @@ class Tools extends Component {
|
||||
</Accordion.Title>
|
||||
<Accordion.Content active={this.drawerIsActive('drawing')}>
|
||||
<Button.Group fluid>
|
||||
<Button data-tooltip="Pan (drag to move) pattern" color={this.props.editor.tool === 'pan' && 'blue'} size="tiny" icon onClick={() => this.enableTool('pan')}><Icon name="move" /></Button>
|
||||
<Button data-tooltip="Paint selected colour" color={this.props.editor.tool === 'colour' && 'blue'} size="tiny" icon onClick={() => this.enableTool('colour')}><Icon name="paint brush" /></Button>
|
||||
<Button data-tooltip="Straight draw" color={this.props.editor.tool === 'straight' && 'blue'} size="tiny" icon onClick={() => this.enableTool('straight')}>/ /</Button>
|
||||
<Button data-tooltip="Point draw" color={this.props.editor.tool === 'point' && 'blue'} size="tiny" icon onClick={() => this.enableTool('point')}><Icon name="chevron up" /></Button>
|
||||
<Button className='joyride-pan' data-tooltip="Pan (drag to move) pattern" color={this.props.editor.tool === 'pan' && 'blue'} size="tiny" icon onClick={() => this.enableTool('pan')}><Icon name="move" /></Button>
|
||||
<Button className='joyride-colour' data-tooltip="Paint selected colour" color={this.props.editor.tool === 'colour' && 'blue'} size="tiny" icon onClick={() => this.enableTool('colour')}><Icon name="paint brush" /></Button>
|
||||
<Button className='joyride-straight' data-tooltip="Straight draw" color={this.props.editor.tool === 'straight' && 'blue'} size="tiny" icon onClick={() => this.enableTool('straight')}>/ /</Button>
|
||||
<Button className='joyride-point' data-tooltip="Point draw" color={this.props.editor.tool === 'point' && 'blue'} size="tiny" icon onClick={() => this.enableTool('point')}><Icon name="chevron up" /></Button>
|
||||
</Button.Group>
|
||||
</Accordion.Content>
|
||||
|
||||
|
@ -191,13 +191,13 @@ class Warp extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
const { warp, weft, baseSize } = this.props;
|
||||
return (
|
||||
<StyledWarp treadles={weft.treadles} shafts={warp.shafts} baseSize={baseSize}>
|
||||
<canvas className='warp-colourway' ref="colourway" width={warp.threading.length * baseSize} height={10}
|
||||
<canvas className='warp-colourway joyride-warpColourway' ref="colourway" width={warp.threading.length * baseSize} height={10}
|
||||
style={{
|
||||
position: 'absolute', top: 0, right: 0, height: 10, width: warp.threading.length * baseSize,
|
||||
}}
|
||||
@ -207,7 +207,7 @@ class Warp extends Component {
|
||||
onMouseUp={this.mouseUpColourway}
|
||||
onMouseLeave={this.mouseUpColourway}
|
||||
/>
|
||||
<canvas className='warp-threads' ref="warp" width={warp.threading.length * baseSize} height={warp.shafts * baseSize}
|
||||
<canvas className='warp-threads joyride-warp' ref="warp" width={warp.threading.length * baseSize} height={warp.shafts * baseSize}
|
||||
style={{
|
||||
position: 'absolute', top: 10, right: 0,
|
||||
height: warp.shafts * baseSize,
|
||||
|
@ -207,7 +207,7 @@ class Weft extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
const { warp, weft, baseSize } = this.props;
|
||||
@ -221,7 +221,7 @@ class Weft extends Component {
|
||||
onMouseUp={this.mouseUpColourway}
|
||||
onMouseLeave={this.mouseUpColourway}
|
||||
/>
|
||||
<canvas className='weft-threads' ref="weft" width={weft.treadles * baseSize} height={weft.threads * baseSize}
|
||||
<canvas className='weft-threads joyride-weft' ref="weft" width={weft.treadles * baseSize} height={weft.threads * baseSize}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0, right: 10, height: weft.threads * baseSize, width: weft.treadles * baseSize,
|
||||
|
@ -1190,6 +1190,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@gilbarbara/deep-equal@^0.1.0":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@gilbarbara/deep-equal/-/deep-equal-0.1.1.tgz#91c8f291da6bf7e21cdbfb585fb072d59963acf3"
|
||||
integrity sha512-SjSBspHXlclODLtSoPIQwBhfeBjncC05NlNoFELJ6xZQkyYDJsVCcs7+f+etHR2cYPbHLjnh1C06lQlCbMEWEA==
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
|
||||
@ -3719,6 +3724,11 @@ decode-uri-component@^0.2.0:
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
|
||||
|
||||
deep-diff@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-1.0.2.tgz#afd3d1f749115be965e89c63edc7abb1506b9c26"
|
||||
integrity sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==
|
||||
|
||||
deep-equal@^1.0.1, deep-equal@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a"
|
||||
@ -3736,6 +3746,11 @@ deep-is@~0.1.3:
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
|
||||
|
||||
deepmerge@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
|
||||
integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
|
||||
|
||||
default-gateway@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
||||
@ -5817,6 +5832,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
|
||||
dependencies:
|
||||
is-extglob "^2.1.1"
|
||||
|
||||
is-lite@^0.8.1:
|
||||
version "0.8.1"
|
||||
resolved "https://registry.yarnpkg.com/is-lite/-/is-lite-0.8.1.tgz#a9bd03c90ea723d450c78c991b84f78e7e3126f9"
|
||||
integrity sha512-ekSwuewzOmwFnzzAOWuA5fRFPqOeTrLIL3GWT7hdVVi+oLuD+Rau8gCmkb94vH5hjXc1Q/CfIW/y/td1RrNQIg==
|
||||
|
||||
is-number@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
|
||||
@ -7198,6 +7218,16 @@ neo-async@^2.5.0, neo-async@^2.6.1:
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
||||
|
||||
nested-property@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-1.0.1.tgz#2001105b5c69413411b876bba9b86f4316af613f"
|
||||
integrity sha512-BnBBoo/8bBNRdAnJc7+m79oWk7dXwW1+vCesaEQhfDGVwXGLMvmI4NwYgLTW94R/x+R2s/yr2g/hB/4w/YSAvA==
|
||||
|
||||
nested-property@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-4.0.0.tgz#a67b5a31991e701e03cdbaa6453bc5b1011bb88d"
|
||||
integrity sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==
|
||||
|
||||
next-tick@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
|
||||
@ -7926,7 +7956,7 @@ pnp-webpack-plugin@1.6.4:
|
||||
dependencies:
|
||||
ts-pnp "^1.1.6"
|
||||
|
||||
popper.js@^1.14.4:
|
||||
popper.js@^1.14.4, popper.js@^1.16.0:
|
||||
version "1.16.1"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
|
||||
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
|
||||
@ -8983,6 +9013,18 @@ react-fast-compare@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
|
||||
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
|
||||
|
||||
react-floater@^0.7.3:
|
||||
version "0.7.3"
|
||||
resolved "https://registry.yarnpkg.com/react-floater/-/react-floater-0.7.3.tgz#f57947960682586866ec21540e73c9049ca9f787"
|
||||
integrity sha512-d1wAEph+xRxQ0RJ3woMmYLlZHTaCIsja7Bv6JNo2ezsVUgdMan4CxOR4Do4/xgpmRFfsQMdlygexLAZZypWirw==
|
||||
dependencies:
|
||||
deepmerge "^4.2.2"
|
||||
exenv "^1.2.2"
|
||||
is-lite "^0.8.1"
|
||||
popper.js "^1.16.0"
|
||||
react-proptype-conditional-require "^1.0.4"
|
||||
tree-changes "^0.5.1"
|
||||
|
||||
react-helmet@^6.0.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
|
||||
@ -8993,11 +9035,27 @@ react-helmet@^6.0.0:
|
||||
react-fast-compare "^3.1.1"
|
||||
react-side-effect "^2.1.0"
|
||||
|
||||
react-is@^16.12.0, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0:
|
||||
react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.6.3, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-joyride@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-joyride/-/react-joyride-2.4.0.tgz#273a99fea4804a48155e7cc7bae308dcbc8cb725"
|
||||
integrity sha512-U0uDFspaAEZucsvYpEIEPnoWD0QwTFk06IgIlinmTDPHgoS+V0q16w1+JqHeEKkR8Q79DWEeBIJYMvCJ7jT2EQ==
|
||||
dependencies:
|
||||
deep-diff "^1.0.2"
|
||||
deepmerge "^4.2.2"
|
||||
exenv "^1.2.2"
|
||||
is-lite "^0.8.1"
|
||||
nested-property "^4.0.0"
|
||||
react-floater "^0.7.3"
|
||||
react-is "^16.13.1"
|
||||
scroll "^3.0.1"
|
||||
scrollparent "^2.0.1"
|
||||
tree-changes "^0.9.0"
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
@ -9016,6 +9074,11 @@ react-popper@^1.3.4:
|
||||
typed-styles "^0.0.7"
|
||||
warning "^4.0.2"
|
||||
|
||||
react-proptype-conditional-require@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz#69c2d5741e6df5e08f230f36bbc2944ee1222555"
|
||||
integrity sha1-acLVdB5t9eCPIw82u8KUTuEiJVU=
|
||||
|
||||
react-redux@^7.2.0:
|
||||
version "7.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.1.tgz#8dedf784901014db2feca1ab633864dee68ad985"
|
||||
@ -9670,6 +9733,16 @@ schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6
|
||||
ajv "^6.12.2"
|
||||
ajv-keywords "^3.4.1"
|
||||
|
||||
scroll@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/scroll/-/scroll-3.0.1.tgz#d5afb59fb3592ee3df31c89743e78b39e4cd8a26"
|
||||
integrity sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg==
|
||||
|
||||
scrollparent@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.0.1.tgz#715d5b9cc57760fb22bdccc3befb5bfe06b1a317"
|
||||
integrity sha1-cV1bnMV3YPsivczDvvtb/gaxoxc=
|
||||
|
||||
select-hose@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
|
||||
@ -10602,6 +10675,22 @@ tr46@^1.0.1:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
tree-changes@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/tree-changes/-/tree-changes-0.5.1.tgz#e31cc8a0f56c8c401f0a88243d9165dbea4f570c"
|
||||
integrity sha512-O873xzV2xRZ6N059Mn06QzmGKEE21LlvIPbsk2G+GS9ZX5OCur6PIwuuh0rWpAPvLWQZPj0XObyG27zZyLHUzw==
|
||||
dependencies:
|
||||
deep-diff "^1.0.2"
|
||||
nested-property "1.0.1"
|
||||
|
||||
tree-changes@^0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/tree-changes/-/tree-changes-0.9.0.tgz#5dabc013f0f02d3f7f764596369adb35bf1b208a"
|
||||
integrity sha512-k1lOWtcWfPzCyx45W3KsYkwNGf4DfnVb5VHV8/Shs8pr9bqhzjaIHgAnIyu9mydbYmluOVSgj2gdSOnIp+If3A==
|
||||
dependencies:
|
||||
"@gilbarbara/deep-equal" "^0.1.0"
|
||||
is-lite "^0.8.1"
|
||||
|
||||
ts-pnp@1.1.6:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a"
|
||||
|
Loading…
Reference in New Issue
Block a user