> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/proj/dictionary-app.md).

# Dictionary App

[JS](/web/js.md) ⟩ [Project](/web/js/proj.md) ⟩ Dictionary&#x20;

{% tabs %}
{% tab title="📗 參考" %}

* [x] MakeUseOf ⟩ [Build a Simple Dictionary Application Using JavaScript](https://www.makeuseof.com/build-dictionary-app-using-javascript/)
* [ ] JS.info ⟩ [fetch](https://javascript.info/fetch)
  {% endtab %}

{% tab title="📘 手冊" %}

{% endtab %}

{% tab title="⬆️ 需要" %}

* [Layout System](/web/css/layout/system.md#versions)
  {% endtab %}
  {% endtabs %}

{% tabs %}
{% tab title="csb" %}
{% embed url="<https://codesandbox.io/embed/strange-night-r2glc?fontsize=14&hidenavigation=1&theme=dark>" %}
Dictionary App
{% endembed %}
{% endtab %}

{% tab title="js" %}

```javascript
import { $, $all, log } from './layout/helpers.mjs';

// ------------ event listeners ------------

async function getData() {

  const baseURL = 'https://api.dictionaryapi.dev/api/v2/entries/en/';
  const term = $('.word').value.toLowerCase().trim();
  const url = `${baseURL}${term}`;

  try {
    const response = await fetch(url);
    const data = await response.json();
    displayData(data);
  } catch (error) {
    log(error);
  }
}

$('form').onsubmit = async function (e) {
  e.preventDefault();
  await getData();
};

// click "search" button
$('.search').onclick = async () => {
  await getData();
};

/*
  structure of API response
  -------------------------
  data
   └ 0 (object)
     ├ word: "sheep"
     ├ phonetic: "ʃiːp"
     ├ origin: "Old English scēp, ..."
     ├ meanings (array)
     │     └ 0 (object)
     │       ├ partOfSpeech: "noun" 
     │       └ definitions (array)
     │             ├ 0: {definition: "...", synonyms: [...], antonyms: [...]}
     │             ├ 1: {definition: "...", synonyms: [...], antonyms: [...]}
     │             └ 2: {definition: "...", synonyms: [...], antonyms: [...]}
     │       
     └ phonetics (array)
           └ 0:  {audio: "...", text: "..."}
*/

//
const displayData = (data) => {
  log(data);

  // if main hidden, unhide it.
  const hiddenMain = $('.hidden');
  if (hiddenMain) hiddenMain.classList.remove('hidden');

  // add 'sink' style to every h3
  $all('.app h3').forEach((h3) => h3.classList.add('sink'));

  // part of speech
  $(
    '.term',
  ).innerHTML = `${data[0].word} <span class="sink">${data[0].meanings[0].partOfSpeech}</span>`;

  // definitions
  $('.list').innerHTML = data[0].meanings[0].definitions
    .map((def) => `<li>${def.definition}</li>`)
    .join('');

  // audio
  $(
    '.audio',
  ).innerHTML = `<audio src="${data[0].phonetics[0].audio}" controls>`;
};

```

{% endtab %}

{% tab title="css" %}

```css
@import './layout/layout.css';

/* ---------- page ---------- */

html {
  background: darkkhaki;
}

body {
  max-width: 600px;
  margin: 0.5rem auto;
}

/* ---------- individual elements ---------- */

header {
  gap: 0.5rem;
}

form {
  /* search bar */
  gap: 6px;
}

form * {
  height: 2rem;
  padding: 0 0.5rem;
}

.hs2 {
  /* term */
  align-items: center;
  gap: 1ch;
}

.app {
  gap: 1.5rem;

  margin: 1rem;
  padding: 1rem;
  border: 1px solid black;
  border-radius: 0.5rem;

  background: #eee;
}

main {
  gap: 1rem;

  max-width: 60ch; /* measure */
  border-top: 1px dotted black;
  padding-top: 1.5rem;
}

.term span {
  background: tomato;
  color: white;
}

.list {
  margin-left: 2rem;
}

.sink {
  align-self: flex-start;

  /* display: inline; */
  font-size: calc(1rem - 2px);
  font-weight: bold;

  background: hsl(225 80% 75%);
  /* color: white; */
  padding: 0 6px;
  border: 1px solid black;
  border-radius: 4px;
  box-shadow: 2px 2px 4px rgb(0 0 0 / 0.3) inset;
}

```

{% endtab %}

{% tab title="html" %}

```html
<!-- Dictionary app container -->
<div class="app vcenter">

  <header class="vcenter">
    
    <!-- title -->
    <h2 class="">Dictionary</h2>
    
    <!-- <input> & <button> -->
    <form class="hstack hs1">
      <input class="word" placeholder="Enter the word" />
      <input type="submit" class="search" value="Search" />
    </form>
    
  </header>

  <main class="hidden vstack">

    <!-- part of speech -->
    <div id="partOfSpeechDiv" class="hstack hs2">
      <h3>Term</h3>
      <p class="term"></p>
    </div>
    
    <!-- definitions -->
    <div class="vstack">
      <h3>Meanings</h3>
      <ul class="list"></ul>
    </div>
    
    <!-- audio -->
    <div class="vstack">
      <h3>Audio</h3>
      <div class="audio"></div>
    </div>

  </main>
</div>
```

{% endtab %}

{% tab title="⬆️ 需要" %}

* CSS ⟩ [Layout System](/web/css/layout/system.md#versions)
  {% endtab %}

{% tab title="💾 程式" %}

* codepen ⟩ [dictionary app](https://codepen.io/lochiwei/pen/qBXBKZo?editors=1000)
  {% endtab %}
  {% endtabs %}
