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
2 changes: 1 addition & 1 deletion solidjs-tailwind/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ git clone https://github.com/thisdot/starter.dev.git

- `pnpm run dev` - Runs the development server on localhost port 3000 with HMR
- `pnpm run test` - Runs the test suite
- `pnpm run storbook` - To showcase the component library
- `pnpm run storybook` - To showcase the component library
- `pnpm run build` - Builds a production version of the app to deploy
- `pnpm run serve` - Serves a production build on localhost port 4173
- `pnpm run lint` - Uses eslint to find potential issues in the codebase
Expand Down
1 change: 1 addition & 0 deletions solidjs-tailwind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@heroicons/react": "1.0.5"
},
"dependencies": {
"solid-heroicons": "^3.1.0",
"solid-js": "1.6.0"
},
"keywords": [
Expand Down
9 changes: 9 additions & 0 deletions solidjs-tailwind/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions solidjs-tailwind/src/components/Icons/TwitterIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function TwitterIcon(className) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
class={className.class || 'w-6 h-6'}
fill="currentColor"
>
<path fill="none" d="M0 0h24v24H0z" />
<path d="M22.162 5.656a8.384 8.384 0 0 1-2.402.658A4.196 4.196 0 0 0 21.6 4c-.82.488-1.719.83-2.656 1.015a4.182 4.182 0 0 0-7.126 3.814 11.874 11.874 0 0 1-8.62-4.37 4.168 4.168 0 0 0-.566 2.103c0 1.45.738 2.731 1.86 3.481a4.168 4.168 0 0 1-1.894-.523v.052a4.185 4.185 0 0 0 3.355 4.101 4.21 4.21 0 0 1-1.89.072A4.185 4.185 0 0 0 7.97 16.65a8.394 8.394 0 0 1-6.191 1.732 11.83 11.83 0 0 0 6.41 1.88c7.693 0 11.9-6.373 11.9-11.9 0-.18-.005-.362-.013-.54a8.496 8.496 0 0 0 2.087-2.165z" />
</svg>
);
}

export default TwitterIcon;
1 change: 1 addition & 0 deletions solidjs-tailwind/src/components/Icons/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as TwitterIcon } from './TwitterIcon';
19 changes: 19 additions & 0 deletions solidjs-tailwind/src/components/UserProfile/OrgList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { For } from 'solid-js';
function OrgList(props) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use splitProps as it shows a major feature in SolidJs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hdJerry I don't understand this comment. Can you explain why splitProps is required and how what you mean by it shows a major feature in SolidJs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hdJerry splitProps is used when you want to pick out certain properties from an object and pass the rest into a child component. It works the same with Pick in typescript.

It doesn't make sense to use it when all the properties passed are going to be used in that component.

If we need to show how major a feature it is, we can have a store that returns both user and repositories data in one object, then split it into two and pass it into their respective components(or into components where the data is needed). Or do the split inside the component and retrieve just the properties needed by the component.

Copy link
Contributor

@hdJerry hdJerry Nov 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the props are not reactive then no need. @vyktoremario , though it also help to know the props expected in there just like how TS does. SO if I view the component with the spiltProps or mergeProps i know the props allowed in that component.

return (
<div class="mt-5 border-t border-gray-200">
<h2 class="my-2 pt-2 text-gray-800 font-bold">Organizations</h2>
<div data-testid="profile page orgs" class="flex flex-wrap space-x-2">
<For each={props.organizations}>
{(props) => (
<div class="relative w-9 h-9 rounded border border-gray-300 overflow-hidden">
<img src={props.avatarUrl} alt="Organization" />
</div>
)}
</For>
</div>
</div>
);
}

export default OrgList;
101 changes: 101 additions & 0 deletions solidjs-tailwind/src/components/UserProfile/UserProfile.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import {
users,
star,
buildingOffice,
mapPin,
link,
} from 'solid-heroicons/outline';
import { Icon } from 'solid-heroicons';
import { TwitterIcon } from '../Icons';
import OrgList from './OrgList';

