Development assistant for gatsby-theme-chronogrove - a GatsbyJS theme with social dashboard widgets, Redux state management, and comprehensive testing.
Expert assistant for developing gatsby-theme-chronogrove, a Gatsby 5 theme powering www.chrisvogt.me with a social dashboard home page and blog.
This is a Yarn v4 workspace monorepo:
```bash
yarn install
yarn develop
yarn test
yarn test:watch
yarn test:coverage
yarn format
yarn lint
yarn workspace gatsby-theme-chronogrove [command]
yarn workspace www.chrisvogt.me [command]
```
Create `.env.development` with:
```
GATSBY_METRICS_API_URL=https://metrics.chrisvogt.me
GATSBY_GITHUB_TOKEN=<optional>
GATSBY_SPOTIFY_CLIENT_ID=<optional>
GATSBY_INSTAGRAM_ACCESS_TOKEN=<optional>
GATSBY_GOODREADS_API_KEY=<optional>
GATSBY_STEAM_API_KEY=<optional>
```
The theme includes a sophisticated widget system for the home page dashboard:
1. **API Calls**: `fetchDataSource.js` with deduplication
2. **Redux Actions**: Dispatch INIT → SUCCESS/FAILURE
3. **Reducers**: Store data with loading states
4. **Selectors**: Transform data for components
5. **Components**: Render with loading/error states
When adding a new widget:
1. **Create component structure**:
```
theme/src/components/widgets/[name]/
├── index.js # Main component
├── [name].js # Widget logic
└── __tests__/
└── [name].test.js # Tests
```
2. **Add Redux state**:
```javascript
// theme/src/state/actions/[name].js
export const fetchWidgetData = () => dispatch => {
dispatch({ type: 'WIDGET_INIT' });
return fetchDataSource('widget-endpoint')
.then(data => dispatch({ type: 'WIDGET_SUCCESS', payload: data }))
.catch(error => dispatch({ type: 'WIDGET_FAILURE', payload: error }));
};
// theme/src/state/reducers/[name].js
const initialState = { data: null, loading: false, error: null };
export default (state = initialState, action) => {
switch (action.type) {
case 'WIDGET_INIT': return { ...state, loading: true };
case 'WIDGET_SUCCESS': return { data: action.payload, loading: false, error: null };
case 'WIDGET_FAILURE': return { ...state, loading: false, error: action.payload };
default: return state;
}
};
```
3. **Create selectors**:
```javascript
// theme/src/state/selectors/[name].js
export const getWidgetData = state => state.widget.data;
export const isWidgetLoading = state => state.widget.loading;
```
4. **Add mock data**:
```javascript
// theme/__mocks__/[name]-data.js
export default { /* mock response */ };
```
5. **Write tests**:
```javascript
// Use React Testing Library + Redux Mock Store
import { render, screen } from '@testing-library/react';
import configureStore from 'redux-mock-store';
import Widget from '../index';
const mockStore = configureStore([]);
test('renders loading state', () => {
const store = mockStore({ widget: { loading: true } });
render(<Provider store={store}><Widget /></Provider>);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
});
```
6. **Update documentation**: Add widget configuration to README
**Current Goal**: Make the theme generic and reusable by moving hardcoded personal information to configuration.
1. **Move hardcoded values to siteMetadata**:
```javascript
// gatsby-config.js
module.exports = {
siteMetadata: {
author: {
name: 'Your Name',
email: '[email protected]',
location: 'City, State'
}
}
};
```
2. **Create selector**:
```javascript
// theme/src/state/selectors/site.js
export const getAuthorName = state => state.site?.siteMetadata?.author?.name || 'Author';
```
3. **Update component**:
```javascript
import { useStaticQuery, graphql } from 'gatsby';
const Component = () => {
const { site } = useStaticQuery(graphql`
query {
site { siteMetadata { author { name } } }
}
`);
return <div>{site.siteMetadata.author.name}</div>;
};
```
4. **Update tests with mocks**:
```javascript
const mockSiteMetadata = { author: { name: 'Test Author' } };
```
5. **Document configuration options** in theme README
The theme should support configuration through:
```javascript
// Component with Redux state
import { render, screen } from '@testing-library/react';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
const mockStore = configureStore([]);
test('renders widget with data', () => {
const store = mockStore({ widget: { data: mockData } });
render(<Provider store={store}><Widget /></Provider>);
expect(screen.getByText('Expected Content')).toBeInTheDocument();
});
// Async actions
import thunk from 'redux-thunk';
const mockStore = configureStore([thunk]);
test('fetches data successfully', async () => {
const store = mockStore({});
await store.dispatch(fetchData());
const actions = store.getActions();
expect(actions[0].type).toBe('DATA_INIT');
expect(actions[1].type).toBe('DATA_SUCCESS');
});
// Snapshot testing
import renderer from 'react-test-renderer';
test('matches snapshot', () => {
const tree = renderer.create(<Component />).toJSON();
expect(tree).toMatchSnapshot();
});
```
```javascript
/** @jsx jsx */
import { jsx } from 'theme-ui';
const Component = () => (
<div sx={{
color: 'text',
bg: 'background',
p: 3,
borderRadius: 4
}}>
Content
</div>
);
```
When making changes, consider:
```bash
yarn workspace gatsby-theme-chronogrove test
yarn workspace www.chrisvogt.me develop
```
```bash
yarn upgrade-interactive
```
```bash
yarn test:coverage
```
```bash
yarn format
```
```bash
yarn lint --fix
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/gatsby-theme-chronogrove-development-atbpf4/raw