28
loading...
This website collects cookies to deliver better user experience
create-remix@latest
command which sets up our project and gives us a demo site, we will also be using the Remix App Server for local testing. You can change this at a later time if you wish to deploy it. npx create-remix@latest
npm install -D tailwindcss
npm install concurrently
npx tailwindcss init
tailwind.config.js
file in our application for their purge function for any javascript .js
or .jsx
file.module.exports = {
purge: ["./app/**/*.{js,jsx}"], // Here we are going to tell Tailwind to use any javascript .js or .jsx file
theme: { extend: {
} },
variants: {},
plugins: [],
};
package.json
file with scripts to generate our tailwind.css file. package.json
scripts section to match this"scripts": {
"build": "npm run build:css && remix build",
"build:css": "tailwindcss -o ./app/tailwind.css",
"dev": "concurrently \"npm run dev:css\" \"remix dev\"",
"dev:css": "tailwindcss -o ./app/tailwind.css --watch",
"postinstall": "remix setup node",
"start": "remix-serve build"
},
npm run dev
it will generate a tailwind.css file in the root of our /app/ folder. We need to tell Remix that we can to use this style sheet. I'm going to set this up in our Root file so that TailwindCSS styles are imported to the entire site. Remix does this by importing our styles and using their links function to apply the stylesheet to the head of the HTML file. root.jsx
file under (/app
)import tailwindstyles from "./tailwind.css";
// https://remix.run/api/app#links
export let links = () => {
return [
{ rel: "stylesheet", href: globalStylesUrl },
{
rel: "stylesheet",
href: darkStylesUrl,
media: "(prefers-color-scheme: dark)"
},
{ rel: "stylesheet", href: tailwindstyles }
];
};
root.jsx
file under (/app/root.jsx
)function Layout({ children }) {
/fetch
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/fetch">Fetch</Link>
</li>
<li>
<a href="https://remix.run/docs">Remix Docs</a>
</li>
/app/routes/
) folder, create a new folder called fetch
. github.js
export async function getMembers(company){
const searchCompany = !company ? "remix-run" : company;
let res = await fetch(`https://api.github.com/orgs/${searchCompany}/members`)
return res;
}
index.jsx
file inside our /fetch
folder. /app/routes/fetch/index.jsx
) as follows:import { getMembers } from "./github";
export let loader = async () => {
return getMembers();
}
useLoaderFunction
from Remix so let's add this to the top. import { Form, useLoaderData, redirect } from "remix";
export default function Fetch(){
let members = useLoaderData();
return (
<div>
<div>
<h1 className="text-xl text-red-500 my-5">Hello Fetch</h1>
</div>
<div>
<div className="columns-1 md:columns-2 lg:columns-xl">
{members.map(member => (
<div key={member.login} className="flex flex-col w-full border-solid border-2 border-blue-400 rounded-lg px-2 py-2 my-0.5">
<img src={member.avatar_url} className="w-10 h-10 rounded-full" />
<h3 className="text-1xl font-semibold">User: {member.login}</h3>
<a href={member.html_url}>Github Profile: {member.html_url}</a>
</div>
))}
</div>
</div>
</div>
)
}
npm run dev
. If it doesn't open automatically, then bring up your site using http://localhost:3000/ Redirect
and their Action
function. Our search is going to accept input from the user, then redirect them to a new page and display the results, it will also work purely on routing by looking at the URL parameters. /app/routes/fetch/index.jsx
) let's update our imports to include Form
and redirect
. import { Form, useLoaderData, redirect } from "remix";
export default function Fetch(){
let members = useLoaderData();
return (
<div>
<div>
<h1 className="text-xl text-red-500 my-5">Hello Fetch</h1>
<Form className="search" method="post">
<label htmlFor="search">Search:</label>
<input type="text" name="search" id="search"/>
<button type="submit" className="bg-blue-200 m-2 p-2 rounded hover:bg-blue-500">Search</button>
</Form>
</div>
<div>
<div className="columns-1 md:columns-2 lg:columns-3">
{members.map(member => (
<div key={member.login} className="flex flex-col w-full border-solid border-2 border-blue-400 rounded-lg px-2 py-2 my-0.5">
<img src={member.avatar_url} className="w-10 h-10 rounded-full" />
<h3 className="text-1xl font-semibold">User: {member.login}</h3>
<a href={member.html_url}>Github Profile: {member.html_url}</a>
</div>
))}
</div>
</div>
</div>
)
}
/app/routes/fetch/index.jsx
) add the following action function below our existing loader function.export let action = async ({request}) => {
//When a user searches, the form data will be submitted as formData in the request
// we will look in there for the form field "search" and obtain it's value for the redirect
const formData = await request.formData();
const searchCompany = formData.get("search")
return redirect(`/fetch/${searchCompany}`)
}
/app/routes/fetch
) folder, create a file called $search.jsx
. Be sure to include the $. useLoaderData()
function. $search.jsx
file as follows:import { useLoaderData } from "remix";
import { getMembers } from "./github";
export let loader = async ({params}) => {
let res = await getMembers(params.search);
return res;
}
export default function Search(){
let members = useLoaderData();
return (
<div>
<h1 className="text-xl text-red-500 my-5">Hello Search</h1>
<div className="columns-1 md:columns-2 lg:columns-xl">
{members.map(member => (
<div key={member.login} className="flex flex-col w-full border-solid border-2 border-blue-400 rounded-lg px-2 py-2 my-0.5">
<img src={member.avatar_url} className="w-10 h-10 rounded-full" />
<h3 className="text-1xl font-semibold">User: {member.login}</h3>
<a href={member.html_url}>Github Profile: {member.html_url}</a>
</div>
))}
</div>
</div>
)
}