{"id":30357743,"url":"https://github.com/ethereumdevtech/githubuser-finder","last_synced_at":"2025-11-26T03:02:39.635Z","repository":{"id":210952781,"uuid":"587006959","full_name":"EthereumDevtech/githubuser-finder","owner":"EthereumDevtech","description":"A great challenge from Frontend Mentor","archived":false,"fork":false,"pushed_at":"2023-01-09T18:57:38.000Z","size":2459,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-29T00:26:08.959Z","etag":null,"topics":["async-await","bem-css","javascript","scss"],"latest_commit_sha":null,"homepage":"https://githubuser-finder.vercel.app","language":"SCSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EthereumDevtech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-01-09T18:39:29.000Z","updated_at":"2023-01-17T02:59:27.000Z","dependencies_parsed_at":"2023-12-05T18:42:30.800Z","dependency_job_id":"a56f7e30-1c7f-4c8e-83ba-d70965d65eb4","html_url":"https://github.com/EthereumDevtech/githubuser-finder","commit_stats":null,"previous_names":["pijeismart/githubuser-finder","imjuniorcris/githubuser-finder","ethereumdevtech/githubuser-finder"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/EthereumDevtech/githubuser-finder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EthereumDevtech%2Fgithubuser-finder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EthereumDevtech%2Fgithubuser-finder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EthereumDevtech%2Fgithubuser-finder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EthereumDevtech%2Fgithubuser-finder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EthereumDevtech","download_url":"https://codeload.github.com/EthereumDevtech/githubuser-finder/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EthereumDevtech%2Fgithubuser-finder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271121211,"owners_count":24702732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async-await","bem-css","javascript","scss"],"created_at":"2025-08-19T08:19:32.414Z","updated_at":"2025-11-26T03:02:34.250Z","avatar_url":"https://github.com/EthereumDevtech.png","language":"SCSS","readme":"# GitHub User Search App\n\nThis is my first API challenge from Frontend Mentor. In this project, I learned about asynchronous programming and worked with a 3rd-party API.\n\n## The challenge\n\nMy challenge is to build out this GitHub user search app using the GitHub users API and get it looking as close to the design as possible.\n\nMy users should be able to:\n\n- View the optimal layout for the app depending on their device's screen size\n- See hover states for all interactive elements on the page\n- See visible focus states for interactive elements when navigating by keyboard\n- Search for GitHub users by their username\n- See relevant user information based on their search\n- Switch between light and dark themes\n- Understand and be able to navigate page content while using assistive technology\n- Have the correct color scheme chosen for them based on their browser preferences\n\n## Links\n\n- [Frontend Mentor Solution Page](https://www.frontendmentor.io/solutions/github-user-search-app-html-css-sass-javascript-async-await-nBt6_lQS5M)\n\n## Screenshots\n\n![Desktop light theme](./screenshots/desktop-light.jpg)\n\n![Desktop dark theme](./screenshots/desktop-dark.jpg)\n\n## Built with\n\n- HTML Semantic Tags\n- [BEM (Block, Element, Modifier)](https://sparkbox.com/foundry/bem_by_example)\n- [Sass](https://sass-lang.com/)\n- JavaScript Async Await and Fetch API\n- CSS flexbox and grid\n- [GitHub user API](https://docs.github.com/en/rest/users/users#get-a-user)\n- [ipify - A Simple Public IP Address API](https://www.ipify.org/)\n- Mobile-first workflow\n\n## What I learned\n\nI learned a lot of things while building this project and I wrote everything that I learned.\n\n### GitHub user API\n\nHere is the URL.\n\n```txt\nhttps://api.github.com/users/{username}\n```\n\nThe documentation shows that I can get:\n\n- User's data in JSON format\n- `200` or `404` HTTP response status code\n\nSee the documentation — [Users - GitHub Docs #get-a-user](https://docs.github.com/en/rest/users/users#get-a-user)\n\nFor the status code, there is a chance that I can get `403`. This happened after I did so many requests.\n\n![Error: API rate limit exceeded for 37.19.205.194 (403 Forbidden)](./images/api-rate-limit-exceeded.png)\n\n### Asynchronous programming\n\nAsynchronous programming is a program that doesn't block the main process of executing JavaScript.\n\nThe example of asynchronous programming that I can think of is the `setTimeout()` function.\n\n```javascript\nsetTimeout(() =\u003e {\n  console.log(\"What did I miss?\");\n}, 3000)\nconsole.log(\"I don't get blocked by the setTimeout() function\");\nconsole.log(\"Me too!\");\n\n// Output:\n// \u003e I don't get blocked by the setTimeout() function\n// \u003e Me too!\n// \u003e What did I miss?\n```\n\n### Two ways to make a request to the API\n\nTwo ways to get the user data from the GitHub API.\n\n- First, an old-school way is by using `XMLHttpRequest()`.\n- Second, the modern way is by using Fetch API.\n\nThis is the code snippet to get the user's data using `XMLHttpRequest()`.\n\n```javascript\nconst fetchUserData = (username) =\u003e {\n  const xhr = new XMLHttpRequest();\n\n  xhr.open(\"GET\", `https://api.github.com/users/${username}`);\n\n  xhr.responseType = \"json\";\n\n  xhr.onreadystatechange = () =\u003e {\n    const DONE = 4;\n    const OK = 200;\n\n    if (xhr.readyState === DONE) {\n      if (xhr.status === OK) {\n        const json = xhr.response;\n        showUserData(json);\n      }\n    }\n  };\n};\n```\n\nIn comparison with Fetch API, it is much shorter than using the old-school way.\n\n```javascript\nfetch(`https://api.github.com/users/${username}`)\n  .then((response) =\u003e response.json())\n  .then((json) =\u003e /* do something */)\n```\n\nResources:\n\n- [XMLHttpRequest - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest)\n- [Fetch API - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)\n\n### Elegant way to work with promises\n\nInstead of using `.then()`, a better way to deal with `Promise` which is by using `async` and `await` keywords.\n\n```javascript\nconst fetchUserData = async (username) =\u003e {\n  try {\n    const response = await fetch(`https://api.github.com/users/${username}`);\n    const json = await response.json();\n    /* do something */\n  } catch (error) {\n    /* handle error */\n  }\n}\n```\n\n### Color flashing\n\nColor flashing happens when the saved color scheme is the opposite color scheme of the browser's preference.\n\nFor example, the browser's color scheme is light and the saved color scheme is dark. When the user refreshes the page, the app's color scheme is white and will be dark after several milliseconds.\n\nI created a GIF that demonstrates the color flashing.\n\n\u003cdetails\u003e\n\u003csummary\u003eColor flashing demo\u003c/summary\u003e\n\n![The initial color scheme is light. Then, I switch the color scheme to dark by clicking the theme switcher button. After that, I refresh the page. For several milliseconds, the page has a light color scheme. Then, it changes to a dark color scheme.](./images/flashing.gif)\n\n\u003c/details\u003e\n\nColor flashing happens because the script only runs after the HTML has been fully parsed. That's why the app will be using the default color scheme at first. Once the script is executed, only then the app will use the saved color scheme (by checking the `localStorage`).\n\nFor your information: I hide the GIF because not all people can deal with animation. So, it is best to hide it by default. Learn more — [Your Interactive Is Making Me Sick](https://source.opennews.org/articles/motion-sick/) and [Accessibility For Vestibular Disorders](https://alistapart.com/article/accessibility-for-vestibular/).\n\n### How to switch the color scheme correctly?\n\nThree things that I need to make the app switch color scheme correctly.\n\n- First, the app follows the user's color scheme preference.\n- Second, the app should be able to remember the user's latest selected color scheme.\n- Third, no color flashing.\n\nTo achieve the first goal, I needed to use `prefers-color-scheme` media query. I used CSS custom properties to control all the colors for all elements.\n\nFor example:\n\n```css\n:root {\n  /* color variables */\n  --very-light-blue: hsl(227, 100%, 98%);\n  --dark-blue-100: hsl(217, 35%, 45%);\n  --very-dark-blue-300: hsl(220, 40%, 13%);\n  --white: hsl(0, 0%, 100%);\n\n  /* variables that handle the color for each element */\n  --body-background-color: var(--very-light-blue);\n  --body-font-color: var(--dark-blue-100);\n}\n\n@media screen and (prefers-color-scheme: dark) {\n  :root {\n    --body-background-color: var(--very-dark-blue-300);\n    --body-font-color: var(--white);\n  }\n}\n\nbody {\n  background-color: var(--body-background-color);\n  color: var(--body-font-color);\n}\n```\n\nAs a result, the `\u003cbody\u003e`'s background color and text color are adapting to the user's color scheme preference.\n\nNext, I needed to understand different ways the user to change the color scheme of the website. This way, I would know what I should do to make the app remembers the latest selected color scheme.\n\nThe user can change the color scheme of the website by:\n\n- Clicking the theme switcher\n- Changing the color scheme preference from the browser's setting\n\nAfter knowing that, I should make sure that the app's color scheme should be able to adapt. Whether the users change the color scheme with the theme switcher or switch the browser's color scheme, the app's color scheme should change.\n\nTo make the app remembers the latest selected color scheme, I used `localStorage` to store the user's latest choice if the user uses the theme switcher. When the user changes the browser's color scheme, I clear the `localStorage` and make the app follows that.\n\nThis way, the latest user's setting will always get applied, regardless of the way the user changes the color scheme.\n\nAfter that, I needed to prevent the app from having color flashing.\n\nI created a new JavaScript file that set the app's color scheme. I made the script load synchronously. This way, the app's color scheme has been set up when the page is fully loaded. Also, the app does not have color flashing.\n\nThe script works by checking the `localStorage` if there is a saved color scheme. If there is, then apply the value as the class of the `\u003chtml\u003e` element. Otherwise, the script will not do anything.\n\nWith all of those, the app's color scheme is adapting to different situations and has no color flashing. That is how to switch the app's color scheme correctly.\n\nResources:\n\n- [prefers-color-scheme - CSS: Cascading Style Sheets | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme)\n- [Window.localStorage - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)\n\n### Regular Expressions\n\nGitHub allows the user to input any data. For example, the user is allowed to input \"hello world\" for the website's URL. So, I had to use regular expressions to check the user's data and render the content with appropriate HTML markup.\n\n#### Date\n\nThe first regular expression is used to get the date format for the date the user's account was created.\n\n```js\nconst dateRegEx = /\\d{2} [A-Z][a-z]{2} \\d{4}/;\n```\n\nHere is an example of the user's data:\n\n```json\n{\n  \"created_at\": \"2021-02-13T23:22:17Z\"\n}\n```\n\nThen, I did the following to get the date format.\n\n```js\nconst formattedDate = new Date(\"2021-02-13T23:22:17Z\").toUTCString().match(dateRegEx)[0];\n// Output\n// 13 Feb 2021\n```\n\n#### Whitespace\n\nThe second regular expression is used to check whitespace in a URL.\n\n```js\nconst whitespaceRegEx = /\\s/;\n```\n\nHere is the an example of the user's data:\n\n```json\n{\n  \"blog\": \"https://www.linkedin.com/in/bill-fowler-43592a243/\"\n}\n```\n\nIf there is no whitespace, then it is a URL, and it will be rendered as a link. Otherwise, it will be rendered as normal text.\n\nHere is an example of an invalid URL:\n\n```json\n{\n  \"blog\": \"hello world\"\n}\n```\n\n#### HTTP\n\nThe third regular expression is used to check `http` or `https` within the URL.\n\n```js\nconst HTTPRegEx = /^https?:\\/\\//;\n```\n\nThis is another regular expression to check the value of the `blog` data. If the string does not contain whitespace and `http`, then add `http` to it.\n\nFor example, if the string is `github.com`, the end result will be `http://github.com`.\n\nIf the string contains `http` or `https` then it will pass the test and wrap the URL with `\u003ca\u003e` element.\n\n#### At sign\n\nThe fourth regular expression is used to check if the value of the `company` data has `@` symbol or not.\n\n```js\nconst companyRegEx = /@/;\n```\n\nHere is an example of the data:\n\n```json\n{\n  \"company\": \"@frontendmentorio\"\n}\n```\n\nIf the value of the `company` data has `@` symbol, I assume that the company has a GitHub account. So, it will be rendered as a link.\n\nHere is an example of the HTML markup:\n\n```html\n\u003ca href=\"https://github.com/frontendmentorio\" rel=\"nofollow me\"\u003e\n  @frontendmentorio\n\u003c/a\u003e\n```\n\nIf there is not `@` symbol, then it will be rendered as normal text.\n\n#### GitHub username\n\nThe fifth regular expression is used to check the user's input on the search text field.\n\n```js\nconst githubUserNameRegEx = /^[a-z\\d](?:[a-z\\d]|-(?=[a-z\\d])){0,38}$/i;\n```\n\nThe regular expression follows the real criteria.\n\n![Error: Username is too long (maximum is 39 characters). Username may only contain alphanumeric characters or single hyphens, cannot begin or end with a hyphen.](./images/github-username-complete-criteria.png)\n\nA valid username is a username that:\n\n- Has less than or exactly 39 characters\n- Do not start and end with a hyphen\n- Contain alphanumeric characters or single hyphens\n\nWith that regular expression, if the user tries to search for an invalid username, then it won't search and throw an error message \"Invalid username\" on the UI.\n\nFor your information, I did not create this regular expression. I got it from the following repository.\n\n[shinnn/github-username-regex: A regular expression that only matches a currently valid Github username](https://github.com/shinnn/github-username-regex)\n\n### Overflowing text\n\nYazdun noticed that there is an overflowing issue when tries to view mseidel819's profile with my app.\n\n![Yazdun said \"Hi Vanza, Great job on this challenge, I specially love the fact that you added a query in the url for the searched user, that's a really nice touch. Here is a quick issue that Matt Seidel noticed on my solution and then I could fix it. Try searching mseidel819 in your app and you will see a weird overflow which doesn't look nice, you may wanna take care of that.\"](./images/yazdun-comment.png)\n\nHere is the issue:\n\n![My app is showing an overflowing issue when displaying Matt Seidel's GitHub profile (@mseidel819).](./images/devfinder-mseidel819-overflowing-issue.png)\n\nI did some research on the internet to find an answer to the issue. I found the MDN documentation page that explains how to manage overflowing text with CSS.\n\n[Wrapping and breaking text - CSS: Cascading Style Sheets | MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Text/Wrapping_Text)\n\nI didn't manage to find the answer on the website. But, I got some information about some CSS properties that deal with text wrappings, such as `word-break` and `overflow` properties.\n\nThen, I was thinking about the way GitHub handle overflowing text. Then, I took a look at the mseidel819 profile on GitHub. After that, I inspected the styling of the element that has overflowing text.\n\n![](./images/how-github-handle-overflowing-text-1.png)\n\nGitHub used the following CSS to handle overflowing text:\n\n```css\n.css-truncate.css-truncate-target {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n```\n\nI copied that code snippet and applied it to my own stylesheet. And here is the result:\n\n![My app is no longer showing an overflowing issue when displaying Matt Seidel's GitHub profile (@mseidel819).](./images/devfinder-mseidel819-overflowing-issue-solved.png)\n\nYou might be wondering that if the text content is not visible, then how the users would access the content? It can't be visually accessible. But, the text content is still 100% available. I tried to copy-paste the text and got the full value. Also, I tested the site with Narrator and it could read the whole text.\n\nThe better solution is to make the two-column layout a one-column layout instead.\n\n![](./images/devfinder-mseidel819-new-design.png)\n\nI think that is a good solution because not only it fixes the overflowing issue, but also there's no visually hidden text. Everything can be seen clearly and nicely.\n\nBut, I still follow GitHub's approach to solve the issue. The reason is that the challenge is trying to create the app to look as close to the design as possible. So, I still follow the design from the original design.\n\n### Better solution to overflowing text issue\n\nWhile refactoring this project on 4th January 2023, I notice that GitHub is using different approach.\n\nNow, GitHub does not truncate the text. Instead it shows everything.\n\n![](./images/github-does-not-truncate-text-anymore.png)\n\nThe only styling that it has is to set `word-wrap: break-word;` to the text element that is wrapped with a `\u003cdiv\u003e`.\n\nAlso, GitHub does a \"smart trick\" to ensure that the text content aligns vertically.\n\nFirst, GitHub sets some `padding-left` to the `\u003cli\u003e`.\n\n![](./images/github-smart-trick-1.png)\n\nSecond, GitHub sets some negative `margin-left` and `float: left` to the `\u003csvg\u003e`.\n\n![](./images/github-smart-trick-2.png)\n\nWithout those styling, the icon will be included in the normal flow and makes the layout not align properly.\n\n![](./images/github-without-smart-trick-mseidel819.png)\n\nTo make it even clearer, I recommend taking a look at the following screenshots.\n\nWith the \"smart trick\", the icon is not joined with the text.\n\n![](./images/github-with-smart-trick-howtologinquickwiththirtyninecharacters.png)\n\nWithout the trick, the icon is in line with the text.\n\n![](./images/github-without-smart-trick-howtologinquickwiththirtyninecharacters.png)\n\n### Placeholder and label\n\nHere is the HTML markup.\n\n```html\n\u003cinput\n  type=\"text\"\n  id=\"username-input\"\n  placeholder=\" \"\n  required\n/\u003e\n\u003clabel for=\"username-input\"\u003e\n  Search GitHub username...\n\u003c/label\u003e\n```\n\nThe idea is to put the `\u003clabel\u003e` inside the `\u003cinput\u003e`. It means that the `\u003clabel\u003e` will be acting as a placeholder.\n\n![Label inside the search input](./images/initial-state-of-the-placeholder.png)\n\nThen, once the user inputs a character, the `\u003clabel\u003e` becomes an actual label.\n\n![Label moves to above search input](./images/last-state-of-the-placeholder.png)\n\nThis pattern is known as the \"float label pattern\".\n\nThe reason for doing this is that there is no visible label on the design. As a user, sometimes I forget about the input. So, by making sure the label is visible when I input a character, I know what the input is about.\n\nAs a side note, It is important to know that a placeholder is not a replacement for a label.\n\nNow, the floating label is not the best solution. The best solution is to provide a visible label all the time. In other words, the `\u003clabel\u003e` is always acting like a label.\n\n\nAnother reason is when the `\u003clabel\u003e` becomes a label, the logo and the `\u003clabel\u003e` are not having enough whitespace between them. They are too close together.\n\n![](./images/float-label-pattern-issue.png)\n\nIn summary, a floating label is a possible solution for this situation. I need to make sure that the app looks as close as possible to the design. But, a visible label is still the best solution because `\u003clabel\u003e` only needs to be a label.\n\nI recommend watching the following video made by Heydon Pickering. In that video, Heydon is talking about different designs of input and label.\n\n[What Happened To Text Inputs? - YouTube](https://www.youtube.com/watch?v=he8wuV880Fc)\n\nResources:\n\n- [HTML Standard #the-placeholder-attribute](https://html.spec.whatwg.org/multipage/input.html#the-placeholder-attribute)\n- [Float label pattern in UX form design](https://scribe.rip/float-label-pattern-in-ux-form-design-7ab5e33010ab)\n- [Floating labels are problematic](https://scribe.rip/simple-human/floating-labels-are-a-bad-idea-82edb64220f6)\n- [Float Label Pattern | Brad Frost](https://bradfrost.com/blog/post/float-label-pattern/)\n\n## Useful resources\n\n- [A Theme Switcher | Inclusive Components](https://inclusive-components.design/a-theme-switcher/) and [Toggle Buttons | Inclusive Components](https://inclusive-components.design/toggle-button/) articles are helping me to create an accessible theme switcher. I recommend everyone that doing this challenge read both articles.\n- [ryanmcdermott/clean-code-javascript: Clean Code concepts adapted for JavaScript](https://github.com/ryanmcdermott/clean-code-javascript) - I wish that I know this repository when I was writing the JavaScript. This repository contains a lot of best practices on how to write clean JavaScript code. I highly recommend taking some time to read it.\n- [RegExr](https://regexr.com/) - This is the tool that I used when I was crafting or testing a regular expression that I wanted to use. It has a handy cheat sheet and is easy to use. I recommend using it for anyone that wants to create or test some regular expressions.\n\n## Author\n\n- Github - [@pijeismart](https://github.com/pijeismart)\n\n## Acknowledgements\n\nThanks to [@shinnn](https://officialdevfinder.netlify.app/?user=shinnn) for the regular expression!\n\nSee the regular expression for GitHub username — [shinnn/github-username-regex: A regular expression that only matches a currently valid GitHub username](https://github.com/shinnn/github-username-regex)\n\nThanks to Grace for helping me improve the accessibility of the site!\n\nShe helped me by:\n\n- Answering all my questions on the solution page\n- Telling me to add a live region to announce the result to the screen reader users\n- Giving me information that radio inputs are better than a checkbox input for the theme switcher\n- Telling me to simplify things or, in other words, not to overcomplicate accessibility\n\n[Frontend Mentor | Grace's profile](https://www.frontendmentor.io/profile/grace-snow)\n\nHere are screenshots of our Slack conversation.\n\n![A thread in the Slack (First part) — Grace tells me that using radio inputs is better than using checkbox input.](./images/use-radio-inputs-for-theme-switcher-1.png)\n\n![A thread in the Slack (Second part) - Grace tells me how to create a theme switcher with radio inputs.](./images/use-radio-inputs-for-theme-switcher-2.png)\n\n## License\n\n[MIT](./LICENSE)\n\n## References\n\nSee the [documentation](./docs/README.md).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fethereumdevtech%2Fgithubuser-finder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fethereumdevtech%2Fgithubuser-finder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fethereumdevtech%2Fgithubuser-finder/lists"}