Skip to content

Commit

Permalink
Merge branch 'main' into csa
Browse files Browse the repository at this point in the history
  • Loading branch information
rupali-codes authored Aug 15, 2023
2 parents 665ac36 + 804d81c commit 17494ed
Show file tree
Hide file tree
Showing 38 changed files with 603 additions and 407 deletions.
2 changes: 2 additions & 0 deletions .github/ISSUE_TEMPLATE/add_link.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ body:
- Artificial Intelligence
- Internet of Things
- Cloud Computing
- DevOps
- Competitive Programming
- Youtube
- Resources
- Languages
Expand Down
50 changes: 19 additions & 31 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,33 +152,7 @@ When adding _YouTube_ channel links, please specify _the language_ of the channe
- If you decide to close the issue, please leave a brief comment describing why(e.g., I'm busy with other obligations.) before you do.
- **Note:** If the Pull Request associated with the issue gets merged and the issue still remains open, it's **your** responsibility to close the issue.
## Commits
- Please keep your commit messages short and clear.
- Use the `type: subject` format for writing your commit messages. `type` could be one of the following:
- `feat`: use this if you're adding any new feature
- `fix`: use this if you're fixing anything in the codebase
- `chore`: use this when you're adding new links/resources AND when making any small changes
(ex. chore: add _resource_name_ in _subcategory_name_ _category_name_ )
If you need more tips, check out [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
## Making Pull Requests
1. When you submit a pull request, several tests are automatically run
as GitHub Actions. If any of these tests fail, it is your responsibility to try and resolve the underlying issue(s). If you don't know how to resolve the underlying issue(s), you can ask for help.
2. Each pull request should contain a single logical change or related set of changes that make sense to submit together. If a pull request becomes too large or contains too many unrelated changes, it becomes too difficult to review. In such cases, the reviewer has the right to close your pull request and ask that you submit a separate pull request for each logical set of changes that belong together.
3. Link the issue you have resolved in the Pull Request Template (e.g. Closes/Fixes #99).
4. Use [Conventional commit messages](https://www.conventionalcommits.org/en/v1.0.0/) for your changes.
5. Do not re-open a pull request that a reviewer has closed.
- Make sure to tick the "Allow edits from maintainers" box. This allows us to directly make minor edits / refactors and saves a lot of time.
> **Note**
> If your pull request has merge conflicts with the `main` branch (GitHub checks for this automatically and notifies you), you are responsible for resolving them. You can do this by merging the `main` branch into your branch (`git pull upstream main`), and then pushing the updated branch to your fork (`git push`). If you need more tips, check out [Resolving a merge conflict on GitHub](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-on-github).
---
### Commit Message Guidelines using Commitlint
## Commits Message Guidelines
We follow a standardized commit message format using Commitlint to ensure consistency and clarity in our commit history. Each commit message should adhere to the following guidelines:
Expand All @@ -198,9 +172,7 @@ We follow a standardized commit message format using Commitlint to ensure consis
4. **Issue reference** (Optional): Include the issue number associated with the commit (e.g., `#123`).
### Examples:
#### Valid Commit Messages:
#### Examples of Valid Commit Messages:
- `feat: Add user authentication feature`
- `fix(auth): Resolve login page redirect issue
Expand All @@ -211,7 +183,7 @@ We follow a standardized commit message format using Commitlint to ensure consis
- `chore: Update dependencies to latest versions
- `fix: Handle edge case in data processing (#456)`
#### Invalid Commit Messages:
#### Examples of Invalid Commit Messages:
- `Added new stuff`
- `Fixed a bug`
Expand All @@ -226,6 +198,22 @@ git commit -m "feat(auth): Implement user signup process (#789)"
```
<hr>
## Making Pull Requests
1. When you submit a pull request, several tests are automatically run
as GitHub Actions. If any of these tests fail, it is your responsibility to try and resolve the underlying issue(s). If you don't know how to resolve the underlying issue(s), you can ask for help.
2. Each pull request should contain a single logical change or related set of changes that make sense to submit together. If a pull request becomes too large or contains too many unrelated changes, it becomes too difficult to review. In such cases, the reviewer has the right to close your pull request and ask that you submit a separate pull request for each logical set of changes that belong together.
3. Link the issue you have resolved in the Pull Request Template (e.g. Closes/Fixes #99).
4. Use [Conventional commit messages](https://www.conventionalcommits.org/en/v1.0.0/) for your changes.
5. Do not re-open a pull request that a reviewer has closed.
- Make sure to tick the "Allow edits from maintainers" box. This allows us to directly make minor edits / refactors and saves a lot of time.
> **Note**
> If your pull request has merge conflicts with the `main` branch (GitHub checks for this automatically and notifies you), you are responsible for resolving them. You can do this by merging the `main` branch into your branch (`git pull upstream main`), and then pushing the updated branch to your fork (`git push`). If you need more tips, check out [Resolving a merge conflict on GitHub](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-on-github).
---
## Remarks ✅
- If something is missing here, or you feel something is not well described, either create a PR, [raise an issue](https://github.com/rupali-codes/LinksHub/issues), or [do a code review of the person’s PR](https://www.freecodecamp.org/news/code-review-tips/) (ensure that your review conforms to the [Code of Conduct](https://github.com/CBID2/LinksHub-my-version-/blob/main/CODE_OF_CONDUCT.md))
8 changes: 4 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The security policy covers the codebase and documentation of the open source pro

## Vulnerability Disclosure Process

The project will provide a dedicated email address (rupali7487@gmail.com) for submitting vulnerability reports related to the [Linkshub](https://linkshub.vercel.app/) website or any of the linked websites. Vulnerability reports will be reviewed and triaged by the project's maintainers. The owner will aim to respond to vulnerability reports within 72 hours, and will provide regular updates on the status of the vulnerability and any remediation efforts.
The project will provide a dedicated email address (rupali7487@gmail.com) for submitting vulnerability reports related to the [Linkshub](https://linkshub.vercel.app/) website or any of the linked websites. Vulnerability reports will be reviewed and triaged by the project's maintainers. The owner will aim to respond to vulnerability reports within 72 hours and will provide regular updates on the status of the vulnerability and any remediation efforts.

## Roles and Responsibilities

Expand All @@ -22,15 +22,15 @@ LinksHub will aim to resolve critical vulnerabilities within 30 days and non-cri

## Secure Coding Practices

LinksHub will provide guidance on secure coding practices for contributors, including guidelines for input validation, authentication, authorization, and data protection.
LinksHub will guide secure coding practices for contributors, including guidelines for input validation, authentication, authorization, and data protection.

## Regular Review and Update

The security policy will be regularly reviewed and updated to ensure that it remains effective and relevant. The maintainers will evaluate the vulnerability disclosure process, update secure coding guidelines, and revise the response timeline as needed.

## Disclosure Policy

LinksHub will follow a coordinated disclosure policy, which means that vulnerabilities will be disclosed publicly only after they have been remediated. The project may work with external website owners to coordinate disclosure of vulnerabilities that affect their websites.
LinksHub will follow a coordinated disclosure policy, which means that vulnerabilities will be disclosed publicly only after they have been remediated. The project may work with external website owners to coordinate the disclosure of vulnerabilities that affect their websites.

## Legal Disclaimer

Expand All @@ -40,4 +40,4 @@ The security policy includes a legal disclaimer that limits the liability of the

If you have any questions or concerns about the security policy or any security vulnerabilities in the project, please contact us at _linkshub.opensource@gmail.com_.

By implementing this security policy, we aim to ensure that vulnerabilities are addressed in a timely manner, and that users and contributors can use [Linkshub](https://linkshub.vercel.app/) and its linked sources safely and securely.
By implementing this security policy, we aim to ensure that vulnerabilities are addressed promptly and that users and contributors can use [Linkshub](https://linkshub.vercel.app/) and its linked sources safely and securely.
65 changes: 44 additions & 21 deletions components/CopyToClipboard/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,56 @@
import useCopyToClipboard from 'hooks/useCopyToClipboard'
import React from 'react'
import { FaRegCopy } from 'react-icons/fa'
import { Tooltip } from 'react-tooltip'
import useCopyToClipboard from "hooks/useCopyToClipboard";
import React from "react";
import { FaRegCopy, FaCheckSquare } from "react-icons/fa";
import { Tooltip } from "react-tooltip";

type CopyToClipboardProps = {
url: string
}
url: string;
};

export const CopyToClipboard = ({ url }: CopyToClipboardProps): JSX.Element => {
const [copyToClipboard, { success }] = useCopyToClipboard()
const [copyToClipboard, { success }] = useCopyToClipboard();

function handleCopy(e: React.MouseEvent<SVGElement, MouseEvent>) {
e.stopPropagation()
copyToClipboard(url)
e.stopPropagation();
copyToClipboard(url);
}

return (
<div
className="dropdown dropdown-left dropdown-hover">
<div style={{ position: 'relative' }}>
<button data-tooltip-id="copy-tooltip" data-tooltip-content={success ? 'Copied!' : 'Copy'} data-tooltip-place="top">
<FaRegCopy
size={'1.3rem'}
className="text-theme-primary cursor-pointer"
onClick={(e) => handleCopy(e)}
/>
<div className="dropdown dropdown-left dropdown-hover">
<div style={{ position: "relative" }}>
<button
data-tooltip-id="copy-tooltip"
data-tooltip-content={success ? "Copied!" : "Copy"}
data-tooltip-place="top"
>
{success ? ( // Render the FaCheckSquare icon if success is true
<FaCheckSquare
size={"1.3rem"}
className="text-theme-primary cursor-pointer"
onClick={(e) => handleCopy(e)}
aria-label="Link copied" // Add aria-label for accessibility
/>
) : (
<FaRegCopy // Otherwise, render the default FaRegCopy icon
size={"1.3rem"}
className="text-theme-primary cursor-pointer"
onClick={(e) => handleCopy(e)}
aria-label="Copy link to clipboard" // Add aria-label for accessibility
/>
)}
</button>
<Tooltip id='copy-tooltip' style={{ backgroundColor: '#8b5cf6', fontSize: '13px', paddingLeft: '6px', paddingRight: '6px', paddingTop: '2px', paddingBottom: '2px' }} />
<Tooltip
id="copy-tooltip"
style={{
backgroundColor: "#8b5cf6",
fontSize: "13px",
paddingLeft: "6px",
paddingRight: "6px",
paddingTop: "2px",
paddingBottom: "2px",
}}
/>
</div>
</div>
)
}
);
}
14 changes: 14 additions & 0 deletions components/ErrorMessage/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
interface ErrorMessageProps {
children: React.ReactNode
className?: string | undefined
}

export const ErrorMessage: React.FC<ErrorMessageProps> = ({
children,
className,
}) => {
const defaultClasses = 'text-red-500 mt-2'
const classes = defaultClasses + ' ' + (className ?? '')

return <p className={classes}>{children}</p>
}
2 changes: 1 addition & 1 deletion components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const Header: FC = () => {

return (
<header className="fixed top-0 left-0 z-30 row-start-1 row-end-2 flex h-[76px] w-screen items-center justify-between bg-light-primary dark:bg-dark">
<div className="bg-[rgba(255,255,255,0.3)] h-full w-fit flex-none px-6 py-4 dark:bg-dark lg:w-[290px]">
<div className="bg-light-primary h-full w-fit flex-none px-6 py-4 dark:bg-dark lg:w-[290px]">
<Link href="/" aria-label="LinksHub Logo">
<Logo className="text-3xl" />
</Link>
Expand Down
132 changes: 74 additions & 58 deletions components/Searchbar/Searchbar.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,80 @@
import React, { useState, useRef } from 'react'
import { useRef, useEffect } from 'react'

import SearchIcon from 'assets/icons/SearchIcon'
import { useRouter } from 'next/router'
import { SearchbarSuggestions } from './SearchbarSuggestions'
import { ErrorMessage } from 'components/ErrorMessage'

import { subcategoryArray } from '../../types'
import { SearchbarAction } from './SearchbarReducer'
import { useRouter } from 'next/router'

interface SearchbarProps {
setSearch: (search: string) => void
dispatchSearch: (action: SearchbarAction) => void
searchQuery: string
showSuggestions: boolean
searchQueryIsValid: boolean
}

export const Searchbar: React.FC<SearchbarProps> = ({ setSearch }) => {
const searchOptions = subcategoryArray
const SEARCH_ERROR_MSG = 'Please enter a valid search query'

export const Searchbar: React.FC<SearchbarProps> = ({
dispatchSearch,
searchQuery,
showSuggestions,
searchQueryIsValid,
}) => {
const formRef = useRef<HTMLFormElement>(null)
const router = useRouter()
const query = router.query.query
const [searchQuery, setSearchQuery] = useState((query as string) ?? '')
const [errorMessage, setErrorMessage] = useState('')
const [suggestions, setSuggestions] = useState<string[]>([])
const dropdownRef = useRef<HTMLUListElement>(null)
const suggestions = getFilteredSuggestions(searchQuery)

const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value
setSearchQuery(value)

const trimmedValue = value.trim().toLowerCase()
if (trimmedValue === '') {
setErrorMessage('')
setSuggestions([])
setSearch('')
} else {
const filteredSuggestions = subcategoryArray.filter((option) =>
option.toLowerCase().includes(trimmedValue)
)
setSuggestions(filteredSuggestions)
}
dispatchSearch({
type: 'search_query_change',
searchQuery: e.target.value,
})
}

const handleSuggestionClick = (suggestion: string) => {
setSearchQuery(suggestion)
setSearch(suggestion)
setSuggestions([])
const handleSuggestionClick = (searchQuery: string) => {
dispatchSearch({ type: 'suggestion_click', searchQuery })
router.push({
pathname: '/search',
query: {
query: searchQuery,
},
})
}

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (searchQuery.trim() === '') {
setErrorMessage('Please enter a search query')
} else {
setErrorMessage('')
setSearch(searchQuery)

dispatchSearch({ type: 'submit' })
if (searchQuery.trim() !== '') {
router.push({
pathname: '/search',
query: {
query: searchQuery,
},
})
}
}

const handleClickOutsideDropdown = (e: MouseEvent) => {
if (
dropdownRef.current &&
!dropdownRef.current.contains(e.target as Node)
) {
setSuggestions([])
useEffect(() => {
const handleClickOutsideDropdown = (e: MouseEvent) => {
if ((formRef.current as HTMLFormElement).contains(e.target as Node))
return
dispatchSearch({ type: 'close_suggestions' })
}
}

React.useEffect(() => {
document.addEventListener('mousedown', handleClickOutsideDropdown)

return () => {
document.removeEventListener('mousedown', handleClickOutsideDropdown)
}
}, [])
}, [dispatchSearch])

return (
<form onSubmit={handleSubmit} noValidate>
<form noValidate ref={formRef} onSubmit={handleSubmit}>
<div className="relative">
<div className="flex items-center" role="search">
<label htmlFor="simple-search" className="sr-only">
Expand All @@ -90,24 +99,31 @@ export const Searchbar: React.FC<SearchbarProps> = ({ setSearch }) => {
<SearchIcon className="w-5 h-5" aria-hidden="true" />
</button>
</div>
{suggestions.length > 0 && (
<ul
ref={dropdownRef}
className="absolute z-10 text-light-primary bg-theme-secondary w-full mt-1 rounded-lg shadow-2xl"
>
{suggestions.map((suggestion) => (
<li
key={suggestion}
className="px-4 py-2 cursor-pointer hover:bg-[rgba(0,0,0,0.2)] capitalize"
onClick={() => handleSuggestionClick(suggestion)}
>
{suggestion.split('-').join(' ')}
</li>
))}
</ul>
{suggestions.length > 0 && showSuggestions && (
<SearchbarSuggestions
suggestions={suggestions}
onSuggestionClick={handleSuggestionClick}
/>
)}
</div>
{errorMessage && <p className="text-red-500">{errorMessage}</p>}
{!searchQueryIsValid && <ErrorMessage>{SEARCH_ERROR_MSG}</ErrorMessage>}
</form>
)
}

const getFilteredSuggestions = (query: string) => {
const normalisedQuery = query.trim().toLowerCase()
if (normalisedQuery.length === 0) {
return []
}

const suggestions = new Set<string>([])
searchOptions.forEach((option) => {
const normalisedOption = option.toLowerCase()
if (normalisedOption.includes(normalisedQuery)) {
suggestions.add(normalisedOption)
}
})

return Array.from(suggestions)
}
Loading

0 comments on commit 17494ed

Please sign in to comment.