1. d0ne1s

    Posted

    d0ne1s
Changes in title
+【Qiigle】というQiitaの記事を検索するサービスを作りました
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,232 @@
+**[Qiigle](https://qiigle.com/)**という、Qiitaの記事を検索するサービスを作りました。
+
+サイトURL: https://qiigle.com/
+GitHub: https://github.com/nyshk97/qiigle
+![how_to_use_qiigle (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244893/705f60c4-238e-f10e-f048-0a7f3a443800.gif)
+
+## 何ができるか(仕様)
+- Qiitaの記事を「ユーザー名」「タイトル」「本文」「タグ」で絞り込んで表示します
+- 複数入力した場合、**AND条件**になります
+- ユーザー名とタグは**完全一致**、タイトルと本文は**含む**です
+
+## なぜ作ったか
+開発中に過去自分が書いた記事を参照することがよくあるのですが、数が多くなってきて探すのが大変になってきました。(ブックマークで管理するのツラい)
+
+ユーザー名 + 記事の内容で簡単に記事を検索する方法がありそうでなかった(どの方法もちょっと面倒だった)ので作ってみました。
+
+## 使用技術
+- ConohaWing
+- PHP
+- Tailwind CSS(CDN)
+- HTML
+
+## やったことまとめ
+- [GoogleDomains](https://domains.google/intl/ja_jp/)でドメインを取得
+- レンタルサーバー([ConohaWING](https://www.conoha.jp/wing/))のコンパネからサイトを追加
+- DNSの設定(ConohaWingのネームサーバーをGoogleDomainsに登録)
+- [QiitaAPI](https://qiita.com/api/v2/docs)のアクセストークンを取得
+- [POSTMAN](https://www.postman.com/)でAPIを叩く
+- HTMLでフォームを作成
+- フォームから受け取ったデータを使いPHPでAPIを叩く
+- 取得したデータを整形して表示
+- [Tailwind CSS](https://tailwindcss.com/)でデザインを整える
+- SSL有効化
+- URL正規化
+- ファビコンを作成→設置
+- TwitterOGPの設定
+- [GoogleAnalytics](https://analytics.google.com/)の設定
+
+実装はシンプルでもやることが意外と多くて、結局半日かかりました。
+超久々にPHPを書きました。(普段はRubyを書いています)
+
+## コード
+Formから受け取った値を使って[QiitaのAPI](https://qiita.com/api/v2/docs)を叩くだけのシンプルな実装です。
+Tailwind CSSをCDNから読み込んでいます。
+
+```html:index.php
+<!DOCTYPE html>
+<html lang='ja'>
+<head>
+ <meta charset='UTF-8'>
+ <meta name='viewport' content='width=device-width, initial-scale=1.0'>
+ <meta name="twitter:card" content="summary" />
+ <meta name="twitter:site" content="@d0ne1s" />
+ <meta property="og:url" content="https://qiigle.com" />
+ <meta property="og:title" content="Qiigle - qiita記事検索サービス" />
+ <meta property="og:description" content="Qiitaの記事を検索するサービスです。ユーザー名、タイトル、本文、タグの複数条件で検索することができます。" />
+ <meta property="og:image" content="https://qiigle.com/ogp.png" />
+ <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
+ <link rel="icon" href="favicon.svg" type="image/svg+xml">
+ <title>Qiigle - qiita記事検索サービス</title>
+</head>
+<body>
+ <style>
+ .green {color: #5bad10;}
+ .light-green {color: #54c000;}
+ .blue {color: #4092d4;}
+ .pink {color: #eadad1;}
+ .black {color: #3b3e3e;}
+ </style>
+ <div class='max-w-3xl mx-auto px-4'>
+ <div class='text-center mb-4'>
+ <a href='/'>
+ <h1>
+ <span class='green text-6xl'>Q</span>
+ <span class='blue text-6xl'>i</span>
+ <span class='pink text-6xl'>i</span>
+ <span class='green text-6xl'>g</span>
+ <span class='black text-6xl'>l</span>
+ <span class='blue text-6xl'>e</span>
+ <span class='text-xs text-gray-800'>by <a href='https://twitter.com/d0ne1s' class='text-gray-600 text-sm'>d0ne1s</a></span>
+ </h1>
+ </a>
+ </div>
+ <div class='mb-6'>
+ <p class='text-sm text-center text-gray-800'>Qiitaの記事を検索します</p>
+ </div>
+ <form action='search_result.php'>
+ <div class="bg-white rounded-lg">
+ <div class="grid lg:grid-cols-2 gap-6">
+ <div class="border focus-within:border-blue-500 focus-within:text-blue-500 transition-all duration-500 relative rounded p-1">
+ <div class="-mt-4 absolute tracking-wider px-1 uppercase text-xs">
+ <p>
+ <label for="user" class="bg-white text-gray-600 px-1">ユーザー名</label>
+ </p>
+ </div>
+ <p>
+ <input id="user" name='user' autocomplete="false" tabindex="0" type="text" placeholder='d0ne1s' class="py-1 px-1 text-gray-900 outline-none block h-full w-full">
+ </p>
+ </div>
+ <div class="border focus-within:border-blue-500 focus-within:text-blue-500 transition-all duration-500 relative rounded p-1">
+ <div class="-mt-4 absolute tracking-wider px-1 uppercase text-xs">
+ <p>
+ <label for="title" class="bg-white text-gray-600 px-1">タイトル</label>
+ </p>
+ </div>
+ <p>
+ <input id="title" name='title' autocomplete="false" tabindex="0" type="text" placeholder='Rubocopを使ってみた' class="py-1 px-1 outline-none block h-full w-full">
+ </p>
+ </div>
+ <div class="border focus-within:border-blue-500 focus-within:text-blue-500 transition-all duration-500 relative rounded p-1">
+ <div class="-mt-4 absolute tracking-wider px-1 uppercase text-xs">
+ <p>
+ <label for="body" class="bg-white text-gray-600 px-1">本文</label>
+ </p>
+ </div>
+ <p>
+ <input id="body" name='body' autocomplete="false" tabindex="0" type="text" placeholder='.rubocop.yml' class="py-1 px-1 outline-none block h-full w-full">
+ </p>
+ </div>
+ <div class="border focus-within:border-blue-500 focus-within:text-blue-500 transition-all duration-500 relative rounded p-1">
+ <div class="-mt-4 absolute tracking-wider px-1 uppercase text-xs">
+ <p>
+ <label for="tag" class="bg-white text-gray-600 px-1">タグ</label>
+ </p>
+ </div>
+ <p>
+ <input id="tag" name='tag' autocomplete="false" tabindex="0" type="text" placeholder='Ruby' class="py-1 px-1 outline-none block h-full w-full">
+ </p>
+ </div>
+ </div>
+ <div class="mt-3 pt-3 text-center">
+ <button class="rounded text-gray-100 px-8 py-2 hover:shadow-inner hover:bg-blue-700 transition-all duration-300 hover:opacity-75" style='background: #54c000'>
+ 検索
+ </button>
+ </div>
+ </div>
+ </form>
+ </div>
+</body>
+</html>
+```
+```search_result.php
+<?php
+if($_GET['user']) {
+ $q_user = urlencode("user:{$_GET['user']} ");
+}
+if($_GET['title']) {
+ $q_title = urlencode("title:{$_GET['title']} ");
+}
+if($_GET['body']) {
+ $q_body = urlencode("body:{$_GET['body']} ");
+}
+if($_GET['tag']) {
+ $q_tag = urlencode("tag:{$_GET['tag']} ");
+}
+$base_url = "https://qiita.com/api/v2/items";
+$url = "{$base_url}?per_page=100&query={$q_user}{$q_title}{$q_body}{$q_tag}";
+$curl = curl_init();
+$option = [
+ CURLOPT_URL => $url,
+ CURLOPT_CUSTOMREQUEST => 'GET',
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => ['Authorization: Bearer MY_ACCESS_TOKEN'],
+];
+curl_setopt_array($curl, $option);
+$response = curl_exec($curl);
+$articles = json_decode($response, true);
+curl_close($curl);
+?>
+<!DOCTYPE html>
+<html lang='en'>
+<head>
+ <meta charset='UTF-8'>
+ <meta name='viewport' content='width=device-width, initial-scale=1.0'>
+ <meta name="twitter:card" content="summary" />
+ <meta name="twitter:site" content="@d0ne1s" />
+ <meta property="og:url" content="https://qiigle.com" />
+ <meta property="og:title" content="Qiigle - qiita記事検索サービス" />
+ <meta property="og:description" content="Qiitaの記事を検索するサービスです。ユーザー名、タイトル、本文、タグの複数条件で検索することができます。" />
+ <meta property="og:image" content="https://qiigle.com/ogp.png" />
+ <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
+ <link rel="icon" href="images/favicon.svg" type="image/svg+xml">
+ <title>検索結果 | Qiigle - qiita記事検索サービス</title>
+</head>
+<body>
+ <style>
+ .green {color: #5bad10;}
+ .light-green {color: #54c000;}
+ .blue {color: #4092d4;}
+ .pink {color: #eadad1;}
+ .black {color: #3b3e3e;}
+ </style>
+ <div class='max-w-3xl mx-auto px-4 pb-8'>
+ <div class='text-center mb-4'>
+ <a href='/'>
+ <h1>
+ <span class='green text-6xl'>Q</span>
+ <span class='blue text-6xl'>i</span>
+ <span class='pink text-6xl'>i</span>
+ <span class='green text-6xl'>g</span>
+ <span class='black text-6xl'>l</span>
+ <span class='blue text-6xl'>e</span>
+ <span class='text-xs text-gray-800'>by <a href='https://twitter.com/d0ne1s' class='text-gray-600 text-sm'>d0ne1s</a></span>
+ </h1>
+ </a>
+ </div>
+ <div>
+ <p>
+ <span class='mr-1'>検索結果</span>
+ <span class='text-gray-800 text-xs'>(ユーザー名: <?= $_GET['user'] ?>, タイトル: <?= $_GET['title'] ?>, 本文: <?= $_GET['body'] ?>, タグ: <?= $_GET['tag'] ?>)
+</span>
+ </p>
+ </div>
+ <div>
+ <?php foreach($articles as $a){ ?>
+ <div class='py-4'>
+ <a href='https://qiita.com/<?= $a['user']['id']; ?>' class='block text-xs' target='_blank'><?= $a['user']['name']; ?> (@<?= $a['user']['id']; ?>)</a>
+ <a href='<?= $a['url']; ?>' class='block hover:underline' target='_blank'>
+ <h3 class='text-lg' style='color: #1a0dab;'><?= $a['title']; ?></h3>
+ <p class='break-all text-xs text-gray-800'><?= substr($a['body'], 0, 200); ?></p>
+ </a>
+ </div>
+ <?php } ?>
+ </div>
+ </div>
+</body>
+</html>
+```
+
+## 参考
+- [Qiita APIを使って記事一覧を取得する - Qiita](https://qiita.com/kou_pg_0131/items/57f86a1abc332ed2185d)