const UserProfile = (userProfileProps) => {
return (
<div>
<img
src={userProfileProps.avatarUrl}
alt="Avatar"
width={260}
height={260}
class="rounded-full shadow z-30"
/>
<h1 class="mt-2">
<div class="text-2xl text-gray-800 font-bold leading-tight">
{userProfileProps.name}
</div>
<div class="text-xl text-gray-500 font-light">
{userProfileProps.username}
</div>
</h1>
<div class="text-gray-800 mt-4">{userProfileProps.bio}</div>
<div class="text-sm text-gray-600 my-4">
<Icon path={users} class="w-4 h-4 mb-0.5 mr-1 inline" />
<span class="inline-block">
<span class="font-medium text-gray-900">
{userProfileProps.followers}
</span>{' '}
followers
</span>
<span class="mx-1">·</span>
<span class="inline-block">
<span class="font-medium text-gray-900">
{userProfileProps.following}
</span>{' '}
following
</span>
<span class="mx-1">·</span>
<Icon path={star} class="w-4 h-4 mb-0.5 mr-1 inline" />
<span class="inline-block">
<span class="font-medium text-gray-900">
{userProfileProps.starredRepos}
</span>{' '}
</span>
</div>
<div class="text-sm text-gray-800 space-y-1">
{userProfileProps.company && (
<div>
<Icon path={buildingOffice} class="w-4 h-4 mb-0.5 mr-1 inline" />
{userProfileProps.company}
</div>
)}
{userProfileProps.location && (
<div>
<Icon path={mapPin} class="w-4 h-4 mb-0.5 mr-1 inline" />
{userProfileProps.location}
</div>
)}
{userProfileProps.websiteUrl && (
<div>
<Icon path={link} class="w-4 h-4 mb-0.5 mr-1 inline" />
<a
class="hover:text-blue-600 hover:underline"
href={userProfileProps.websiteUrl}
target="_blank"
rel="noreferrer"
>
{userProfileProps.websiteUrl}
</a>
</div>
)}
{userProfileProps.twitterUsername && (
<div>
<TwitterIcon class="w-4 h-4 mb-0.5 mr-1 inline" />
<a
class="hover:text-blue-600 hover:underline"
href={`https:/twitter.com/${userProfileProps.twitterUsername}`}
target="_blank"
rel="noreferrer"
>
@{userProfileProps.twitterUsername}
</a>
</div>
)}
</div>
{userProfileProps.organizations.length > 0 && (
<OrgList organizations={userProfileProps.organizations} />
)}
</div>
);
};

export default UserProfile;
30 changes: 30 additions & 0 deletions solidjs-tailwind/src/components/UserProfile/UserProfile.spec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Router } from '@solidjs/router';
import { render } from 'solid-testing-library';
import { beforeEach, describe, expect, it } from 'vitest';
import UserProfile from './UserProfile.jsx';
import { userProfileProps } from './data';

describe('User profile card', () => {
let wrapper;
beforeEach(async () => {
wrapper = await render(() => (
<Router>
<UserProfile {...userProfileProps} />
</Router>
));
});

it('should mount', () => {
expect(wrapper).toBeTruthy();
});

it('should show the user display name', async () => {
const fullName = await wrapper.getByText(userProfileProps.name);
expect(fullName).toBeVisible();
});

it('should have a link for user profile picture', async () => {
const avatar = await wrapper.getByAltText('Avatar');
expect(avatar).toBeVisible();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Router } from '@solidjs/router';
import { UserProfile } from '.';
import { userProfileProps } from './data.js';

export default {
title: 'Components/User Profile Card',
component: UserProfile,
};

const Template = (args) => (
<Router>
<UserProfile {...args} />
</Router>
);
export const Default = Template.bind({});

Default.args = {
...userProfileProps,
};
18 changes: 18 additions & 0 deletions solidjs-tailwind/src/components/UserProfile/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const userProfileProps = {
avatarUrl: 'https://avatars.githubusercontent.com/u/2487968?v=4',
bio: `Senior Software Engineer @thisdot`,
company: '@thisdot',
followers: 24,
following: 20,
location: 'Washington, DC',
login: 'tvanantwerp',
name: 'Tom VanAntwerp',
twitterUsername: 'tvanantwerp',
websiteUrl: 'https://tomvanantwerp.com',
organizations: [
{
avatarUrl: 'https://avatars.githubusercontent.com/u/22839396?v=4',
login: 'thisdot',
},
],
};
1 change: 1 addition & 0 deletions solidjs-tailwind/src/components/UserProfile/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default as UserProfile } from './UserProfile';
2 changes: 2 additions & 0 deletions solidjs-tailwind/src/components/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from './CounterExample';
export * from './FetchExample';
export * from './UserProfile';
export * from './Icons';
export * from './RepoFilter';
export * from './GistPanel';
export * from './RepoMeta';
Expand Down