Added ability to set icons on bookmarks. Added hover indicator for apps
This commit is contained in:
parent
8b87ad92f1
commit
4583ca00e9
11 changed files with 80 additions and 20 deletions
|
@ -27,4 +27,16 @@
|
|||
font-weight: 400;
|
||||
font-size: 0.8em;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@media (min-width: 500px) {
|
||||
.AppCard {
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.10s;
|
||||
}
|
||||
|
||||
.AppCard:hover {
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import { Link } from 'react-router-dom';
|
|||
|
||||
import classes from './AppCard.module.css';
|
||||
import Icon from '../../UI/Icons/Icon/Icon';
|
||||
import { iconParser } from '../../../utility/iconParser';
|
||||
|
||||
import { App } from '../../../interfaces';
|
||||
|
||||
|
@ -11,16 +12,6 @@ interface ComponentProps {
|
|||
}
|
||||
|
||||
const AppCard = (props: ComponentProps): JSX.Element => {
|
||||
const iconParser = (mdiName: string): string => {
|
||||
let parsedName = mdiName
|
||||
.split('-')
|
||||
.map((word: string) => `${word[0].toUpperCase()}${word.slice(1)}`)
|
||||
.join('');
|
||||
parsedName = `mdi${parsedName}`;
|
||||
|
||||
return parsedName;
|
||||
}
|
||||
|
||||
const redirectHandler = (url: string): void => {
|
||||
window.open(url);
|
||||
}
|
||||
|
|
|
@ -18,9 +18,17 @@
|
|||
.Bookmarks a {
|
||||
line-height: 2;
|
||||
transition: all 0.25s;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.BookmarkCard a:hover {
|
||||
text-decoration: underline;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.BookmarkIcon {
|
||||
width: 20px;
|
||||
display: flex;
|
||||
margin-bottom: 1px;
|
||||
margin-right: 2px;
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
import { Bookmark, Category } from '../../../interfaces';
|
||||
import classes from './BookmarkCard.module.css';
|
||||
|
||||
import Icon from '../../UI/Icons/Icon/Icon';
|
||||
import { iconParser } from '../../../utility/iconParser';
|
||||
|
||||
interface ComponentProps {
|
||||
category: Category;
|
||||
}
|
||||
|
@ -15,6 +18,11 @@ const BookmarkCard = (props: ComponentProps): JSX.Element => {
|
|||
href={`http://${bookmark.url}`}
|
||||
target='blank'
|
||||
key={`bookmark-${bookmark.id}`}>
|
||||
{bookmark.icon && (
|
||||
<div className={classes.BookmarkIcon}>
|
||||
<Icon icon={iconParser(bookmark.icon)} />
|
||||
</div>
|
||||
)}
|
||||
{bookmark.name}
|
||||
</a>
|
||||
))}
|
||||
|
|
|
@ -29,9 +29,11 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
|||
const [formData, setFormData] = useState<NewBookmark>({
|
||||
name: '',
|
||||
url: '',
|
||||
categoryId: -1
|
||||
categoryId: -1,
|
||||
icon: ''
|
||||
})
|
||||
|
||||
// Load category data if provided for editing
|
||||
useEffect(() => {
|
||||
if (props.category) {
|
||||
setCategoryName({ name: props.category.name });
|
||||
|
@ -40,18 +42,21 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
|||
}
|
||||
}, [props.category])
|
||||
|
||||
// Load bookmark data if provided for editing
|
||||
useEffect(() => {
|
||||
if (props.bookmark) {
|
||||
setFormData({
|
||||
name: props.bookmark.name,
|
||||
url: props.bookmark.url,
|
||||
categoryId: props.bookmark.categoryId
|
||||
categoryId: props.bookmark.categoryId,
|
||||
icon: props.bookmark.icon
|
||||
})
|
||||
} else {
|
||||
setFormData({
|
||||
name: '',
|
||||
url: '',
|
||||
categoryId: -1
|
||||
categoryId: -1,
|
||||
icon: ''
|
||||
})
|
||||
}
|
||||
}, [props.bookmark])
|
||||
|
@ -79,7 +84,8 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
|||
setFormData({
|
||||
name: '',
|
||||
url: '',
|
||||
categoryId: formData.categoryId
|
||||
categoryId: formData.categoryId,
|
||||
icon: ''
|
||||
})
|
||||
}
|
||||
} else {
|
||||
|
@ -94,7 +100,8 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
|||
setFormData({
|
||||
name: '',
|
||||
url: '',
|
||||
categoryId: -1
|
||||
categoryId: -1,
|
||||
icon: ''
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -201,6 +208,25 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => {
|
|||
})}
|
||||
</select>
|
||||
</InputGroup>
|
||||
<InputGroup>
|
||||
<label htmlFor='icon'>Bookmark Icon (optional)</label>
|
||||
<input
|
||||
type='text'
|
||||
name='icon'
|
||||
id='icon'
|
||||
placeholder='book-open-outline'
|
||||
value={formData.icon}
|
||||
onChange={(e) => inputChangeHandler(e)}
|
||||
/>
|
||||
<span>
|
||||
Use icon name from MDI.
|
||||
<a
|
||||
href='https://materialdesignicons.com/'
|
||||
target='blank'>
|
||||
{' '}Click here for reference
|
||||
</a>
|
||||
</span>
|
||||
</InputGroup>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
|||
<Table headers={[
|
||||
'Name',
|
||||
'URL',
|
||||
'Icon',
|
||||
'Category',
|
||||
'Actions'
|
||||
]}>
|
||||
|
@ -104,6 +105,7 @@ const BookmarkTable = (props: ComponentProps): JSX.Element => {
|
|||
<tr key={bookmark.bookmark.id}>
|
||||
<td>{bookmark.bookmark.name}</td>
|
||||
<td>{bookmark.bookmark.url}</td>
|
||||
<td>{bookmark.bookmark.icon}</td>
|
||||
<td>{bookmark.categoryName}</td>
|
||||
<td className={classes.TableActions}>
|
||||
<div
|
||||
|
|
|
@ -45,6 +45,7 @@ const Bookmarks = (props: ComponentProps): JSX.Element => {
|
|||
name: '',
|
||||
url: '',
|
||||
categoryId: -1,
|
||||
icon: '',
|
||||
id: -1,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date()
|
||||
|
|
|
@ -4,10 +4,12 @@ export interface Bookmark extends Model {
|
|||
name: string;
|
||||
url: string;
|
||||
categoryId: number;
|
||||
icon: string;
|
||||
}
|
||||
|
||||
export interface NewBookmark {
|
||||
name: string;
|
||||
url: string;
|
||||
categoryId: number;
|
||||
icon: string;
|
||||
}
|
9
client/src/utility/iconParser.ts
Normal file
9
client/src/utility/iconParser.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
export const iconParser = (mdiName: string): string => {
|
||||
let parsedName = mdiName
|
||||
.split('-')
|
||||
.map((word: string) => `${word[0].toUpperCase()}${word.slice(1)}`)
|
||||
.join('');
|
||||
parsedName = `mdi${parsedName}`;
|
||||
|
||||
return parsedName;
|
||||
}
|
7
db.js
7
db.js
|
@ -8,13 +8,10 @@ const sequelize = new Sequelize({
|
|||
|
||||
const connectDB = async () => {
|
||||
try {
|
||||
await sequelize.authenticate({ logging: false });
|
||||
await sequelize.authenticate();
|
||||
console.log('Connected to database');
|
||||
|
||||
await sequelize.sync({
|
||||
// alter: true,
|
||||
logging: false
|
||||
});
|
||||
await sequelize.sync({ alter: true });
|
||||
console.log('All models were synced');
|
||||
} catch (error) {
|
||||
console.error('Unable to connect to the database:', error);
|
||||
|
|
|
@ -13,6 +13,10 @@ const Bookmark = sequelize.define('Bookmark', {
|
|||
categoryId: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false
|
||||
},
|
||||
icon: {
|
||||
type: DataTypes.STRING,
|
||||
defaultValue: ''
|
||||
}
|
||||
}, {
|
||||
tableName: 'bookmarks'
|
||||
|
|
Loading…
Reference in a new issue