1
0
mirror of https://github.com/uetchy/namae.git synced 2025-03-17 12:30:32 +09:00

feat: smart suggestion

This commit is contained in:
uetchy 2019-08-03 21:51:12 +09:00
parent f4b6140aa6
commit 3982fb5cc4
6 changed files with 91 additions and 30 deletions

View File

@ -15,6 +15,7 @@
"i18next-browser-languagedetector": "^3.0.1", "i18next-browser-languagedetector": "^3.0.1",
"i18next-xhr-backend": "^3.0.0", "i18next-xhr-backend": "^3.0.0",
"isomorphic-unfetch": "^3.0.0", "isomorphic-unfetch": "^3.0.0",
"prop-types": "^15.7.2",
"react": "^16.8.6", "react": "^16.8.6",
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-ga": "^2.6.0", "react-ga": "^2.6.0",

View File

@ -15,5 +15,5 @@
"twitter": "Twitter", "twitter": "Twitter",
"slack": "Slack" "slack": "Slack"
}, },
"try": "suggestion" "try": "How about"
} }

View File

@ -15,6 +15,7 @@ import PypiCard from './components/cards/PypiCard'
import S3Card from './components/cards/S3Card' import S3Card from './components/cards/S3Card'
import CratesioCard from './components/cards/CratesioCard' import CratesioCard from './components/cards/CratesioCard'
import RubyGemsCard from './components/cards/RubyGemsCard' import RubyGemsCard from './components/cards/RubyGemsCard'
import { EventReporter } from './components/Analytics' import { EventReporter } from './components/Analytics'
import Welcome from './components/Welcome' import Welcome from './components/Welcome'
import Footer from './components/Footer' import Footer from './components/Footer'
@ -34,7 +35,7 @@ export default function App() {
const queryGiven = query && query.length > 0 const queryGiven = query && query.length > 0
useEffect(() => { useEffect(() => {
const modifiedValue = inputValue.replace(/[\s@\+!#$%^&*()\[\]]/g, '') const modifiedValue = inputValue.replace(/[\s@+!#$%^&*()[\]]/g, '')
setQuery(modifiedValue) setQuery(modifiedValue)
}, [inputValue, setQuery]) }, [inputValue, setQuery])

View File

@ -1,26 +1,85 @@
import React from 'react' import React, { useEffect, useState } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import fetch from 'isomorphic-unfetch'
import { capitalize } from '../util/text' import { capitalize } from '../util/text'
function modifyWord(word) {
const modifiers = [
(word) => `${capitalize(word)}ify`,
(word) => `lib${lower(word)}`,
(word) => `Omni${capitalize(word)}`,
(word) => `${capitalize(word)}Lab`,
(word) => `${capitalize(word)}Kit`,
(word) => `Open${capitalize(word)}`,
(word) => `${capitalize(word)}box`,
(word) => `Insta${lower(word)}`,
(word) => `${capitalize(word)}Hub`,
(word) => `Semantic ${capitalize(word)}`,
(word) => `Cloud${capitalize(word)}`,
(word) => `Deep${capitalize(word)}`,
(word) => `${capitalize(word)}gram`,
(word) => `${capitalize(word)}base`,
(word) => `${capitalize(word)}API`,
(word) => `${capitalize(word)}note`,
(word) => `In${capitalize(word)}`,
(word) => `Under${lower(word)}`,
(word) => `Uni${lower(word)}`,
(word) => `${capitalize(word)}mind`,
]
return modifiers[Math.floor(Math.random() * modifiers.length)](word)
}
function lower(word) {
return word.toLowerCase()
}
async function findSynonyms(word, maximum = 10) {
try {
const response = await fetch(
`https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&dt=ss&ie=UTF-8&oe=UTF-8&dj=1&q=${encodeURIComponent(
word
)}`
)
const json = await response.json()
const synonyms = json.synsets.reduce(
(sum, synset) =>
(sum = [...sum, ...synset.entry.map((e) => e.synonym[0])]),
[]
)
let bestWords = [
...new Set(
synonyms
.filter((word) => !word.match(/[\s-]/))
.sort(() => Math.random() - 0.5)
.slice(0, maximum)
),
]
const deficit = maximum - bestWords.length
if (deficit > 0) {
bestWords = [...bestWords, ...Array(deficit).fill(word)]
}
return bestWords
} catch (err) {
return Array(maximum).fill(word)
}
}
export default function Suggestion({ query, onSubmit }) { export default function Suggestion({ query, onSubmit }) {
const { t } = useTranslation() const { t } = useTranslation()
const capital = capitalize(query) const [synonyms, setSynonyms] = useState([])
const lower = query.toLowerCase()
const suggestions = [ useEffect(() => {
`${lower}ify`, const fn = async () => {
`insta${lower}`, if (query && query.length > 0) {
`lib${lower}`, const synonyms = (await findSynonyms(query, 3)).map((synonym) =>
`omni${lower}`, modifyWord(synonym)
`${capital}Lab`, )
`${capital}Kit`, setSynonyms(synonyms)
`Open${capital}`, }
`${capital}box`, }
`${lower}hub`, fn()
] }, [query])
.sort(() => Math.random() - 0.5)
.slice(0, 3)
function applyQuery(name) { function applyQuery(name) {
onSubmit(name) onSubmit(name)
@ -30,11 +89,12 @@ export default function Suggestion({ query, onSubmit }) {
<Container> <Container>
<Title>{t('try')}</Title> <Title>{t('try')}</Title>
<Items> <Items>
{suggestions.map((name) => ( {synonyms &&
<Item key={name} onClick={() => applyQuery(name)}> synonyms.map((name) => (
{name} <Item key={name} onClick={() => applyQuery(name)}>
</Item> {name}
))} </Item>
))}
</Items> </Items>
</Container> </Container>
) )
@ -52,9 +112,6 @@ const Container = styled.div`
const Title = styled.div` const Title = styled.div`
margin-top: 15px; margin-top: 15px;
border: 1px solid black;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.6em; font-size: 0.6em;
` `
@ -63,10 +120,13 @@ const Items = styled.div`
margin-left: 8px; margin-left: 8px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap;
justify-content: center;
` `
const Item = styled.div` const Item = styled.div`
margin-right: 8px; margin-right: 10px;
cursor: pointer; cursor: pointer;
font-weight: bold; font-weight: bold;
font-family: monospace;
` `

View File

@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next'
import { FaGithub } from 'react-icons/fa' import { FaGithub } from 'react-icons/fa'
import { Card } from '../Cards' import { Card } from '../Cards'
import { DedicatedAvailability } from '../Availability' import { DedicatedAvailability } from '../Availability'
import { capitalize } from '../../util/text'
export default function GithubCard({ name }) { export default function GithubCard({ name }) {
const { t } = useTranslation() const { t } = useTranslation()
@ -17,7 +16,7 @@ export default function GithubCard({ name }) {
`${lowerCase}hq`, `${lowerCase}hq`,
`${lowerCase}-team`, `${lowerCase}-team`,
`${lowerCase}-org`, `${lowerCase}-org`,
`${capitalize(name)}-js`, `${lowerCase}-js`,
]}> ]}>
{(name) => ( {(name) => (
<DedicatedAvailability <DedicatedAvailability

View File

@ -8291,7 +8291,7 @@ prompts@^2.0.1:
kleur "^3.0.2" kleur "^3.0.2"
sisteransi "^1.0.0" sisteransi "^1.0.0"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.6.2: prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2" version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==