| @@ -13,6 +13,7 @@ | |||||
| "@radix-ui/react-switch": "^1.2.5", | "@radix-ui/react-switch": "^1.2.5", | ||||
| "@radix-ui/react-toast": "^1.2.14", | "@radix-ui/react-toast": "^1.2.14", | ||||
| "axios": "^1.9.0", | "axios": "^1.9.0", | ||||
| "camelcase-keys": "^9.1.3", | |||||
| "class-variance-authority": "^0.7.1", | "class-variance-authority": "^0.7.1", | ||||
| "clsx": "^2.1.1", | "clsx": "^2.1.1", | ||||
| "humps": "^2.0.1", | "humps": "^2.0.1", | ||||
| @@ -2591,6 +2592,18 @@ | |||||
| "node": ">=6" | "node": ">=6" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/camelcase": { | |||||
| "version": "8.0.0", | |||||
| "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", | |||||
| "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", | |||||
| "license": "MIT", | |||||
| "engines": { | |||||
| "node": ">=16" | |||||
| }, | |||||
| "funding": { | |||||
| "url": "https://github.com/sponsors/sindresorhus" | |||||
| } | |||||
| }, | |||||
| "node_modules/camelcase-css": { | "node_modules/camelcase-css": { | ||||
| "version": "2.0.1", | "version": "2.0.1", | ||||
| "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", | "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", | ||||
| @@ -2601,6 +2614,24 @@ | |||||
| "node": ">= 6" | "node": ">= 6" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/camelcase-keys": { | |||||
| "version": "9.1.3", | |||||
| "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-9.1.3.tgz", | |||||
| "integrity": "sha512-Rircqi9ch8AnZscQcsA1C47NFdaO3wukpmIRzYcDOrmvgt78hM/sj5pZhZNec2NM12uk5vTwRHZ4anGcrC4ZTg==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "camelcase": "^8.0.0", | |||||
| "map-obj": "5.0.0", | |||||
| "quick-lru": "^6.1.1", | |||||
| "type-fest": "^4.3.2" | |||||
| }, | |||||
| "engines": { | |||||
| "node": ">=16" | |||||
| }, | |||||
| "funding": { | |||||
| "url": "https://github.com/sponsors/sindresorhus" | |||||
| } | |||||
| }, | |||||
| "node_modules/caniuse-lite": { | "node_modules/caniuse-lite": { | ||||
| "version": "1.0.30001718", | "version": "1.0.30001718", | ||||
| "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", | ||||
| @@ -4151,6 +4182,18 @@ | |||||
| "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" | "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/map-obj": { | |||||
| "version": "5.0.0", | |||||
| "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-5.0.0.tgz", | |||||
| "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==", | |||||
| "license": "MIT", | |||||
| "engines": { | |||||
| "node": "^12.20.0 || ^14.13.1 || >=16.0.0" | |||||
| }, | |||||
| "funding": { | |||||
| "url": "https://github.com/sponsors/sindresorhus" | |||||
| } | |||||
| }, | |||||
| "node_modules/markdown-it": { | "node_modules/markdown-it": { | ||||
| "version": "14.1.0", | "version": "14.1.0", | ||||
| "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", | "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", | ||||
| @@ -5362,6 +5405,18 @@ | |||||
| ], | ], | ||||
| "license": "MIT" | "license": "MIT" | ||||
| }, | }, | ||||
| "node_modules/quick-lru": { | |||||
| "version": "6.1.2", | |||||
| "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz", | |||||
| "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==", | |||||
| "license": "MIT", | |||||
| "engines": { | |||||
| "node": ">=12" | |||||
| }, | |||||
| "funding": { | |||||
| "url": "https://github.com/sponsors/sindresorhus" | |||||
| } | |||||
| }, | |||||
| "node_modules/react": { | "node_modules/react": { | ||||
| "version": "19.1.0", | "version": "19.1.0", | ||||
| "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", | "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", | ||||
| @@ -6192,6 +6247,18 @@ | |||||
| "node": ">= 0.8.0" | "node": ">= 0.8.0" | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/type-fest": { | |||||
| "version": "4.41.0", | |||||
| "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", | |||||
| "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", | |||||
| "license": "(MIT OR CC0-1.0)", | |||||
| "engines": { | |||||
| "node": ">=16" | |||||
| }, | |||||
| "funding": { | |||||
| "url": "https://github.com/sponsors/sindresorhus" | |||||
| } | |||||
| }, | |||||
| "node_modules/typescript": { | "node_modules/typescript": { | ||||
| "version": "5.8.3", | "version": "5.8.3", | ||||
| "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", | ||||
| @@ -14,6 +14,7 @@ | |||||
| "@radix-ui/react-switch": "^1.2.5", | "@radix-ui/react-switch": "^1.2.5", | ||||
| "@radix-ui/react-toast": "^1.2.14", | "@radix-ui/react-toast": "^1.2.14", | ||||
| "axios": "^1.9.0", | "axios": "^1.9.0", | ||||
| "camelcase-keys": "^9.1.3", | |||||
| "class-variance-authority": "^0.7.1", | "class-variance-authority": "^0.7.1", | ||||
| "clsx": "^2.1.1", | "clsx": "^2.1.1", | ||||
| "humps": "^2.0.1", | "humps": "^2.0.1", | ||||
| @@ -1,13 +1,18 @@ | |||||
| import axios from 'axios' | |||||
| import toCamel from 'camelcase-keys' | |||||
| import React, { useEffect, useState } from 'react' | import React, { useEffect, useState } from 'react' | ||||
| import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription } from './ui/dialog' | |||||
| import { Switch } from './ui/switch' | |||||
| import { Button } from './ui/button' | |||||
| import { Link, useNavigate, useLocation } from 'react-router-dom' | |||||
| import { Button } from '@/components/ui/button' | |||||
| import { Dialog, | |||||
| DialogContent, | |||||
| DialogDescription, | |||||
| DialogTitle, | |||||
| DialogTrigger } from '@/components/ui/dialog' | |||||
| import { Input } from '@/components/ui/input' | import { Input } from '@/components/ui/input' | ||||
| import { Switch } from '@/components/ui/switch' | |||||
| import { toast } from '@/components/ui/use-toast' | import { toast } from '@/components/ui/use-toast' | ||||
| import axios from 'axios' | |||||
| import { Link, useNavigate, useLocation } from 'react-router-dom' | |||||
| import { API_BASE_URL } from '@/config' | import { API_BASE_URL } from '@/config' | ||||
| import { camelizeKeys } from 'humps' | |||||
| import type { Tag, User } from '@/types' | import type { Tag, User } from '@/types' | ||||
| @@ -17,7 +22,10 @@ type Props = { visible: boolean | |||||
| setUser: (user: User) => void } | setUser: (user: User) => void } | ||||
| const SettingsDialogue: React.FC = ({ visible, onVisibleChange, user, setUser }: Props) => { | |||||
| const SettingsDialogue: React.FC = ({ visible, | |||||
| onVisibleChange, | |||||
| user, | |||||
| setUser }: Props) => { | |||||
| const [inputCode, setInputCode] = useState ('') | const [inputCode, setInputCode] = useState ('') | ||||
| const handleShowCode = () => { | const handleShowCode = () => { | ||||
| @@ -35,7 +43,7 @@ const SettingsDialogue: React.FC = ({ visible, onVisibleChange, user, setUser }: | |||||
| if (res.data.valid) | if (res.data.valid) | ||||
| { | { | ||||
| localStorage.setItem ('user_code', inputCode) | localStorage.setItem ('user_code', inputCode) | ||||
| setUser (camelizeKeys (res.data.user)) | |||||
| setUser (toCamel (res.data.user, { deep: true })) | |||||
| toast ({ title: '引継ぎ成功!' }) | toast ({ title: '引継ぎ成功!' }) | ||||
| } | } | ||||
| else | else | ||||
| @@ -1,4 +1,5 @@ | |||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import toCamel from 'camelcase-keys' | |||||
| import { useEffect, useState } from 'react' | import { useEffect, useState } from 'react' | ||||
| import { Helmet } from 'react-helmet' | import { Helmet } from 'react-helmet' | ||||
| import ReactMarkdown from 'react-markdown' | import ReactMarkdown from 'react-markdown' | ||||
| @@ -33,7 +34,7 @@ export default () => { | |||||
| void (axios.get (`${ API_BASE_URL }/wiki/title/${ encodeURIComponent (title) }`, version && { params: { version } }) | void (axios.get (`${ API_BASE_URL }/wiki/title/${ encodeURIComponent (title) }`, version && { params: { version } }) | ||||
| .then (res => { | .then (res => { | ||||
| setWikiPage (res.data) | |||||
| setWikiPage (toCamel (res.data, { deep: true })) | |||||
| WikiIdBus.set (res.data.id) | WikiIdBus.set (res.data.id) | ||||
| }) | }) | ||||
| .catch (() => setWikiPage (null))) | .catch (() => setWikiPage (null))) | ||||
| @@ -51,7 +52,7 @@ export default () => { | |||||
| < 古 | < 古 | ||||
| </Link>) : <>(最古)</>} | </Link>) : <>(最古)</>} | ||||
| <span>{wikiPage.updated_at}</span> | |||||
| <span>{wikiPage.updatedAt}</span> | |||||
| {wikiPage.succ ? ( | {wikiPage.succ ? ( | ||||
| <Link to={`/wiki/${ title }?version=${ wikiPage.succ }`}> | <Link to={`/wiki/${ title }?version=${ wikiPage.succ }`}> | ||||
| @@ -1,4 +1,5 @@ | |||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import toCamel from 'camelcase-keys' | |||||
| import { useEffect, useState } from 'react' | import { useEffect, useState } from 'react' | ||||
| import { Helmet } from 'react-helmet' | import { Helmet } from 'react-helmet' | ||||
| import { Link, useLocation, useParams } from 'react-router-dom' | import { Link, useLocation, useParams } from 'react-router-dom' | ||||
| @@ -23,7 +24,7 @@ export default () => { | |||||
| useEffect (() => { | useEffect (() => { | ||||
| void (axios.get (`${ API_BASE_URL }/wiki/${ id }/diff`, { params: { from, to } }) | void (axios.get (`${ API_BASE_URL }/wiki/${ id }/diff`, { params: { from, to } }) | ||||
| .then (res => setDiff (res.data))) | |||||
| .then (res => setDiff (toCamel (res.data, { deep: true })))) | |||||
| }, []) | }, []) | ||||
| return ( | return ( | ||||
| @@ -1,4 +1,5 @@ | |||||
| import axios from 'axios' | import axios from 'axios' | ||||
| import toCamel from 'camelcase-keys' | |||||
| import { useEffect, useState } from 'react' | import { useEffect, useState } from 'react' | ||||
| import { Helmet } from 'react-helmet' | import { Helmet } from 'react-helmet' | ||||
| import { Link, useLocation, useParams } from 'react-router-dom' | import { Link, useLocation, useParams } from 'react-router-dom' | ||||
| @@ -18,7 +19,7 @@ export default () => { | |||||
| useEffect (() => { | useEffect (() => { | ||||
| void (axios.get (`${ API_BASE_URL }/wiki/changes`, id && { params: { id } }) | void (axios.get (`${ API_BASE_URL }/wiki/changes`, id && { params: { id } }) | ||||
| .then (res => setChanges (res.data))) | |||||
| .then (res => setChanges (toCamel (res.data, { deep: true })))) | |||||
| }, [location.search]) | }, [location.search]) | ||||
| return ( | return ( | ||||
| @@ -39,19 +40,19 @@ export default () => { | |||||
| {changes.map (change => ( | {changes.map (change => ( | ||||
| <tr key={change.sha}> | <tr key={change.sha}> | ||||
| <td> | <td> | ||||
| {change.change_type === 'update' && ( | |||||
| <Link to={`/wiki/${ change.wiki_page.id }/diff?from=${ change.pred }&to=${ change.sha }`}> | |||||
| {change.changeType === 'update' && ( | |||||
| <Link to={`/wiki/${ change.wikiPage.id }/diff?from=${ change.pred }&to=${ change.sha }`}> | |||||
| 差分 | 差分 | ||||
| </Link>)} | </Link>)} | ||||
| </td> | </td> | ||||
| <td className="p-2"> | <td className="p-2"> | ||||
| <Link to={`/wiki/${ encodeURIComponent (change.wiki_page.title) }?version=${ change.sha }`}> | |||||
| {change.wiki_page.title} | |||||
| <Link to={`/wiki/${ encodeURIComponent (change.wikiPage.title) }?version=${ change.sha }`}> | |||||
| {change.wikiPage.title} | |||||
| </Link> | </Link> | ||||
| </td> | </td> | ||||
| <td className="p-2"> | <td className="p-2"> | ||||
| {(() => { | {(() => { | ||||
| switch (change.change_type) | |||||
| switch (change.changeType) | |||||
| { | { | ||||
| case 'create': | case 'create': | ||||
| return '新規' | return '新規' | ||||
| @@ -23,28 +23,28 @@ export type User = { | |||||
| role: UserRole } | role: UserRole } | ||||
| export type WikiPage = { | export type WikiPage = { | ||||
| id: number | |||||
| title: string | |||||
| sha: string | |||||
| pred?: string | |||||
| succ?: string | |||||
| updated_at?: string } | |||||
| id: number | |||||
| title: string | |||||
| sha: string | |||||
| pred?: string | |||||
| succ?: string | |||||
| updatedAt?: string } | |||||
| export type WikiPageChange = { | export type WikiPageChange = { | ||||
| sha: string | |||||
| pred?: string | |||||
| succ?: string | |||||
| wiki_page: WikiPage | |||||
| user: User | |||||
| change_type: string | |||||
| timestamp: string } | |||||
| sha: string | |||||
| pred?: string | |||||
| succ?: string | |||||
| wikiPage: WikiPage | |||||
| user: User | |||||
| changeType: string | |||||
| timestamp: string } | |||||
| export type WikiPageDiff = { | export type WikiPageDiff = { | ||||
| wiki_page_id: number | |||||
| title: string | |||||
| older_sha: string | |||||
| newer_sha: string | |||||
| diff: WikiPageDiffDiff[] } | |||||
| wikiPageId: number | |||||
| title: string | |||||
| olderSha: string | |||||
| newerSha: string | |||||
| diff: WikiPageDiffDiff[] } | |||||
| export type WikiPageDiffDiff = { | export type WikiPageDiffDiff = { | ||||
| type: 'context' | 'added' | 'removed' | type: 'context' | 'added' | 'removed' | ||||